zl程序教程

您现在的位置是:首页 >  Javascript

当前栏目

谈谈Spring boot 启动层面的开发

2023-03-09 22:07:29 时间

Spring boot的启动可以主要分为2个阶段。1 是调用AbstractApplicationContext的refresh方法之前和调用AbstractApplicationContext的refresh。 我们知道AbstractApplicationContext的refresh的方法是一个模板方法。几乎所有类型的ApplicationContext的初始化都是围绕这个refresh方法来进行。

1. refresh方法之前

1.1 ApplicationContextInitializer

这个类Spring boot***进行调用的类,其主要就是初始化一些BeanFactoryPostProcessor(后面会说明),或者一些在Application 初始化的时候就需要做的事情。而这些类通过通过扫描calsspath路径下的:META-INF/spring.factories 文件中的org.springframework.context.ApplicationContextInitializer字来加载类的全路径名,通过反射获取对象,然后调用initialize方法。

1.2 ApplicationListener

这个和ApplicationContextInitializer加载的方式类似,也是从META-INF/spring.factories文件中的配置,主要作用就是在Spring boot的初始化不同阶段会处罚不同的事件(ApplicationEvent及其子类),而这些监听器就会根据自己在不同事件触发的情况下完成自己的处理逻辑。例如,ConfigFileApplicationListener负责加载配置文件。

当然也可以通过其他方式加入beanFactory中,详情可以参照BeanFactoryPostProcessor加入到beanFactory的方法

1.ApplicationListener的有些事件是在ApplicationContextInitializer之前触发的

2.建议不要直接在ApplicationContextInitializer加入自己的BeanFactoryPostProcessor方法,xxxAware是不会帮你注入的。

2. refresh方法

这个就是spring的模板方法,主要有3个比较重要的接口

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})

@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能够满足)

转载请注明出处:https://my.oschina.net/u/3039671/blog/852211

例子,Spring boot风格使用dubbo

码云:https://git.oschina.net/null_584_3382/spring-dubbo-parent

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