這幾天在看雷老師講的spring註解開發,做了個筆記,在這裏記錄一下
sping註解開發
@configuration
@conditional
@bean
@Import
一:給容器中註冊組件
1)包掃描+組件標註註解(@Controller/@Service/@Repository/@Component)
2)@Bean[導入的第三方包裏面的組件]
3)@Import[快速給容器中導入一個組件]
1)@Import:容器會自動註冊這個組件,id默認是全類名
2)ImportSelector,實現importSelector接口,返回一個類全路徑數組,@Import({Color.class,Red.class.MyImportSelector.class})
3) 實現ImportBeanDefinitionRegistrar:手動註冊bean到容器中
4) 使用Spring提供的FactoryBean(工廠Bean);
(1)使用spring提供的FactoryBean(工廠 Bean)
(2) 要獲取工廠Bean本身,我們需要給id前面 加一個& (&colorFactoryBean)
二.bean的生命週期:
bean的生命週期:
-
構造(對象創建)
- 單實例:在容器啓動的時候創建對象
- 多實例:在每次獲取的時候創建對象
-
初始化:
- 對象創建完成,並賦值好,調用初始化
-
銷燬
- 單實例:容器關閉的時候
- 多實例:容器不會管理這個bean,容器不會調用銷燬方法
-
指定初始化和銷燬方法
通過@Bean指定init-method和destory-method;
-
通過讓Bean實現InitializingBean(定義初始化邏輯),通過實現DisposableBean(定義銷燬邏輯)
-
可以使用JSR250;
@PostConstruct:在bean創建完成並且屬性賦值完成,來執行初始化方法
@PreDestroy:在容器銷燬Bean之前通知我們進行清理
-
BeanPostProcessor[interface] :bean的後置處理器;在bean初始化前後進行一些處理工作
postProcessBeforeInitialization:在初始化之前工作
postProcessAfterInitialization:在初始化之後工作
遍歷得到容器中所有的BeanPostProcessor;挨個執行beforeInitialization,一旦返回null,跳出for循環,不會執行後面的BeanPostProcessor.postProcessBeforeInitialization 1.populateBean(beanName,mbd,instanceWrapper) ;給bean複製 initializeBean{ 2.applyBeanPostProcessorBeforeInitialization(wrappedBean,beanNaem); 3.invokeInitMethods(beanName,wrappedBean,mbd);執行初始化方法 4.applyBeanPostProcessorAfterInitialization(wrappedBean,beanName) }
三:Spring底層對postProccessor的使用
BeanValidationPostProcessor
ApplicationContextAwareProcessor
AutowiredAnnotationBeanPostProcessor
Spring底層對BeanPostProcessor的使用
bean賦值。注入其他組件,@Autowired,生命週期註解功能
四,給屬性賦值
使用@Value賦值;
- 基本數值
- 可以寫SpEL;#{}
- 可以寫${};取出配置文件中的值
使用@PropertySource讀取外部配置文件中k/v保存到運行的環境變量中
@PropertySource(value={“classpath:/person.properties”})
屬性的自動裝配
-
@Autowore:自動注入
-
默認優先按照類型去容器中找對應的組件:applicationContext.getBean(Book.Class)
-
如果找到多個相同類型的組件,再將屬性的名稱作爲組件的id去容器中國尋找
-
@Qualifier(“bookDao”):使用@Qualifier指定需要裝配的組件id
-
自動裝配默認一定要將屬性賦值好,沒有就會報錯,可以使用
可以使用@Autowired(required=false);
-
@Primary:讓Spring進行自動裝配的時候,默認使用首選的bean,也可以繼續使用qualifier指定需要裝配的Bean的名
-
-
使用AutowiredAnnotationBeanPostProcessor:解析完成自動裝配功能
-
@Autowire:構造器,參數,方法,屬性
-
自定義組件想要使用Spring容器底層的一些組件(ApplicationContex,BeanFactory,XXX)要實現XXXXAware:在創建對象的時候,會調用想要的方法獲取相應的組件
-
@profile :
spring爲我們提供的可以根據當前環境,動態的激活和切換一系列組件的功能
- 1.使用命令行動態參數:在虛擬機參數位置加載 -Dspring.profiles.active=test
- @Profile:指定組件在哪個環境的情況下才能被註冊到容器中,不指定,任何環境下都能註冊這個組件
- 加了環境標識的bean,只有之歌環境被激活的時候才能註冊到容器中。默認是default環境
- 寫在配置類上,只有是指定的環境的時候,整個配置類裏面的所有配置才能開始生效
- 沒有標註環境標識的bean在任何環境下都是加載的。
五. AOP面向切面編程
aop:指在程序運行期間動態的將某段代碼切入到指定方法指定位置進行運行的編程方式;
AOP原理
@EnableAspectJAutoProxy
AnnotationAwareAspectJAutoProxyCreator
-
傳入配置類,創建ioc容器
-
註冊配置類,調用refresh()刷新容器
-
registerBeanPostProcessors(beanFactory);註冊Bean的後置處理器來方便攔截bean的創建
- 先獲取ioc容器已經定義了的需要創建對象的所有BeanPostProcessor
- 給容器中加別的BeanPostProcessor
- 優先註冊實現了PriorityOrdered接口的BeanPostProcessor
- 再給容器總註冊實現了Ordered接口的BeanPostProcessor
- 註冊沒實現優先級接口的BeanPostProcessor;
- 註冊BeanPostProcessor,實際上就是創建BeanPostProcessor對象,保存在容器中。
- 創建Bean的實例
- populateBean:給bean的各種屬性賦值
- initializeBean:初始化Bean
- invokeAwareMethods():處理Aware接口的方法回調
- applyBeanPostProcessorsBeforeInitialization():應用獲知處理器的
- invokeInitMethods();執行自定義的初始化方法
- applyBeanPostProcessorsAfterInitialization()
- BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)
- 把BeanPostProcessor註冊到BeanFactory中beanFactory.addBeanPostProcessor(pstProcessor)
-
finishBeanFactoryInitailization(beanFactory);完成BeanFactory初始化工作
-
遍歷獲取容器中所有的Bean,依次創建getBean(beanName)
getBean->doGetBean->getSingleton()
-
創建bean
-
先從緩存中獲取當前bean,如果能獲取到,說明bean是之前被創建過的,直接使用,否則再創建
-
createBean(),創建Bean,AnnotationAwareAspectJAutoProxyCreator會在任何bean創建之前先嚐試返回
BeanPostProcessor是在Bean對象創建完成初始化前後調用的
instantiationAwareBeanPostProcessor是在創建Bean實例之前先嚐試用後置處理器返回對象的。
- resolveBeforeInstantiation(beanName,mbdToUse);希望後置處理器在此返回一個代理對象,如果不能,走下一步:
- doCreateBean()
-
-
AnnotationAwareAspectJAutoProxyCreator[InstantiationAwareBeanPostProcessor]的作用
-
每個Bean創建之前調用調用postProcessBeforeInstantiation();
- 判斷當前bean是否在adviseBeans中(保存了所有需要增強Bean)
- 判斷當前bean是否是基礎類型的Advice,PointCut,Advisor,AopInfrastructureBean,或者是否是切面(@Aspect)
- 是都需要跳過
- 獲取候選的增強器(切面裏面的通知方法)【List candidateAdvisors】,每個封裝的通知方法的增強器是InstantiationModelAwarePointcutAdvisor,判斷每個增強器是否是AspectJPointcutAdvisor類型的
- 永遠返回false
-
創建對象
postProcessAfterInitialization;
return wrapIfNecessary(bean,beanNaem,cachekey);
-
獲取當前bean的所有增強器(通知方法)
-
找到能在當前bean使用的增強器(找哪些通知方法是需要切入當前bean方法的)
-
獲取到能在bean使用的增強器
-
給增強器排序
-
保存當前bean在advicedBeans中
-
如果當前bean需要增強,創建當前bean的代理對象
-
獲取所喲增強器(通知方法)
-
保存到proxyFactory
-
創建代理對象,Spring自動決定
JdkDynamicAopProxy(config);
ObjenesisCglibAopProxy(config)
-
-
給容器中返回當前組件使用cglib增強的代理對象
-
以後容器中獲取到的就是這個組件的代理對象,執行目標方法的時候,代理對象就會執行通知方法的流程
目標方法的執行
-
容器中保存組件的代理對象(cglib增強後的對象)
-
CglibAopProxy.intercept()攔截方法的執行
-
根據proxyfactory獲取目標方法攔截器鏈
-
List interceptorList保存了所有的攔截器,一個默認的exposeInvocationInterceptor和4個增強器
-
遍歷所有的增強器,將其轉爲Interceptor;
registry.getInterceptor(advisor)
-
將增強器轉爲List<MethodInterceptor);如果是MethodIntereptors,直接加入到集合中,如果不是,使用AdvisorAdapter將增強器轉爲MethodInterceptor;轉化完成返貨MethodInterceptor數組
-
-
如果沒有攔截器鏈,直接執行目標方法
-
如果有攔截器鏈,吧需要執行的目標對象,目標方法,攔截器鏈等信息創建一個CglibMethodInvocation對象,並調用 mi.proceed();
-
攔截器鏈的觸發過程
- 如果沒有攔截器執行目標方法,或者攔截器的索引和攔截器數組-1大小一樣(制定了最後一個攔截器)執行目標方法
- 鏈式獲取每一個攔截器,攔截器執行invoke方法,每個攔截器等待下一個攔截器執行完成返回結果以後再來執行。
總結:
-
@EnableAspectJAutoProxy開啓AOP功能
-
@EnableAspectJAutoProxy會給容器中註冊一個組件
-
AnnotationAwareAspectJAutoProxyCreator是一個後置處理器
-
容器的創建流程:
-
registerBeanPostProcessors()註冊後置處理器,創建annotationAware
-
finishBeanFactoryInitialization()初始化剩下的單實例bean
-
創建業務邏輯組件和切面組件
-
AnnotationAwareAspectJAutoProxyCreator攔截組件的創建過程
-
組件創建完之後,判斷組件是否需要增強,
是:切面的通知方法,包裝成增強器( Advisor);給業務邏輯組件創建一個代理對象
-
-
-
執行目標方法:
-
代理對象目標方法
-
CglibAopProxy.intercept()
-
得到目標方法的攔截器鏈(增強器包裝成攔截器MethodInterceptor)
-
利用攔截器的鏈式機制,依次進入每一個攔截器進行執行
-
效果:
正常執行:前置通知-》目標方法-》後置通知-》返回通知
出現異常:前置通知-》目標方法-》後置通知-》異常通知
-
-