当前位置: 首页 > news >正文

Spring源码(2)BeanFactory工厂后置处理器、Bean的后置处理器、ApplicationContext容器、Bean的生命周期

1、目标

本文的主要目标是学习BeanFactory工厂后置处理器、Bean的后置处理器、ApplicationContext容器、Bean的生命周期

2、BeanFactory

2.1 BeanFactory工厂后置处理器

@SpringBootApplication
@Log4j2
public class SpringBootDemoApplication {public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();// BeanFactory对象注册BeanDefinition对象beanFactory.registerBeanDefinition("config", beanDefinition);// BeanFactory对象添加后置处理器AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);// 执行BeanFactoryPostProcessor后置处理器的postProcessBeanFactory方法才会将@Bean注解的对象注入到容器中for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values()) {beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);}// 输出注册的bean的名字for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {System.out.println(beanDefinitionName);}}@Configurationstatic class Config {@Beanpublic Bean01 bean01() {return new Bean01();}@Beanpublic Bean02 bean02() {return new Bean02();}}static class Bean01 {@Autowiredprivate Bean02 bean02;}static class Bean02 {}
}

DefaultListableBeanFactory是默认的BeanFactory对象,BeanFactory对象可以注册BeanDefinition对象

BeanFactoryPostProcessor这是bean工厂的后置处理器,通过postProcessBeanFactory方法可以添加一些bean对象的定义

输出结果是:

在这里插入图片描述

可以看到,BeanFactory容器中包含了config、bean01、bean02和后置处理器等对象

internalAutowiredAnnotationProcessor后置处理器是bean工厂的后置处理器,专门用来处理器@Autowired注解的

internalCommonAnnotationProcessor后置处理器是bean工厂的后置处理器,专门用来处理@Resource注解的

2.2 Bean的后置处理器

2.2.1 添加Bean的后置处理器可以依赖注入成功
Bean01 bean01 = beanFactory.getBean(Bean01.class);
System.out.println("bean01 = " + bean01);
Bean02 bean02 = beanFactory.getBean(Bean02.class);
System.out.println("bean02 = " + bean02);
bean02 = beanFactory.getBean(Bean01.class).getBean02();  //为null说明依赖注入失败了
System.out.println("bean02 = " + bean02);

获取Bean01对象中依赖注入的Bean02对象,会返回null,因为没有将bean的后置处理器放到添加到BeanFactory中

在这里插入图片描述

没有依赖注入bean02对象

// 执行BeanPostProcessor后置处理器的方法会对bean的生命周期提供扩展,比如对@Autowired和@Resource注解等
Collection<BeanPostProcessor> values = beanFactory.getBeansOfType(BeanPostProcessor.class).values();
values.forEach(beanFactory::addBeanPostProcessor);

执行BeanPostProcessor后置处理器的addBeanPostProcessor方法会对bean的生命周期提供扩展

在这里插入图片描述

添加了在bean01对象中的bean02对象会依赖注入成功

2.2.2 @Autowired和@Resource注解解析的优先级顺序

希望看到@Autowired和@Resource注解依赖注入的顺序,可以打印bean的后置处理器BeanPostProcessor

// 执行BeanPostProcessor后置处理器的方法会对bean的生命周期提供扩展,比如对@Autowired和@Resource注解等
Collection<BeanPostProcessor> values = beanFactory.getBeansOfType(BeanPostProcessor.class).values();values.forEach(beanPostProcessor -> {System.out.println("beanPostProcessor = " + beanPostProcessor);beanFactory.addBeanPostProcessor(beanPostProcessor);});

遍历并打印所有的BeanPostProcessor对象

在这里插入图片描述

可以看到Autowired注解的bean后置处理器比Resource注解的bean后置处理器优先执行,因此如果这两个注解同时存在的话会优先解析@Autowired注解

// 执行BeanPostProcessor后置处理器的方法会对bean的生命周期提供扩展,比如对@Autowired和@Resource注解等
Collection<BeanPostProcessor> values = beanFactory.getBeansOfType(BeanPostProcessor.class).values();values.stream().sorted(beanFactory.getDependencyComparator()).forEach(beanPostProcessor -> {System.out.println("beanPostProcessor = " + beanPostProcessor);beanFactory.addBeanPostProcessor(beanPostProcessor);});

这个根据Stream流的sorted进行排序,是根据BeanFactory对象的getDependencyComparator方法进行排序

在这里插入图片描述

AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory)方法是设置BeanFactory对象的依赖比较器

在这里插入图片描述

AutowiredAnnotationBeanPostProcessor这个bean的后置处理器是依赖注入@Autowired注解的bean对象,它的order设置成Integer的最大值减去2

在这里插入图片描述

CommonAnnotationBeanPostProcessor这个bean的后置处理器是依赖注入@Resource注解的bean对象,它的order设置成Integer的最大值减去3

order的值越小,优先级越高

在这里插入图片描述

可以看到,根据order进行排序,CommonAnnotationBeanPostProcessor的@Resource注解解析的bean对象优先级比AutowiredAnnotationBeanPostProcessor的@Autowried注解解析的bean对象的优先级更高

