Spring Bean 注册顺序优先级总结

总结Spring 相关知识点,根据日常开发遇到的问题进行整理总结

目录

  • Bean 注册优先级
  • Bean注册顺序
    • @DependsOn
    • @Order
    • @Bean 方法参数注入
    • @AutoConfigureOrder
    • @AutoConfigureBefore 和 @AutoConfigureAfter
  • Bean初始化顺序问题
    • 属性字段注入和构造器注入
    • 单一Bean 初始化执行方法顺序
    • 单一Bean 销毁时执行方法顺序
  • BeanDefinition 解析
    • 常见的 BeanDefinition 的接口类
  • 关于 BeanFactoryPostProcessor和BeanPostProcessor 后置处理器

Bean 注册优先级

  1. 具有 @ComponentScan注解的bean优先注册
  2. 具有 @Configuration 注解的bean
  3. 具有 @Controller @Service @Repository @Component 等常用注解的bean
  4. @Import注解导入的Bean
  5. 被 实现了ImportSelector接口的类导入的Bean
  6. 被 实现了ImportBeanDefinitionRegistrar接口的类导入的Bean
  7. BeanDefinitionRegistry 动态注入的Bean (属于懒加载,在没有被Spring进行getBean查找时,不会执行初始化方法)

Bean注册顺序

同一个级别的spring容器载入bean顺序是不确定的,spring框架没有约定特定顺序逻辑规范。
但spring保证如果A依赖B (如beanA中有@Autowired B的变量),那么B将先于A被加载。

@DependsOn

如果A不依赖B,但是A需要在B后面初始化,可以使用@DependsOn(value=“Bbeanname”)。
B的@Bean上面需要手动指定Name,否则找不到。

@Order

@Order注解并不能改变Bean加载优先级不能指定 bean 的加载顺序
它适用于 AOP 的优先级,以及将多个 Bean 注入到集合时,这些 bean 在集合中的顺序

@Bean 方法参数注入

@Configuration
public class MytestConfigure {

    @Bean
    public BeanA beanA(BeanB demoB){
      System.out.println("bean A init");
      return new BeanA();
    }
    
    @Bean
    public BeanB beanB(){
      System.out.println("bean B init");
      return new BeanB();
    }
}

上面的两个Bean加载到Spring容器时,Spring容器优先加载 BeanB

@AutoConfigureOrder

注解是Spring Boot提供
@AutoConfigureOrder 只能改变外部依赖的 @Configuration的顺序,例如 spring.factories中的@Configuration的顺序

@AutoConfigureBefore 和 @AutoConfigureAfter

注解是Spring Boot提供
@AutoConfigureBefore、@AutoConfigureAfter、@AutoConfigureOrder
这三个注解只能作用于自动配置类,而不能是自定义的@Configuration配置类

Bean初始化顺序问题

属性字段注入和构造器注入

如果bean直接依赖于另一个bean,我们可以将其通过属性字段或者构造函数参数引入进来。
而使用构造函数的方法显示依赖一个bean,能够保证·依赖的bean先初始化

private JdbcProperties prop;
public JdbcConfig(Jdbcproperties prop){
    this.prop = prop;
}

但是属性注入不可以,属性注入是Spring等全部bean实例化之后进行的关系创建,这种情况下,被注入的bean不一定优先创建

@Autowired
private JdbcProperties prop;

单一Bean 初始化执行方法顺序

  1. Bean对象的初始化方法; 初始化之后设置依赖的其他Bean
  2. 调用有 @PostConstruct 注解的方法;
  3. 如果实现了 BeanNameAware接口, 调用 setBeanName方法设置Bean的ID或者Name;
  4. 如果实现了 BeanFactoryAware接口, 调用 setBeanFactory方法设置BeanFactory;
  5. 如果实现了 ApplicationContextAware接口, 调用 setApplicationContext方法设置ApplicationContext;
  6. 如果实现了 BeanPostProcessor接口, 调用 BeanPostProcessor的预先初始化方法;
  7. 如果实现了 InitializingBean接口, 调用 InitializingBean的afterPropertiesSet方法;
  8. 如果是 @Bean 方式注册,调用指定的init-method方法;
  9. 如果实现了 BeanPostProcessor接口, 调用 BeanPostProcessor的后初始化方法;

