一、容器中注入組件
1,包掃描 + 組件標注注解
a)組件標注
- @Controller
- @Service
- @Repository
- @Component
b)包掃描@ComponentScan
@ComponentScan中主要值的解釋
- value:掃描的包路徑(數組)
- excludeFilters:指定掃描的時候按照什么規則排除那些組件(@ComponentScan.Filter)includeFilters:指定掃描的時候只需要包含哪些組件。使用同excludeFilter。
- FilterType.ANNOTATION:按照注解
- FilterType.ASSIGNABLE_TYPE:按照給定的類型
- FilterType.ASPECTJ:使用ASPECTJ表達式
- FilterType.REGEX:使用正則指定
- FilterType.CUSTOM:使用自定義規則
- useDefaultFilters:是否使用默認的掃描機制。默認按照a)中組件標注掃描
2,使用@Bean導入
a)@Scope作用域
- prototype:多實例的:ioc容器啟動並不會去調用方法創建對象放在容器中。每次獲取的時候才會調用方法創建對象;
- singleton:單實例的(默認值):ioc容器啟動會調用方法創建對象放到ioc容器中。以后每次獲取就是直接從容器(map.get())中拿,
- request:同一次請求創建一個實例
- session:同一個session創建一個實例
b)@Lazy
單實例bean:默認在容器啟動的時候創建對象;
懶加載:容器啟動不創建對象。第一次使用(獲取)Bean創建對象,並初始化。
c)@Conditional
@Bean上加改注解,按照一定的條件進行判斷,滿足條件給容器中注冊bean;如在類上加改注解,這個類中配置的所有bean注冊才能生效。
- @ConditionalOnClass 表示如果有后面的類,那么就加載這個自動配置;
- @ConditionalOnMissingClass 如果沒有后面的類,才自動配置。如果沒有就配置,保證bean的唯一。
大量運用於SpringBoot中。
3,使用@Import導入
快速為容器中導入一個組件。
- @Import(要導入到容器中的組件);容器中就會自動注冊這個組件,id默認是全類名
- ImportSelector:返回需要導入的組件的全類名數組
- ImportBeanDefinitionRegistrar:手動注冊bean到容器中。1.new RootBeanDefinition(Dog.class);2.registry.registerBeanDefinition()。
4,FactoryBean(工廠Bean)
將實現FactoryBean的類加到容器中。
- 默認從容器中獲取到的是工廠bean調用getObject創建的對象。
- 要獲取工廠Bean本身,我們需要給id前面加一個&
二、Bean的生命周期
1,bean生命周期
bean創建 --- 初始化 --- 銷毀
- 構造(對象創建)
- 單實例:在容器啟動的時候創建對象
- 多實例:在每次獲取的時候創建對象
- 初始化:
- 成員變量賦值,各種增強等,對象創建完成,並賦值好,調用初始化方法
- 銷毀:
- 單實例:容器關閉的時候
- 多實例:容器不會管理這個bean;容器不會調用銷毀方法;
2,定義Bean初始化和銷毀
a)定義initMethod和destroyMethod
- 定義初始化方法,定義@Bean的initMethod為該方法
- 定義銷毀方法,定義@Bean的destroyMethod為該方法
b)實現InitializingBean和DisposableBean接口
- 定義當前對象實現InitializingBean接口。其中afterPropertiesSet方法會在當前對象設置完屬性之后調用。
- 定義當前對象實現DisposableBean接口。其中destroy方法會在當前對象銷毀的時候調用。
c)可以使用JSR250
- @PostConstruct定義在方法上,則該方法會在Bean創建並且屬性賦值之后執行,為初始化方法
- @PreDestroy定義在方法上,則該方法在容器銷毀bean之前通知我們進行清理工作
d)實現BeanPostProcessor,bean的后置處理
源碼:Demo04_BeanLifeCycle、Demo04_BeanPostProccessor
在bean初始化前后進行一些處理工作;
- postProcessBeforeInitialization:在初始化之前工作
- postProcessAfterInitialization:在初始化之后工作
3,從源碼看BeanPostProcessor后置處理器
在Spring類AbstractAutowireCapableBeanFactory中方法doCreateBean可以看到
//給bean進行屬性賦值 populateBean(beanName, mbd, instanceWrapper); //初始化bean exposedObject = initializeBean(beanName, exposedObject, mbd);
在方法initializeBean中可以看到
//調用applyBeanPostProcessorsBeforeInitialization進行初始化之前的處理 if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } //調用自定義初始化方法 try { invokeInitMethods(beanName, wrappedBean, mbd); }catch ...//調用applyBeanPostProcessorsAfterInitialization進行初始化之后的處理 if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }
總結:
BeanPostProcessor會在Bean對象創建並屬性賦值完成之后,在執行init初始化方法的前后進行增加。
4,BeanPostProcessor在Spring中的應用
a)ApplicationContextAware各種Aware接口
查看源碼類ApplicationContextAwareProcessor實現了BeanPostProcessor接口,其中postProcessBeforeInitialization的實現為:
//如果當前bean為各種指定的Aware的bean就會執行invokeAwareInterfaces方法 this.invokeAwareInterfaces(bean); private void invokeAwareInterfaces(Object bean) { if (bean instanceof Aware) { ... //如果當前bean為ApplicationContextAware的子類,則會調用其setApplicationContext將applicationContext進行賦值 if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext); } } }
所以在ApplicationContextAware時,可以通過setApplicationContext獲取到ApplicationContext上下文對象
b)BeanValidationPostProcessor
查看BeanValidationPostProcessor實現了BeanPostProcessor接口,其中不管是postProcessBeforeInitialization還是postProcessAfterInitialization,均調用了doValidate方法來驗證當前bean是否合理
c)@PostConstruct和@PreDestroy方法
查看InitDestroyAnnotationBeanPostProcessor實現了BeanPostProcessor接口,其中postProcessBeforeInitialization在當前bean初始化之前的源碼為:
//獲取生命周期的metadata,得到標注有@PostConstruct和@PreDestroy的方法 LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass()); try { //這個方法會采用反射的方式,調用方法 metadata.invokeInitMethods(bean, beanName); }...
d)AutowiredAnnotationBeanPostProcessor
用來處理@Autowire注解的屬性
三、屬性賦值
- @Value:給屬性賦值,也可以使用SpEL和外部文件的值
- @PropertySource:讀取外部配置文件中的k/v保存到運行環境中。@PropertySource(value={"classpath:/application.yaml"})
- @Autowried 裝配優先級如下:構造器、參數、方法、屬性。
- 使用按照類型去容器中找對應的組件
- 如果找到多個相同類型的組件,再將屬性的名稱作為組件的id去容器中查找
- @Qualifier:使用@Qualifier指定需要裝配的組件的id,結合@Autowried使用
- @Primary:spring自動裝配的時候,默認首先bean,配合@Bean使用
- @Resource(JSR250):jsr規范:按照組件名稱進行裝配,不支持@Primary和@Autowired(reqiured=false)
- @Inject(JSR330):jsr規范和@Autowired功能一致,不支持require=false;
- @Profile:結合@Bean使用,默認為default環境,可以通過命令行參數來切換環境
- 加上VM參數:-Dspring.profiles.active=dev 則采用的dev環境。多個用逗號隔開
- 1.無參構造ApplicationContext,2.通過applicationContext.getEnvironment().setActiveProfiles("dev"),3.注冊配置類applicationContext.register(Main.class),4.采用ApplicationContext.refresh()