2.3 加载容器中的对象

System.out.println("==========================");Bean01 bean01 = beanFactory.getBean(Bean01.class);
System.out.println("bean01 = " + bean01);
Bean02 bean02 = beanFactory.getBean(Bean02.class);
System.out.println("bean02 = " + bean02);
bean02 = beanFactory.getBean(Bean01.class).getBean02();  //为null说明依赖注入失败了
System.out.println("bean02 = " + bean02);

默认是懒加载的,getBean用到这个对象的时候才会执行构造器

在这里插入图片描述

调用getBean方法才会执行构造器

// 实例化单例对象
beanFactory.preInstantiateSingletons();System.out.println("==========================");Bean01 bean01 = beanFactory.getBean(Bean01.class);
System.out.println("bean01 = " + bean01);
Bean02 bean02 = beanFactory.getBean(Bean02.class);
System.out.println("bean02 = " + bean02);
bean02 = beanFactory.getBean(Bean01.class).getBean02();  //为null说明依赖注入失败了
System.out.println("bean02 = " + bean02);

beanFactory.preInstantiateSingletons()方法会初始化容器中的单例对象

在这里插入图片描述

默认情况下是懒加载的,beanFactory.preInstantiateSingletons()方法会初始化容器中的单例对象

2.4 总结

因此,BeanFactory对象不会主动调用BeanFactory工厂的后置处理器,不会主动调用Bean的后置处理器,不会主动初始化单例对象,不会解析#{}和${}

3、ApplicationContext

AnnotationConfigServletWebServerApplicationContext applicationContext = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);

AnnotationConfigServletWebServerApplicationContex是一个基于注解配置的web服务器的容器applicationContext

@Configuration
static class WebConfig {// 配置内嵌容器@Beanpublic ServletWebServerFactory servletWebServerFactory() {return new TomcatServletWebServerFactory();}@Beanpublic DispatcherServlet dispatcherServlet() {return new DispatcherServlet();}// 注册DispatcherServlet到Tomcat服务器@Beanpublic DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet) {return new DispatcherServletRegistrationBean(dispatcherServlet, "/");}// Controller接口@Bean("/hello")public Controller controller() {return (httpServletRequest, httpServletResponse) -> {httpServletResponse.getWriter().println("hello");return null;};}
}

WebConfig是一个配置类,它在容器中创建了内嵌容器TomcatServletWebServerFactory,它创建了DispatcherServlet对象,它创建了DispatcherServletRegistrationBean对象用来注册DispatcherServlet对象到Tomcat服务器,还创建了一个Controller,这个Controller是一个接口,它在springframework.web.servlet.mvc包下,@Bean上写上/hello表示请求路径是/hello

浏览器输入:localhost:8080/hello,浏览器会返回hello

问题:启动服务失败

在这里插入图片描述

启动SpringBoot时发现DispatcherServletRegistrationBean有多个Bean实例,因此容器不知道选择哪个,因此可以使用@Primary注解指定相同类型的多个Bean对象优先使用哪个Bean对象并注入到容器中

4、Bean的生命周期

4.1 Bean的生命周期

Bean的生命周期包括:

构造方法实例化、依赖注入、初始化、销毁

@Component
@Log4j2
public class LifeCycleBean {public LifeCycleBean() {log.info("LifeCycleBean构造方法执行");}@Autowiredpublic void autowire(I18nMsgService i18nMsgService) {System.out.println(i18nMsgService.toString());log.info("LifeCycleBean依赖注入对象");}@PostConstructpublic void init() {log.info("LifeCycleBean初始化");}@PreDestroypublic void destroy() {log.info("LifeCycleBean销毁方法");}}

用@Component注解将LifeCycleBean对象注入到容器中,构造方法,用@Autowired注解依赖注入对象,用@PostConstruct注解实现初始化方法,用@PreDestroy注解实现销毁方法,方法的入参可以传入容器中的Bean对象

在这里插入图片描述

Bean的生命周期顺序是执行构造方法实例化、依赖注入方法、初始化方法、销毁方法

和Bean的生命周期相关的有Bean的后置处理器

