spring源碼
spring源碼
一、IOC模組:組件註冊
1.原始方式,是通過配置xml配置文件,寫bean類。使用如下ClassPathXmlApplicationContext獲取類。
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
RegisterDAO registerDAO = (RegisterDAO)ac.getBean("RegisterDAO");
2.註解方式,通過@Configuration+@Bean的方式。其中@Scope可以配置單例(只需一份實例)還是多例(適用於並發環境,但其實我們還是更傾向於使用程式碼控制並發),request還是session。區別:單例在spring啟動時,不管調不調用直接進入spring容器(因為是單實例嘛,所以乾脆直接加入了)。而多例只在使用時才加入,且每次使用都會初始化一個新的類。
由此才有了@Lazy去懶載入,保證默認的單例不會加入容器,只有使用時才會。
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
//ctx.register(AppConfig.class);相當於讀哪份配置文件
ctx.refresh();
Entitlement ent = (Entitlement)ctx.getBean("entitlement");
重點:@Component主要注入自己寫的類交給spring管理,@Bean注入第三方包交給spring管理。
但是實際上對於無參的第三方包可以直接通過@import(類.class)導入,方便多了
3.包掃描作用:讓@Component,@Controller這些註解自動注入spring管理,並且自動裝配。否則得用application對象完成這些操作。
同樣的,xml需要有一句話配置,註解也需要有個註解。@ComponentScan
@ComponentScan(裡面的確還有很多配置,比如掃描的包,去除和只包含哪些)其實註解裡面方法就是這樣配置 方法名=””
@ComponentScan(value = "com.nrsc.springstudy.c1_componentscan1.study2.config2_test",
includeFilters = {
@Filter(type = FilterType.ANNOTATION, classes = {Component.class})},
useDefaultFilters = false)
總結:
1.配置的所有@Component等註解,spring不能主動進行管理。所以得要我們告訴他哪些需要管理,所以才有了@ComponentScan。
二、生命周期
可自定義bean的初始化和銷毀。@Bean(initMethod= ,destoryMethod=)
1.通過@Bean註解中配置初始化和銷毀的方法。(單例是執行初始化和銷毀的方法。但是多例是不會調用銷毀方法,spring要求自己銷毀)
2.通過bean實現介面initializingBean,afterPropertieset()方法定義初始化,通過實現DisposableBean介面,destory()定義銷毀方法。
(Timing:對象創建並賦值之後)
3.@PostConstruct配置初始化,@PreDestory配置銷毀
(Timing:對象創建並賦值之後)
4.bean的後置處理器beanPostProcessor介面。postProcessBeforeInitialization,postProcessAfterInitialization
(Timing:對象創建並賦值之後,在其他任何初始化調用之前,在初始化調用之後。初始化前後。作用:在bean初始化前後完成操作)
註:1.spring底層用beanPostProcessor也用的非常多。2.必須在對象裝配完屬性之後
大概過程:
-
bean實例化
finishBeanFactoryInitialization getBean(就是doGetBean,只是一層包裝) doGetBean getSingleton createBean doCreateBean(包含了populateBean,initializeBean的全過程,即使通過這個方法來完成後面的方法) 以下是2,3,4是docreateBean中的執行方法。
-
createBeanInstance 通過bean的name得到一個BeanWrapper,通過這個調用getWrappedInstance就可以得到我們要的bean。
-
屬性賦值 Populate populateBean() -> 屬性賦值 (AutowiredAnnotationBeanPostProcessor,一般是這個進行屬性裝配)
-
初始化 Initialization initializeBean() -> 初始化 (上面的4種方法都是圍繞這個)
initializeBean的過程如下:
applyBeanPostProcessorsBeforeInitialization 遍歷取出所有的beanPostProcessor,進行執行相應的前置處理 invokeInitMethods 初始化方法(就是我們定義的前幾種初始化的方法,執行init-method、postConstract註解的方法、afterPropertiesSet) applyBeanPostProcessorsAfterInitialization 遍歷取出所有的beanPostProcessor,進行執行相應的後置處理
-
銷毀 Destruction
bean的賦值(@value),注入其他組件(xxxAware所有介面),@Autowired(AutowiredAnnotationBeanPostProcessor,其實查看源碼可以發現,他還支援@value,@autowired,@inject),生命周期註解功能(@PostConstruct屬於InitDestroyAnnotationBeanPostProcessor)…..等等功能,都是beanPostProcessor的實現類實現的。
三、快速獲取application對象
1.實現Spring的ApplicationContextAware介面,重寫setApplicationContext方法,將得到的ApplicationContext對象保存到一個靜態變數中,有了這個上下文對象,就可以在項目的任意地方用它來得到任意Bean;
2.直接注入對象
@Autowired
private ApplicationContext applicationContext;
四、屬性賦值(AutowiredAnnotationBeanPostProcessor)
1.@Vlaue(${}):取出配置文件中的值(可以指定讀取配置)。@Vlaue(#{}):使用Spel表達式取值
2.@Autoired:默認是按類型去容器中找組件。如果找到多個,默認按屬性名作為id。加上@Qualifer可以直接指定名字。默認必須裝配成功,裝配失敗則報錯。當然裡面也有屬性可以配置。@Autowired(required =false)
3.@Resource java規範註解,僅提供按名稱注入。
4.@Inject java規範註解額,需要額外導包,和@Autoired效果一樣。但是不支援required。
重點介紹:@Autoired
作用域:@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
即可以加到構造器,方法,屬性等上。
@Autoired//加在方法上,傳入的參數從容器中拿。加在參數上也是一樣。用構造器也是這樣,但是對於只有一個有參構造器,可以省略註解
public void setCar(Car car){
this.car=car;
}
5.獲取spring底層組件,實現XXXAware介面。(Aware類型的介面可以得到很多spring的組件)
如:ApplicationContextAware,BeanFactoryAware等。也不難,在實現這些介面,都會要求重寫set方法,底層無非就是通過判斷當前類是否實現了XXXAware,如果是,則調用剛才實現的set方法進行注入。
底層依賴ApplicationContextAwareProcessor,是BeanPostProcessor的實現類。所以對於獲得spring底層組件的類基本都是利用了BeanPostProcessor,且多以XXXAware結尾。並在postProcessBeforeInitialization中進行判斷是否是ApplicationContextAware類(裡面還判斷是否其他類,如上下文環境等),如果是,則賦值applicationContext。
對於這類方法必定會有一個setxxxxx()方法。用於注入對象。
五、AOP
JoinPoint這個參數必須寫參數表的第一位,寫在後面無法生效。
1.寫切面記得用@Aspect。
2.在切面的通知方法中必須標註註解,並寫切入點表達式。
3.開啟aop註解模式@EnableAspectJAutoProxy,不然上面註解都不能生效。
源碼:@EnableAspectJAutoProxy做了哪些事?
通過導入@Import(AspectJAutoProxyRegistrar.class),這個類創建一個自動代理創建器AnnotationAwareAspectJAutoProxyCreator。
可以發現最後還是實現了BeanPostProcessor介面和Aware介面。