談談Spring boot 啓動層面的開發

Spring boot的啓動能夠主要分爲2個階段。1 是調用AbstractApplicationContext的refresh方法以前和調用AbstractApplicationContext的refresh。 咱們知道AbstractApplicationContext的refresh的方法是一個模板方法。幾乎全部類型的ApplicationContext的初始化都是圍繞這個refresh方法來進行。git

1. refresh方法以前

1.1 ApplicationContextInitializer

這個類Spring boot最早進行調用的類,其主要就是初始化一些BeanFactoryPostProcessor(後面會說明),或者一些在Application 初始化的時候就須要作的事情。而這些類經過經過掃描calsspath路徑下的:META-INF/spring.factories 文件中的org.springframework.context.ApplicationContextInitializer字來加載類的全路徑名,經過反射獲取對象,而後調用initialize方法。github

1.2 ApplicationListener

這個和ApplicationContextInitializer加載的方式相似,也是從META-INF/spring.factories文件中的配置,主要做用就是在Spring boot的初始化不一樣階段會處罰不一樣的事件(ApplicationEvent及其子類),而這些監聽器就會根據本身在不一樣事件觸發的狀況下完成本身的處理邏輯。例如,ConfigFileApplicationListener負責加載配置文件。spring

固然也能夠經過其餘方式加入beanFactory中,詳情能夠參照BeanFactoryPostProcessor加入到beanFactory的方法app

1.ApplicationListener的有些事件是在ApplicationContextInitializer以前觸發的post

2.建議不要直接在ApplicationContextInitializer加入本身的BeanFactoryPostProcessor方法,xxxAware是不會幫你注入的。spa

2. refresh方法

這個就是spring的模板方法,主要有3個比較重要的接口.net

2.1 BeanFactoryPostProcessor

public interface BeanFactoryPostProcessor {
    
   void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

這個方法就是給能夠對beanFactory進行一些自定義的操做,例如加入一些bean等。固然前提就是咱們定義的bean是在beanFactory中。有許多辦法能夠作到對象

  •  在ApplicationContextInitializer中定義加入,例如
public class MyContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    public void initialize(ConfigurableApplicationContext applicationContext) {
        applicationContext.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());
    }

}
  • 經過其餘BeanFactoryPostProcessor加入,能夠經過註解@Import或者加載XML)

例如經過@Import(value={AnnotationBeanDefinitionRegistrar.class})blog

@Configuration
public class AnnotationBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    private String BEAN_NAME = "annotationBeanPostProcessor";

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        List<String> basePackages = getPackagesToScan(importingClassMetadata);
        if (!registry.containsBeanDefinition(BEAN_NAME)) {
            addPostProcessor(registry, basePackages);
        }
    }

    private void addPostProcessor(BeanDefinitionRegistry registry, List<String> basePackages) {
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(AnnotationBeanPostProcessor.class);
        beanDefinition.getConstructorArgumentValues()
                .addGenericArgumentValue(basePackages);
        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
    }


    private List<String> getPackagesToScan(AnnotationMetadata metadata) {
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                metadata.getAnnotationAttributes(EnableDubbo.class.getName()));
        String[] basePackages = attributes.getStringArray("basePackages");
        return Arrays.asList(basePackages);
    }
}

這樣,就能夠加入咱們自定義的BeanFactoryPostProcessor,就能夠在Bean註冊的層面上進行開發接口

2.2 BeanPostProcessor

public interface BeanPostProcessor {
  
   Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

   Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

}

這個接口主要就是針對在bean實例化先後作一些定製開發。通常只針對某個接口或者某個註解進行批量操做

 

3. 綜述

1. 若是你須要在SpringApplication初始化的時候就作一些事情,使用ApplicationContextInitializer

2. 若是你須要SpringApplication的某個特定階段作一些事情,使用ApplicationListener(推薦)

3. 若是你須要在beanFactory層面上開發,使用BeanFactoryPostProcessor(推薦)

4. 若是你須要在對某個bean的實例化層面上開發,使用BeanPostProcessor(通常業務上的開發使用InitializingBean或者init-method可以知足)

轉載請註明出處:http://www.javashuo.com/article/p-anzkimzy-mc.html

實戰文章:https://my.oschina.net/u/3039671/blog/856577

例子,Spring boot風格使用dubbo

碼雲:https://git.oschina.net/null_584_3382/spring-dubbo-parent

github: https://github.com/Athlizo/spring-dubbo-parent

相關文章
相關標籤/搜索