@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {if("lifeCycleBean".equals(beanName)) {System.out.println(beanName + "对象构造方法执行之前(实例化之前)");}// 修改返回的对象,如果返回null则保持原对象不变return null;}@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {if("lifeCycleBean".equals(beanName)) {System.out.println(beanName + "对象构造器方法执行之后(实例化之后)");}// 如果返回false则会跳过依赖注入阶段return true;}@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {if("lifeCycleBean".equals(beanName)) {System.out.println(beanName + "对象依赖注入执行,解析@Autowired、@Resource、@Value");}return pvs;}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if("lifeCycleBean".equals(beanName)) {System.out.println(beanName + "对象的初始化方法之前执行,解析@PostConstruct, @ConfigurationProperties注解");}// 修改返回的对象,如果返回null则保持原对象不变return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if("lifeCycleBean".equals(beanName)) {System.out.println(beanName + "对象的初始化方法之后执行,可以创建代理对象用来增强");}// 修改返回的对象,如果返回null则保持原对象不变return null;}@Overridepublic void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {if("lifeCycleBean".equals(beanName)) {System.out.println(beanName + "对象的销毁方法之前执行");}}}

InstantiationAwareBeanPostProcessor和DestructionAwareBeanPostProcessor接口都继承了BeanPostProcessor接口

重写了实例化之前和之后的方法,重写了依赖注入之前的方法,重写了初始化之前和之后的方法,重写了销毁之前的方法

在这里插入图片描述

在LifeCycleBean对象的构造方法之前和之后分别打印,在依赖注入方法之前打印,在初始化方法之前和之后分别打印,在销毁方法之前打印

4.2 模板方法模式

模拟getBean方法,bean的生命周期中后置处理器用到模板方法模式

public class MyBeanFactory {@Testpublic void f1() {MyBeanFactory myBeanFactory = new MyBeanFactory();myBeanFactory.addBeanPostProcessor(bean -> System.out.println("bean后置处理器解析@Autowired注解"));myBeanFactory.addBeanPostProcessor(bean -> System.out.println("bean后置处理器解析@Resource注解"));Object bean = myBeanFactory.getBean();System.out.println("bean = " + bean);}public Object getBean() {Object bean = new Object();System.out.println("bean构造方法执行");System.out.println("bean依赖注入执行");// 抽象方法模式中变化的部分放在接口的方法上for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {beanPostProcessor.inject(bean);}System.out.println("bean初始化方法执行");System.out.println("bean销毁方法执行");return bean;}// 持有变化部分的接口集合private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {beanPostProcessorList.add(beanPostProcessor);}public interface BeanPostProcessor {public abstract void inject(Object bean);}}

模板方法模式是将变化的部分封装成一个接口或者抽象类,包含抽象方法,持有接口或者抽象类的List集合,用add方法新增持有的接口或者抽象类

在这里插入图片描述

模板方法模式可以执行Bean的生命周期

5、Bean的后置处理器

static class Bean1 {private Bean2 bean2;@Autowiredpublic void setBean2(Bean2 bean2) {System.out.println("@Autowired注解生效");this.bean2 = bean2;}private Bean3 bean3;@Resourcepublic void setBean3(Bean3 bean3) {System.out.println("@Resource注解生效");this.bean3 = bean3;}@Autowiredpublic void getServerPort(@Value("${server.port}") String port) {System.out.println("@Value生效,port = " + port);}@PostConstructpublic void init() {System.out.println("@PostConstruct注解生效");}@PreDestroypublic void destroy() {System.out.println("@PreDestroy注解生效");}}static class Bean2 {}static class Bean3 {}

定义Bean1、Bean2、Bean3等Bean对象,其中@Autowired修改的方法入参可以传入容器中的Bean对象,如果是字符串就用@Value注入

// GenericApplicationContext对象注册Bean对象
GenericApplicationContext genericApplicationContext = new GenericApplicationContext();
genericApplicationContext.registerBean("bean1", Bean1.class);
genericApplicationContext.registerBean("bean2", Bean2.class);
genericApplicationContext.registerBean("bean3", Bean3.class);// 注册后置处理器对象
// 设置@Value注入的对象
genericApplicationContext.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
// 解析@Autowired @Value注解
genericApplicationContext.registerBean(AutowiredAnnotationBeanPostProcessor.class);
// 解析@Resource @PostConstruct @PreDestroy注解
genericApplicationContext.registerBean(CommonAnnotationBeanPostProcessor.class);
// 解析@ConfigurationProperties注解
ConfigurationPropertiesBindingPostProcessor.register(genericApplicationContext.getDefaultListableBeanFactory());// 初始化容器
genericApplicationContext.refresh();// 销毁容器
genericApplicationContext.close();

GenericApplicationContext容器对象可以通过registerBean方法注册Bean对象,可以注册BeanPostProcessor后置处理器对象,可以通过refresh方法初始化容器,通过close方法销毁容器

在这里插入图片描述

先处理@Resource的后置处理器,然后处理@Autowired的后置处理器,因为@Resource的后置处理器的优先级更高


http://www.mrgr.cn/news/17479.html

相关文章:

  • C++STL简介
  • 华为盘古大模型
  • 实施面试题目
  • 记一次学习--webshell绕过(利用清洗函数)
  • HighPoint发布NVMe RAID外壳以应对严苛环境
  • 详解PyTorch中的`add_self_loops`函数及其在图神经网络中的应用
  • 【微服务】限流、熔断和降级(持续更新中~)
  • Clickhouse 为什么这么快
  • 【入门】面试408机试-排序(冒泡排序、快排)
  • 封装_私有类字段和方法
  • django企业开发实战-学习小结1
  • 数据库(MySQL)的基本操作
  • 每日错题(2024年9月1日)
  • Docker(完整实验版)
  • 二分查找 | 二分模板 | 二分题目解析
  • 时间戳:时间的数字化表达
  • 顶顶通热词模型配置热词方法(mod_cti基于FreeSWITCH)
  • Mysql:create table ... select ...报错
  • 18041 分期还款(加强版)
  • 进程间的通信(IPC)基础了解,匿名管道使用,有名管道使用