单一Bean 销毁时执行方法顺序

  1. 调用有 @PreDestroy 注解的方法;
  2. 如果实现了 DisposableBean接口, 调用 destroy方法;
  3. 如果是 @Bean 方式注册,调用指定的destroyMethod方法;

BeanDefinition 解析

BeanDefinition 中包括属性、构造方法参数、依赖的 Bean 名称及是否单例、延迟加载等,Spring 根据 BeanDefinition 实例化 Bean.

参考博客: https://www.cnblogs.com/loongk/p/12262101.html

常见的 BeanDefinition 的接口类

AnnotatedBeanDefinition
用来操作注解元数据,一般通过注解方式(例如:@Component、@Bean)得到的 Bean。

AbstractBeanDefinition
是 BeanDefinition 的子抽象类,描述通用的 Bean定义。

RootBeanDefinition
继承自 AbstractBeanDefinition,它可以单独作为一个 BeanDefinition,也可以作为其他 BeanDefinition 的父类。

ChildBeanDefinition
该类继承自 AbstractBeanDefinition。其相当于一个子类,不可以单独存在,必须依赖一个父 BeanDetintion。

GenericBeanDefinition
是 ChildBeanDefinition 更好的替代者,它同样可以通过 setParentName 方法设置父 BeanDefinition。

下面三个 BeanDefinition 既实现了 AnnotatedBeanDefinition 接口,又间接继承 AbstractBeanDefinition 抽象类,这些 BeanDefinition 描述的都是注解形式的 Bean。

ConfigurationClassBeanDefinition
这个 BeanDefinition 用来描述在标注 @Configuration 注解的类中,通过 @Bean 注解实例化的 Bean

AnnotatedGenericBeanDefinition
该类继承自 GenericBeanDefinition ,并实现了 AnnotatedBeanDefinition 接口。这个 BeanDefinition 用来描述标注 @Configuration 注解的 Bean。

ScannedGenericBeanDefinition
该类继承自 GenericBeanDefinition ,并实现了 AnnotatedBeanDefinition 接口。这个 BeanDefinition 用来描述标注 @Component 注解的 Bean,其派生注解如 @Service、@Controller等。

关于 BeanFactoryPostProcessor和BeanPostProcessor 后置处理器

BeanFactoryPostProcessor:
BeanFactory 后置处理器,是对 BeanDefinition 对象进行修改

BeanPostProcessor:
Bean 后置处理器,是对生成的 Bean 对象进行修改

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition bd = beanFactory.getBeanDefinition("xxxxxxxBean");
        System.out.println("得到了xxxxxxxBean 的BeanDefinition 定义 ");
        MutablePropertyValues pv =  bd.getPropertyValues();
        if (pv.contains("userName")) {
            pv.addPropertyValue("userName", "将在初始化时调用setUserName()方法修改remark");
        }
    }
}

public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化方法之前的数据: " + bean.toString());
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化方法之后的数据:" + bean.toString());
        return bean;
    }
}

参考:https://www.jianshu.com/p/71e9b5dac4c4

值得注意的是:
实现了BeanPostProcessor 接口的类是特殊的,它们会被容器不同地对待。

所有实现了BeanPostProcessor 的Bean和它们直接引用的Bean都将被提前实例化(在其他AOP处理方法之前),因为Spring的AOP自动代理也是通过实现BeanPostProcessor接口来做的,所以 BeanPostProcessor的实现类和它们直接引用的bean不满足AOP自动代理的条件,因此它们导致AOP失效问题

你可能感兴趣的:(java,spring,bean,优先级,顺序,注册)