Spring的IOC常用註解(含源碼)

一、容器中注入組件

1,包掃描 + 組件標註註解

  源碼:Demo01_ComponentScan

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導入

  源碼:Demo02_Import

  快速爲容器中導入一個組件。

  • @Import(要導入到容器中的組件);容器中就會自動註冊這個組件,id默認是全類名
  • ImportSelector:返回需要導入的組件的全類名數組
  • ImportBeanDefinitionRegistrar:手動註冊bean到容器中。1.new RootBeanDefinition(Dog.class);2.registry.registerBeanDefinition()。

4,FactoryBean(工廠Bean)

  源碼:Demo03_FactoryBean

  將實現FactoryBean的類加到容器中。

  • 默認從容器中獲取到的是工廠bean調用getObject創建的對象。
  • 要獲取工廠Bean本身,我們需要給id前面加一個&

二、Bean的生命週期

1,bean生命週期

  bean創建 --- 初始化 --- 銷燬

  • 構造(對象創建)
    • 單實例:在容器啓動的時候創建對象
    • 多實例:在每次獲取的時候創建對象
  • 初始化:
    • 成員變量賦值,各種增強等,對象創建完成,並賦值好,調用初始化方法
  • 銷燬:
    • 單實例:容器關閉的時候
    • 多實例:容器不會管理這個bean;容器不會調用銷燬方法;

2,定義Bean初始化和銷燬

a)定義initMethod和destroyMethod

  源碼:Demo04_BeanLifeCycleCar

  • 定義初始化方法,定義@Bean的initMethod爲該方法
  • 定義銷燬方法,定義@Bean的destroyMethod爲該方法

b)實現InitializingBean和DisposableBean接口

  源碼:Demo04_BeanLifeCycleDog

  • 定義當前對象實現InitializingBean接口。其中afterPropertiesSet方法會在當前對象設置完屬性之後調用。
  • 定義當前對象實現DisposableBean接口。其中destroy方法會在當前對象銷燬的時候調用。

c)可以使用JSR250

  源碼:Demo04_BeanLifeCycleColor

  • @PostConstruct定義在方法上,則該方法會在Bean創建並且屬性賦值之後執行,爲初始化方法
  • @PreDestroy定義在方法上,則該方法在容器銷燬bean之前通知我們進行清理工作

d)實現BeanPostProcessor,bean的後置處理

  源碼:Demo04_BeanLifeCycleDemo04_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()

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章