Spring原理学习(二):Bean的生命周期和Bean后处理器
〇、前言
倘若是为了面试,请背下来下面这段:
spring的bean的生命周期主要是创建bean的过程,一个bean的生命周期主要是4个步骤:实例化、属性注入、初始化、销毁。但是对于一些复杂的bean的创建,spring会在bean的生命周期中开放很多的接口,可以让你加载bean的时候对bean做一些改变,因此一个普通的bean的生命周期为:
- 实现了BeanFactoryPostProcessor接口的bean,在加载其他的bean的时候,也会调用这个bean的 postProcessBeanFactory方法,可以在这个步骤去对bean中的属性去赋值。设置年龄初始化18等等。
- 实现了InstantiationAwareBeanPostProcessor接口的bean,会在实例化bean之前调用 postProcessBeforeInstantiation方法
- 然后在对bean进行实例化
- 对bean进行属性注入
- 对bean进行初始化,在初始化中,包含了以下几个步骤:
- 实现了BeanFactoryAware接口,会先调用setBeanFactory方法
- 实现了BeanNameAware接口,会先调用setBeanName方法
- 实现了BeanPostProcessor接口,会先调用postProcessBeforeInitialization方法
- 实现了InitializingBean接口,会调用afterPropertiesSet方法
- 然后在进行aop后置处理,通过实现BeanPostProcessor接口,在postProcessAfterInitialization方法中进行动态代理
- 销毁
如果不是为了面试,请往下看:
一、Bean的生命周期与Bean后处理器
1.1 Bean的生命周期
我们先来体验一下bean的生命周期:
@SpringBootApplication
public class A03 {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(A03.class, args);//感受销毁阶段context.close();}
}
@Component
public class LifeCycleBean {private static final Logger log = LoggerFactory.getLogger(LifeCycleBean.class);public LifeCycleBean() {log.debug("构造");}@Autowiredpublic void autowired(@Value("${JAVA_HOME}") String home) {log.debug("依赖注入: {}", home);}@PostConstructpublic void init() {log.debug("初始化");}@PreDestroypublic void destroy() {log.debug("销毁");}
}
1.2 Bean后处理器
在前文:Spring原理学习(一):BeanFactory和ApplicationContext的原理和实现 中,我们已经简单了解了Bean后处理器的作用。
Bean后处理器的作用:为bean生命周期的各个阶段提供一些扩展功能。
要实现bean后处理器,需要实现 InstantiationAwareBeanPostProcessor 和 DestructionAwareBeanPostProcessor 这两个接口。
@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {private static final Logger log = LoggerFactory.getLogger(MyBeanPostProcessor.class);/* 销毁之前执行*/@Overridepublic void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {//因为spring中有很多bean,我们只打印自己创建的lifeCycleBean有关的if (beanName.equals("lifeCycleBean"))log.debug("<<<<<< 销毁之前执行, 如 @PreDestroy");}/* 实例化之前执行*/@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean"))log.debug("<<<<<< 实例化之前执行, 这里返回的对象会替换掉原本的 bean");return null;}/* 实例化之后执行*/@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean")) {log.debug("<<<<<< 实例化之后执行, 这里如果返回true(默认)会执行依赖注入阶段;false 会跳过依赖注入阶段");
// return false;}return true;}/* 依赖注入阶段执行,一般这里扩展功能比较多*/@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean"))log.debug("<<<<<< 依赖注入阶段执行, 如 @Autowired、@Value、@Resource");return pvs;}/* 初始化之前执行*/@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean"))log.debug("<<<<<< 初始化之前执行, 这里返回的对象会替换掉原本的 bean, 如 @PostConstruct、@ConfigurationProperties");return bean;}/* 初始化之后执行*/@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean"))log.debug("<<<<<< 初始化之后执行, 这里返回的对象会替换掉原本的 bean, 如代理增强");return bean;}
}
二、常见的Bean后处理器
2.1 bean后处理器的作用
先来体验一下bean后处理器的作用:
启动类:
public class A04 {public static void main(String[] args) {// GenericApplicationContext 是一个【干净】的容器,没有一系列spring提供的后处理器GenericApplicationContext context = new GenericApplicationContext();// 用原始方法注册三个 beancontext.registerBean("bean1", Bean1.class);context.registerBean("bean2", Bean2.class);context.registerBean("bean3", Bean3.class);// 初始化容器context.refresh(); // 执行beanFactory后处理器, 添加bean后处理器, 初始化所有单例System.out.println(context.getBean(Bean1.class));// 销毁容器context.close();
}
Bean1里面使用了各种注解,Bean2和Bean3就是最简单的bean
public class Bean1 {private static final Logger log = LoggerFactory.getLogger(Bean1.class);private Bean2 bean2;@Autowiredpublic void setBean2(Bean2 bean2) {log.debug("@Autowired 生效: {}", bean2);this.bean2 = bean2;}@Autowiredprivate Bean3 bean3;@Resourcepublic void setBean3(Bean3 bean3) {log.debug("@Resource 生效: {}", bean3);this.bean3 = bean3;}private String home;@Autowiredpublic void setHome(@Value("${JAVA_HOME}") String home) {log.debug("@Value 生效: {}", home);this.home = home;}@PostConstructpublic void init() {log.debug("@PostConstruct 生效");}@PreDestroypublic void destroy() {log.debug("@PreDestroy 生效");}@Overridepublic String toString() {return "Bean1{" +"bean2=" + bean2 +", bean3=" + bean3 +", home='" + home + '\\'' +'}';}
}
bean2:
public class Bean2 {
}
bean3:
public class Bean3 {
}
运行:
发现只打印了一些spring的信息。我们在bean1里写的一些log.dubug信息都没有打印出来,也就是说,我们使用的@Autowired、@Resource等注解都没有被解析。
解析这些注解的功能实际上是由bean后处理器完成的。
2.2 常见的bean后处理器
AutowiredAnnotationBeanPostProcessor 可以解析@Autowired和@Value注解;
CommonAnnotationBeanPostProcessor 在依赖注入的时候解析@Resource注解,在初始化完成后解析@PostConstruct,在销毁之前解析@PreDestroy注解
public class A04 {public static void main(String[] args) {// ⬇️GenericApplicationContext 是一个【干净】的容器GenericApplicationContext context = new GenericApplicationContext();// ⬇️用原始方法注册三个 beancontext.registerBean("bean1", Bean1.class);context.registerBean("bean2", Bean2.class);context.registerBean("bean3", Bean3.class);context.registerBean("bean4", Bean4.class);//这句可以帮助获取@Value注解里面的值context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());// 解析@Autowired @Valuecontext.registerBean(AutowiredAnnotationBeanPostProcessor.class);//解析@Resource @PostConstruct @PreDestroycontext.registerBean(CommonAnnotationBeanPostProcessor.class);// 初始化容器context.refresh(); // 执行beanFactory后处理器, 添加bean后处理器, 初始化所有单例System.out.println(context.getBean(Bean1.class));// 销毁容器context.close();/*学到了什么a. @Autowired 等注解的解析属于 bean 生命周期阶段(依赖注入, 初始化)的扩展功能b. 这些扩展功能由 bean 后处理器来完成*/}
}
再引入一个bean4,它带有springboot中的属性绑定注解 @ConfigurationProperties
/*ConfigurationProperties是springboot中的注解,有属性绑定功能,也就是可以根据前缀匹配到相应的值比如前缀为Java,属性名为home,那么home的值就可以匹配到java.home*/
@ConfigurationProperties(prefix = "java")
public class Bean4 {//java.home的值private String home;//java.version的值private String version;public String getHome() {return home;}public void setHome(String home) {this.home = home;}public String getVersion() {return version;}public void setVersion(String version) {this.version = version;}@Overridepublic String toString() {return "Bean4{" +"home='" + home + '\\'' +", version='" + version + '\\'' +'}';}
}
解析@ConfigurationProperties:
ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
三、AutowiredAnnotationBeanPostProcessor 源码分析
3.1 AutowiredAnnotationBeanPostProcessor 的具体作用
我们将AutowiredAnnotationBeanPostProcessor 实例化出来,看看他要调用哪些方法完成依赖注入。
public class DigInAutowired {public static void main(String[] args) throws Throwable {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();// 为了省事,选择了比较简单的注册方法,省略了创建过程,依赖注入,初始化beanFactory.registerSingleton("bean2", new Bean2());beanFactory.registerSingleton("bean3", new Bean3());//这句能够帮助找到@Value注解里的值beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());// 1. 查找哪些属性、方法加了 @Autowired, 这称之为 InjectionMetadata// 把AutowiredAnnotationBeanPostProcessor实例化出来,看看他要调用哪些方法完成依赖注入AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();processor.setBeanFactory(beanFactory);//复用前面的bean1,因为是我们自己实例化的,所以肯定没有注入那些依赖Bean1 bean1 = new Bean1();System.out.println(bean1);// 执行依赖注入 @Autowired @Value,再看看结果processor.postProcessProperties(null, bean1, "bean1"); System.out.println(bean1);
}
运行结果:
可以看到,第一行打印中,bean2、bean3、home都是没有值的;而在最后一行,bean2 和 home有值,说明解析了@Autowired 和 @Value 注解。
3.2 AutowiredAnnotationBeanPostProcessor 原理解析
我们看一下 postProcessProperties 方法的源码:
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {//找到有哪些数据上有@Autowired注解,将结果封入InjectionMetadata InjectionMetadata metadata = this.findAutowiringMetadata(beanName, bean.getClass(), pvs);try {//依赖注入metadata.inject(bean, beanName, pvs);return pvs;} catch (BeanCreationException var6) {throw var6;} catch (Throwable var7) {throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", var7);}
}
也就是说 postProcessProperties 总体分为两步:
- 先看看有哪些数据上有@Autowired注解
- 然后再给这些数据执行依赖注入
那我们分别看看这两步。
3.2.1 findAutowiringMetadata
由于该方法是private方法,我们无法直接调用,于是我们采用反射的方式来执行它。
public class DigInAutowired {public static void main(String[] args) throws Throwable {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();// 为了省事,选择了比较简单的注册方法,省略了创建过程,依赖注入,初始化beanFactory.registerSingleton("bean2", new Bean2());beanFactory.registerSingleton("bean3", new Bean3());beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); // @ValuebeanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders); // ${} 的解析器// 1. 查找哪些属性、方法加了 @Autowired, 这称之为 InjectionMetadataAutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();processor.setBeanFactory(beanFactory);Bean1 bean1 = new Bean1();Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);findAutowiringMetadata.setAccessible(true);InjectionMetadata metadata = (InjectionMetadata) findAutowiringMetadata.invoke(processor, "bean1", Bean1.class, null);// 获取 Bean1 上加了 @Value @Autowired 的成员变量,方法参数信息System.out.println(metadata);}
}
下断点之后可以看到,metadata里有一个名为injectedElements的ArrayList,injectedElements里装着setBean2 和 setHome,也就是两个有@Autowired的注解
3.2.2 inject
inject的原理是将findAutowiringMetadata 拿到的成员变量、方法名等信息封装成DependencyDescriptor对象,然后调用beanFactory.doResolveDependency方法。我们模拟一下inject方法。
public class DigInAutowired {public static void main(String[] args) throws Throwable {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();// 为了省事,选择了比较简单的注册方法,省略了创建过程,依赖注入,初始化beanFactory.registerSingleton("bean2", new Bean2());beanFactory.registerSingleton("bean3", new Bean3());beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); // @ValuebeanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders); // ${} 的解析器// 1. 查找哪些属性、方法加了 @Autowired, 这称之为 InjectionMetadataAutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();processor.setBeanFactory(beanFactory);Bean1 bean1 = new Bean1();processor.postProcessProperties(null, bean1, "bean1"); // 按类型查找值//bean3就相当于已经被findAutowiringMetadata找到的成员变量Field bean3 = Bean1.class.getDeclaredField("bean3");DependencyDescriptor dd1 = new DependencyDescriptor(bean3, false);Object o = beanFactory.doResolveDependency(dd1, null, null, null);System.out.println(o);//setBean2就相当于已经被findAutowiringMetadata找到的方法Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);DependencyDescriptor dd2 =new DependencyDescriptor(new MethodParameter(setBean2, 0), true);Object o1 = beanFactory.doResolveDependency(dd2, null, null, null);System.out.println(o1);//setHome就相当于已经被findAutowiringMetadata找到的方法Method setHome = Bean1.class.getDeclaredMethod("setHome", String.class);DependencyDescriptor dd3 = new DependencyDescriptor(new MethodParameter(setHome, 0), true);Object o2 = beanFactory.doResolveDependency(dd3, null, null, null);System.out.println(o2);}
}
运行结果成功: