总结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.

常见的 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;
}
}

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

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