封面画师:T5-茨舞(微博) 封面ID:108988374
本文涉及的代码:springboot-study/extension-point-summary
参考链接:Springboot扩展点
本文基于 SpringBoot 3.1.x 和 JDK17
0. 前言
Spring 的核心是容器,SpringBoot 则是对 Spring 的又一层封装,一个注解、一个方法将复杂功能全部隐藏,实现开箱即用,但如果需要对某些功能进行定制,就需要利用 SpringBoot 预留的拓展点来实现。
学习 SpringBoot 的简单使用并不难,学习 SpringBoot 如何将复杂功能进行简化、预留的拓展点如何使用才是重中之重。
1. 应用上下文初始化器
1.1 拓展点的作用
应用上下文初始化器,即:ApplicationContextInitializer
,它并非由 SpringBoot 提供,而是在 Spring 中就存在的:
1 2 3 4 @FunctionalInterface public interface ApplicationContextInitializer <C extends ConfigurableApplicationContext > { void initialize (C applicationContext) ; }
在 Spring 容器初始化时,所有实现 ApplicationContextInitializer
接口的类都会被实例化;在 Spring 容器 refresh
前,ApplicationContextInitializer
所有实现类的 initialize()
方法都会被依次调用,调用顺序可使用 Spring 提供的 Ordered
接口、@Order
接口等方式进行指定。
ApplicationContextInitializer
接口常用于需要对应用上下文进行初始化的的 Web 应用程序中,比如在上下文环境中注册运行环境属性或激活配置文件。
1.2 使用方式
实现 ApplicationContextInitializer
接口,重写 initialize()
方法。
由于 initialize()
方法的执行时间点在 Spring 容器未初始化完成前,因此将实现类交由 Spring 管理,并以此来执行重写的 initialize()
方法是行不通的,此时可以使用 SpringBoot 的自动装配机制、读取配置文件信息或手动添加初始化器来添加初始化器。
编写 ApplicationContextInitializer
的三个实现类,在实现类中增加系统变量:
比如:
1 2 3 4 5 6 static class FirstApplicationContextInitializer implements ApplicationContextInitializer <ConfigurableApplicationContext> { @Override public void initialize (ConfigurableApplicationContext context) { putProperty(context, "1" , "ONE" ); } }
利用 SpringBoot 的自动装配机制
创建 META-INF/spring.factories
文件,在该文件中添加 ApplicationContextInitializer
的实现类信息:
1 2 org.springframework.context.ApplicationContextInitializer = \ indi.mofan.summary.a01.A01ExtensionPoint.FirstApplicationContextInitializer
读取配置文件信息
创建 application.properties
配置文件,在配置文件中以 context.initializer.classes
为 Key,添加 ApplicationContextInitializer
的实现类信息:
1 context.initializer.classes =indi.mofan.summary.a01.A01ExtensionPoint.SecondApplicationContextInitializer
手动添加初始化器
创建 SpringApplication
对象,调用其 addInitializers()
方法手动添加初始化器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @SpringBootApplication public class A01ExtensionPoint { public static void main (String[] args) { SpringApplication application = new SpringApplication (A01ExtensionPoint.class); application.addInitializers(new ThirdApplicationContextInitializer ()); ConfigurableApplicationContext context = application.run(args); ConfigurableEnvironment environment = context.getEnvironment(); System.out.println(environment.getProperty("1" )); System.out.println(environment.getProperty("2" )); System.out.println(environment.getProperty("3" )); context.close(); } }
1.3 实例化与执行
实例化
在 SpringBoot 中,构造 SpringApplication
对象时会调用 setInitializers()
方法添加所有 ApplicationContextInitializer
实例。见:
1 2 3 4 5 6 7 8 9 10 11 12 public SpringApplication (ResourceLoader resourceLoader, Class<?>... primarySources) { this .resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null" ); this .primarySources = new LinkedHashSet <>(Arrays.asList(primarySources)); this .webApplicationType = WebApplicationType.deduceFromClasspath(); this .bootstrapRegistryInitializers = new ArrayList <>( getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this .mainApplicationClass = deduceMainApplicationClass(); }
执行
调用 SpringApplication
对象的 run()
方法时,在执行 refreshContext()
方法前调用 prepareContext()
方法,在该方法中调用 applyInitializers()
方法执行上一步添加的所有 ApplicationContextInitializer
实例的 initialize()
方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 private void prepareContext (DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment); postProcessApplicationContext(context); addAotGeneratedInitializerIfNecessary(this .initializers); applyInitializers(context); listeners.contextPrepared(context); }
1.4 内置实现
DelegatingApplicationContextInitializer
实例化 ApplicationContextInitializer
时,是通过 SpringFactoriesLoader.loadFactoryNames()
方法获取 META-INF/spring.factories
文件中的实现类信息,而配置文件中的实现类信息是通过 DelegatingApplicationContextInitializer
得到的。
该实现类信息被 SpringBoot 默认添加到 META-INF/spring.factories
文件中,因此能够直接获取到其实例。
而后在执行 DelegatingApplicationContextInitializer
的 initialize()
方法时,获取配置文件中的 ApplicationContextInitializer
实现类信息,构造它们的实例并执行 initialize()
方法。
ContextIdApplicationContextInitializer
该实现类用于设置应用上下文 ID,如果配置文件中未显示指定 spring.application.name
的值,那么默认的应用上下文 ID 为 application
。
其他内置实现
ConfigurationWarningsApplicationContextInitializer
:添加后置处理器 ConfigurationWarningsPostProcessor
到 Spring 容器中,用于打印添加 Bean 时产生的警告信息;
ServerPortInfoApplicationContextInitializer
:该实现类也实现了 ApplicationListener
接口,其 initialize()
方法就是将自身添加到 Spring 容器中,用于监听 WebServerInitializedEvent
;
还有一些其他内置实现,其功能要么是添加后置处理器、要么是添加监听器,作用都大差不差。
2. Bean 工厂后置处理器
2.1 拓展点的作用
Bean 工厂后置处理器,即:BeanFactoryPostProcessor
,它也并非 SpringBoot 提供,而是在 Spring 中就存在的:
1 2 3 4 @FunctionalInterface public interface BeanFactoryPostProcessor { void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) throws BeansException; }
在 Spring 生命周期内,BeanFactoryPostProcessor
实例的 postProcessBeanFactory()
方法 只会 执行一次;在容器读取到所有的 BeanDefinition
后,但 Bean 尚未初始化前,读取 BeanDefinition
信息,对其中的属性进行修改或添加。
BeanFactoryPostProcessor
接口常用于修改应用程序上下文中系统管理员的自定义配置文件绑定的 Bean 属性信息,比如在读取配置文件中加密的敏感信息时,对这些信息进行解密。
2.2 使用方式
实现 BeanFactoryPostProcessor
接口,重写 postProcessBeanFactory()
方法,并 将实现类交由 Spring 管理。
postProcessBeanFactory()
方法的执行时机实在 Spring 容器读取到所有 BeanDefinition
后,因此将实现类交由 Spring 管理即可在对应时机执行 postProcessBeanFactory()
方法。
比如容器中已经存在名为 dog
的 Bean:
1 2 3 4 5 6 7 @Getter @Setter @Component("dog") static class Dog { private String name = "旺财" ; private Integer age = 2 ; }
现在需要修改该 Bean 的 name
信息,就需要使用到 BeanFactoryPostProcessor
接口:
1 2 3 4 5 6 7 8 9 @Component static class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) throws BeansException { ScannedGenericBeanDefinition definition = (ScannedGenericBeanDefinition) beanFactory.getBeanDefinition("dog" ); MutablePropertyValues properties = definition.getPropertyValues(); properties.add("name" , "小黑" ); } }
1 2 3 4 5 6 7 8 9 10 @SpringBootApplication public class A02ExtensionPoint { public static void main (String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A02ExtensionPoint.class, args); Dog dog = context.getBean(Dog.class); System.out.println(dog.getName()); System.out.println(dog.getAge()); context.close(); } }
小黑
2
2.3 执行入口
还是从调用 SpringApplication
对象的 run()
方法入手:
1 2 3 4 5 6 7 8 9 10 11 12 13 public ConfigurableApplicationContext run (String... args) { try { prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); } }
1 2 3 4 5 6 7 private void refreshContext (ConfigurableApplicationContext context) { if (this .registerShutdownHook) { shutdownHook.registerApplicationContext(context); } refresh(context); }
1 2 3 4 protected void refresh (ConfigurableApplicationContext applicationContext) { applicationContext.refresh(); }
ConfigurableApplicationContext
有三种实现类,但直接的实现类只有 AbstractApplicationContext
一种,另外两种实现类又会继承 AbstractApplicationContext
,因此重点分析 AbstractApplicationContext#refresh()
方法。
AbstractApplicationContext#refresh()
方法很重要,后续还会讲到。
在 refresh()
方法中调用了 invokeBeanFactoryPostProcessors()
方法,也是在这个方法中完成对所有 BeanFactoryPostProcessor
实例的 postProcessBeanFactory()
方法的调用。
invokeBeanFactoryPostProcessors()
方法只是一个入口,真正的实现是:
1 org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List<org.springframework.beans.factory.config.BeanFactoryPostProcessor>)
这个方法除了接收 ConfigurableListableBeanFactory
对象外,还接收了 BeanFactoryPostProcessor
实例列表。
2.4 第二个参数的来源
BeanFactoryPostProcessor
实例列表是从哪来的呢?
BeanFactoryPostProcessor
实例不应该直接从 BeanFactory 中获取吗?这里传入的又是什么呢?
传入的 BeanFactoryPostProcessor
实例列表是 AbstractApplicationContext
中的一个成员变量 beanFactoryPostProcessors
:
1 private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList <>();
提供了通过 addBeanFactoryPostProcessor()
方法作为修改的方式:
1 2 3 4 5 @Override public void addBeanFactoryPostProcessor (BeanFactoryPostProcessor postProcessor) { Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null" ); this .beanFactoryPostProcessors.add(postProcessor); }
调用该方法的地方共有两处:
org.springframework.boot.SpringApplication#prepareContext()
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer#initialize()
前者会在 SpringApplication#run()
方法中、在 refreshContext()
方法调用前被调用,因此在执行 refresh()
方法时能够拿到添加的 BeanFactoryPostProcessor
实例;后者的 ConfigurationWarningsApplicationContextInitializer
是先前介绍的 ApplicationContextInitializer
的一个实现类,其 initialize()
方法会在 prepareContext()
方法中被调用,也能够在后续执行时拿到被添加的 BeanFactoryPostProcessor
实例。
2.5 执行的逻辑
又回到 PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()
方法,源码里先是一大段注释,简单来说就是 不要瞎重构这个方法来减少多个循环和多个列表的使用 ,因为那是故意为之的,具体来说是不能通过调用 getBean()
方法获取某些 BeanFactoryPostProcessor
,这会到导致 BeanFactoryPostProcessor
提前被实例化,或者以错误的顺序在 ApplicationContext 中注册 BeanFactoryPostProcessor
,最后甚至还给出了“耻辱墙 ”,里面过滤出所有被拒绝的相关 PR。😂
源码中充满了注释,像极了工作中写满注释不让同事乱动的样子。🤣
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 public static void invokeBeanFactoryPostProcessors ( ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { Set<String> processedBeans = new HashSet <>(); if (beanFactory instanceof BeanDefinitionRegistry registry) { List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList <>(); List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList <>(); for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) { if (postProcessor instanceof BeanDefinitionRegistryPostProcessor registryProcessor) { registryProcessor.postProcessBeanDefinitionRegistry(registry); registryProcessors.add(registryProcessor); } else { regularPostProcessors.add(postProcessor); } } List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList <>(); String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true , false ); for (String ppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup()); currentRegistryProcessors.clear(); postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true , false ); for (String ppName : postProcessorNames) { if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup()); currentRegistryProcessors.clear(); boolean reiterate = true ; while (reiterate) { reiterate = false ; postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true , false ); for (String ppName : postProcessorNames) { if (!processedBeans.contains(ppName)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); reiterate = true ; } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup()); currentRegistryProcessors.clear(); } invokeBeanFactoryPostProcessors(registryProcessors, beanFactory); invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory); } else { invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory); } String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true , false ); List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList <>(); List<String> orderedPostProcessorNames = new ArrayList <>(); List<String> nonOrderedPostProcessorNames = new ArrayList <>(); for (String ppName : postProcessorNames) { if (processedBeans.contains(ppName)) { } else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class)); } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } sortPostProcessors(priorityOrderedPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList <>(orderedPostProcessorNames.size()); for (String postProcessorName : orderedPostProcessorNames) { orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); } sortPostProcessors(orderedPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList <>(nonOrderedPostProcessorNames.size()); for (String postProcessorName : nonOrderedPostProcessorNames) { nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); } invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory); beanFactory.clearMetadataCache(); }
PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()
方法不仅处理了 BeanFactoryPostProcessor
,还处理了 BeanDefinitionRegistryPostProcessor
,后者被称为“Bean 定义注册器后置处理器”,是一种容器级的后置处理器,那它又是什么呢?
3. Bean 定义注册器后置处理器
3.1 拓展点的作用
Bean 定义注册器后置处理器,即:BeanDefinitionRegistryPostProcessor
,它同样并非 SpringBoot 提供,也是在 Spring 中就存在的:
1 2 3 public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor { void postProcessBeanDefinitionRegistry (BeanDefinitionRegistry registry) throws BeansException; }
它是容器级别的后置处理器,将在 Spring 容器初始化后、refresh
前(即 Bean 被抽象成 BeanDefinition
后、未实例化前)执行。
提供了 postProcessBeanDefinitionRegistry()
方法,使用 BeanDefinitionRegistry
能够对 BeanDefinition 进行增删改查。
该接口继承了 BeanFactoryPostProcessor
接口,是它的一个拓展,通过前文的介绍可知它们都是在同一个方法中被执行的,只不过 BeanDefinitionRegistryPostProcessor
较 BeanFactoryPostProcessor
更先 执行,因此 可以使用 BeanDefinitionRegistryPostProcessor
可以用来注册 BeanFactoryPostProcessor
的 BeanDefinition 。
3.2 使用方式
实现 BeanDefinitionRegistryPostProcessor
接口,重写 postProcessBeanDefinitionRegistry()
方法,并 将实现类交由 Spring 管理。
比如存在 Cat
类,它并未交由 Spring 管理:
1 2 3 4 5 6 @Getter @Setter static class Cat { private String name; private String age; }
编写实现类,实现 BeanDefinitionRegistryPostProcessor
接口,尝试注册 Cat
类型的 BeanDefinition:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Component static class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry (BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException { RootBeanDefinition beanDefinition = new RootBeanDefinition (); beanDefinition.setBeanClass(Cat.class); PropertyValue name = new PropertyValue ("name" , "大橘" ); PropertyValue age = new PropertyValue ("age" , 1 ); MutablePropertyValues propertyValues = new MutablePropertyValues (Arrays.asList(name, age)); beanDefinition.setPropertyValues(propertyValues); beanDefinitionRegistry.registerBeanDefinition("cat" , beanDefinition); } @Override public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) throws BeansException { RootBeanDefinition beanDefinition = (RootBeanDefinition) beanFactory.getBeanDefinition("cat" ); MutablePropertyValues propertyValues = beanDefinition.getPropertyValues(); System.out.println("原始年龄是: " + propertyValues.get("age" )); propertyValues.add("age" , 2 ); } }
在重写的 postProcessBeanDefinitionRegistry()
方法中手动注册 Cat
类型、名为 cat
的 BeanDefinition,并添加了名为 age
的 property;在重写的 postProcessBeanFactory()
方法中获取名为 cat
的 BeanDefinition,然后添加同名的 property,新值将覆盖旧值。
1 2 3 4 5 6 7 8 9 10 @SpringBootApplication public class A03ExtensionPoint { public static void main (String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A03ExtensionPoint.class, args); Cat cat = context.getBean(Cat.class); System.out.println(cat.getName()); System.out.println(cat.getAge()); context.close(); } }
原始年龄是: 1
大橘
2
3.3 相关的几个类
BeanDefinition
是什么?
postProcessBeanDefinitionRegistry()
方法的入参 BeanDefinitionRegistry
是什么?
postProcessBeanFactory()
方法的入参 ConfigurableListableBeanFactory
又是什么?
理解这些类的含义有助于更好地理解 Spring 拓展点。
BeanDefinition
BeanDefinition
意为“Bean 定义”,是用来定义 Bean 的。
Spring 容器中 Bean 的来源有多种,Bean 的类型又有多种,如何将这些不同来源、不同类型的 Bean 使用同一种方式注册到 Spring 容器中就成了个问题。
定义 BeanDefinition
类,它将不同的 Bean 信息进行抽象成 BeanDefinition
对象,在不同时机根据 BeanDefinition
对象对 Bean 进行实例化。
BeanDefinitionRegistry
BeanDefinitionRegistry
意为“Bean 定义注册器”,是用来注册 BeanDefinition
的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public interface BeanDefinitionRegistry extends AliasRegistry { void registerBeanDefinition (String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException; void removeBeanDefinition (String beanName) throws NoSuchBeanDefinitionException; BeanDefinition getBeanDefinition (String beanName) throws NoSuchBeanDefinitionException; boolean containsBeanDefinition (String beanName) ; String[] getBeanDefinitionNames(); int getBeanDefinitionCount () ; boolean isBeanNameInUse (String beanName) ; }
AliasRegistry
用于管理别名,作为 BeanDefinitionRegistry
的父类。
ConfigurableListableBeanFactory
ConfigurableListableBeanFactory
意为“可配置的列表 Bean 工厂”。所谓 Spring 容器,指的就是 BeanFactory
,它提供了多种重载的 getBean()
方法用于获取 Bean,而 ConfigurableListableBeanFactory
是 BeanFactory
的一个子接口,可以认为它就是 Spring 容器。
在 Spring 中,其默认实现是 DefaultListableBeanFactory
:
它继承了很多接口,包括 ConfigurableListableBeanFactory
、BeanDefinitionRegistry
等等。
3.4 实例化与执行
参考【2.3 实例化与执行】即可。
3.5 内置实现
BeanDefinitionRegistryPostProcessor
在 Spring 和 SpringBoot 中有众多内置实现,它们的大致逻辑都差不多,都是注册了一些特殊的 BeanDefinition
。
在 Spring 中有一个名为 ConfigurationClassPostProcessor
的实现类,用于解析 @Configuration
注解,可以参考 @Configuration 注解的那些事 一文。
4. Bean 后置处理器
4.1 拓展点的作用
Bean 后置处理器,即:BeanPostProcessor
,它并非 SpringBoot 提供,是在 Spring 中就存在的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public interface BeanPostProcessor { @Nullable default Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException { return bean; } @Nullable default Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException { return bean; } }
它是 Bean 级别的后置处理器,在 Bean 实例化后执行。单例 Bean 被实例化后,最终会被缓存到 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#singletonObjects
中,在实例化之后会进行初始化过程,包括属性填充、自定义初始化方法等,BeanPostProcessor
就是对这个阶段进行的拓展。
注意实例化和初始化的区别,实例化指的是 new
出一个对象,初始化指的是给 new
出的对象进行属性填充等操作。
BeanPostProcessor
提供了两个方法,分别是 postProcessBeforeInitialization()
和 postProcessAfterInitialization()
,前者将在 Bean 实例化后、初始化前执行,后者将在初始化后、自定义初始方法后执行。
BeanPostProcessor
与先前的所有拓展点都不同,并不是只执行一次,而是会作用于 Spring 管理的每个 Bean。
4.2 使用方式
实现 BeanPostProcessor
接口,重写抽象方法,并 将实现类交由 Spring 管理。
比如存在 Fish
类,采用配置类的方式将其交由 Spring 管理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @Getter @Setter static class Fish implements InitializingBean { private Double weight; private Double price; public Fish () { System.out.println("1. 执行了无参构造" ); } @Override public void afterPropertiesSet () throws Exception { System.out.println("3. 执行了 afterPropertiesSet() 方法" ); } public void init () { System.out.println("4. 执行了 init() 方法" ); } } @Configuration static class A04Configuration { @Bean(name = "fish", initMethod = "init") public Fish fish () { return new Fish (); } }
编写 BeanPostProcessor
的实现类,重写其中的抽象方法,当遇到名为 fish
的 Bean 时,执行一些特殊操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Component static class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException { if ("fish" .equals(beanName)) { System.out.println("2. 执行了 postProcessBeforeInitialization() 方法" ); } return bean; } @Override public Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException { if ("fish" .equals(beanName)) { System.out.println("5. 执行了 postProcessAfterInitialization() 方法" ); } return bean; } }
1 2 3 4 5 6 7 @SpringBootApplication public class A04ExtensionPoint { public static void main (String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A04ExtensionPoint.class, args); context.close(); } }
1. 执行了无参构造
2. 执行了 postProcessBeforeInitialization() 方法
3. 执行了 afterPropertiesSet() 方法
4. 执行了 init() 方法
5. 执行了 postProcessAfterInitialization() 方法
4.3 注册与执行
前文中已经介绍过 AbstractApplicationContext#refresh()
方法了,BeanPostProcessor
的注册与执行也将围绕这个方法。
注册
在 AbstractApplicationContext#refresh()
方法中调用了 registerBeanPostProcessors()
方法,见名之意,该方法完成了 BeanPostProcessor
的注册。
它只是一个入口,真正的实现是:
1 org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, org.springframework.context.support.AbstractApplicationContext)
PostProcessorRegistrationDelegate
很熟悉,BeanFactoryPostProcessor
与 BeanDefinitionRegistryPostProcessor
的执行也是使用的这个类中的方法。
registerBeanPostProcessors()
与前文介绍的 invokeBeanFactoryPostProcessors()
方法很类似,内部充满了注释,也告诉想要提交 PR 的开发者不要瞎重构。😂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 public static void registerBeanPostProcessors ( ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) { String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true , false ); int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length; beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker (beanFactory, beanProcessorTargetCount)); List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList <>(); List<BeanPostProcessor> internalPostProcessors = new ArrayList <>(); List<String> orderedPostProcessorNames = new ArrayList <>(); List<String> nonOrderedPostProcessorNames = new ArrayList <>(); for (String ppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); priorityOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } sortPostProcessors(priorityOrderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); List<BeanPostProcessor> orderedPostProcessors = new ArrayList <>(orderedPostProcessorNames.size()); for (String ppName : orderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); orderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } sortPostProcessors(orderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, orderedPostProcessors); List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList <>(nonOrderedPostProcessorNames.size()); for (String ppName : nonOrderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); nonOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); sortPostProcessors(internalPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, internalPostProcessors); beanFactory.addBeanPostProcessor(new ApplicationListenerDetector (applicationContext)); }
简单来说就是先获取容器中的所有 BeanPostProcessor
,然后按照优先级分成三类再依次注册。
注册的逻辑采用 registerBeanPostProcessors()
方法实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 private static void registerBeanPostProcessors ( ConfigurableListableBeanFactory beanFactory, List<? extends BeanPostProcessor> postProcessors) { if (beanFactory instanceof AbstractBeanFactory abstractBeanFactory) { abstractBeanFactory.addBeanPostProcessors(postProcessors); } else { for (BeanPostProcessor postProcessor : postProcessors) { beanFactory.addBeanPostProcessor(postProcessor); } } }
调用 beanFactory
的 addBeanPostProcessor()
方法完成 BeanPostProcessor
的注册,最终由 AbstractBeanFactory#addBeanPostProcessor()
实现真正的逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 private final List<BeanPostProcessor> beanPostProcessors = new BeanPostProcessorCacheAwareList ();@Override public void addBeanPostProcessor (BeanPostProcessor beanPostProcessor) { Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null" ); synchronized (this .beanPostProcessors) { this .beanPostProcessors.remove(beanPostProcessor); this .beanPostProcessors.add(beanPostProcessor); } }
执行
BeanPostProcessor
将在 Bean 实例化后,初始化前后执行,也就是说只要找到 Bean 实例化的位置,那 BeanPostProcessor
的执行时机也就在那附近了。
在 refresh()
方法中调用了 finishBeanFactoryInitialization()
方法:
1 2 finishBeanFactoryInitialization(beanFactory);
其上的注释:实例化所有剩余的非懒加载单例 Bean。
也就是说,这个方法将完成 Bean 的实例化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 protected void finishBeanFactoryInitialization (ConfigurableListableBeanFactory beanFactory) { if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { beanFactory.setConversionService( beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); } if (!beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); } String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false , false ); for (String weaverAwareName : weaverAwareNames) { getBean(weaverAwareName); } beanFactory.setTempClassLoader(null ); beanFactory.freezeConfiguration(); beanFactory.preInstantiateSingletons(); }
显然,重点是最后调用 beanFactory
的 preInstantiateSingletons()
方法。
其默认实现是 DefaultListableBeanFactory
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @Override public void preInstantiateSingletons () throws BeansException { if (logger.isTraceEnabled()) { logger.trace("Pre-instantiating singletons in " + this ); } List<String> beanNames = new ArrayList <>(this .beanDefinitionNames); for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof SmartFactoryBean<?> smartFactoryBean && smartFactoryBean.isEagerInit()) { getBean(beanName); } } else { getBean(beanName); } } } for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton smartSingleton) { StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize" ) .tag("beanName" , beanName); smartSingleton.afterSingletonsInstantiated(); smartInitialize.end(); } } }
总体来说分成两部分:
触发所有非懒加载单例 Bean 的初始化,使用 getBean()
实现
为所有适用的 Bean 触发后置初始化回调,即调用 SmartInitializingSingleton
的 afterSingletonsInstantiated()
方法(这个拓展点在后续会讲到)
getBean()
的流程很长,也不是本文的重点, 后续另开一文详细分析, 此处仅着重分析要点:
1 2 3 4 @Override public Object getBean (String name) throws BeansException { return doGetBean(name, null , null , false ); }
调用了 doGetBean()
方法,这个方法贼长,重点是调用的 createBean()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 protected <T> T doGetBean ( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } }); beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } }
其默认实现是 AbstractAutowireCapableBeanFactory#createBean()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Override protected Object createBean (String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { try { Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isTraceEnabled()) { logger.trace("Finished creating instance of bean '" + beanName + "'" ); } return beanInstance; } }
重点是调用的 doCreateBean()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 protected Object doCreateBean (String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); exposedObject = initializeBean(beanName, exposedObject, mbd); } }
在这个方法中完成了 Bean 的实例和初始化,初始化操作由 initializeBean()
方法完成。BeanPostProcessor
会在 Bean 初始化前后执行,不妨大胆猜测就是在 initializeBean()
方法中完成 BeanPostProcessor
的执行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 protected Object initializeBean (String beanName, Object bean, @Nullable RootBeanDefinition mbd) { invokeAwareMethods(beanName, bean); Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException ( (mbd != null ? mbd.getResourceDescription() : null ), beanName, ex.getMessage(), ex); } if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
查看源码后也是验证了猜想,选取 applyBeanPostProcessorsBeforeInitialization()
方法进行解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Override public Object applyBeanPostProcessorsBeforeInitialization (Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessBeforeInitialization(result, beanName); if (current == null ) { return result; } result = current; } return result; }
逻辑很简单,获取所有 BeanPostProcessor
后进行遍历,依次执行它们的 postProcessBeforeInitialization()
方法。那 BeanPostProcessor
是怎么获取的呢?
1 2 3 public List<BeanPostProcessor> getBeanPostProcessors () { return this .beanPostProcessors; }
调用的是 AbstractBeanFactory#getBeanPostProcessors()
方法,直接返回成员变量 beanPostProcessors
的值,这里和前文中注册 BeanPostProcessor
的逻辑串联了起来。
4.4 内置实现与使用场景
内置实现举例
SpringBoot 进行参数校验时会使用到 BeanValidationPostProcessor
,它也是 BeanPostProcessor
的一种内置实现。
更多使用场景
有时可能会编写一些自定义注解将它们标记到相应的类上,希望在对应的 Bean 实例化后,根据标记的自定义注解执行特定的逻辑,此时就可以通过实现 BeanPostProcessor
完成。
4.5 更多思考
BeanPostProcessor
能够在 Bean 初始化前后被调用,那如果要在 Bean 实例化前后进行拓展应该怎么办呢?
5. 实例化感知 Bean 后置处理器
5.1 拓展点的作用
实例化感知 Bean 后置处理器,即:InstantiationAwareBeanPostProcessor
,它并非 SpringBoot 提供,是在 Spring 中就存在的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor { @Nullable default Object postProcessBeforeInstantiation (Class<?> beanClass, String beanName) throws BeansException { return null ; } default boolean postProcessAfterInstantiation (Object bean, String beanName) throws BeansException { return true ; } @Nullable default PropertyValues postProcessProperties (PropertyValues pvs, Object bean, String beanName) throws BeansException { return pvs; } }
可以看到,InstantiationAwareBeanPostProcessor
继承了 BeanPostProcessor
,并额外提供了三个方法,能够分别在 Bean 实例化前、实例化后、属性注入阶段进行拓展。
InstantiationAwareBeanPostProcessor
与 BeanPostProcessor
类似,会作用于 Spring 管理的每个 Bean。
5.2 使用方法
实现 InstantiationAwareBeanPostProcessor
接口,重写抽象方法,并 将实现类交由 Spring 管理。
比如存在 Dependence
和 Example
类,将t它们交由 Spring 管理,并在 Example
中注入 Dependence
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 @Getter @Setter static class Example { private String str = "example" ; private Dependence dependence; @Autowired public void setDependence (Dependence dependence) { System.out.println("6. Example 注入 dependence" ); this .dependence = dependence; } public void setStr (String str) { System.out.println("7. Example 注入 str" ); this .str = str; } public Example () { System.out.println("3. 执行了 Example 的无参构造" ); } public void init () { System.out.println("9. 执行了 init() 方法" ); } } @Configuration static class A05Configuration { @Bean(initMethod = "init", value = EXAMPLE_BEAN_NAME) public Example example () { return new Example (); } } @Component static class Dependence { public Dependence () { System.out.println("1. 执行了 Dependence 的无参构造" ); } }
编写 InstantiationAwareBeanPostProcessor
的实现类,重写其中所有抽象方法(包括父接口 BeanPostProcessor
中的方法),当遇到名为 a05-example
的 Bean 时,执行一些特殊操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 @Component static class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor { @Override public Object postProcessBeforeInstantiation (Class<?> beanClass, String beanName) throws BeansException { if (EXAMPLE_BEAN_NAME.equals(beanName)) { System.out.println("2. 执行了 postProcessBeforeInstantiation() 方法" ); } return null ; } @Override public boolean postProcessAfterInstantiation (Object bean, String beanName) throws BeansException { if (EXAMPLE_BEAN_NAME.equals(beanName)) { System.out.println("4. 执行了 postProcessAfterInstantiation() 方法" ); } return true ; } @Override public PropertyValues postProcessProperties (PropertyValues pvs, Object bean, String beanName) throws BeansException { if (EXAMPLE_BEAN_NAME.equals(beanName)) { System.out.println("5. 执行了 postProcessProperties() 方法" ); MutablePropertyValues propertyValues = (MutablePropertyValues) pvs; propertyValues.add("str" , "str" ); } return pvs; } @Override public Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException { if (EXAMPLE_BEAN_NAME.equals(beanName)) { System.out.println("8. 执行了 postProcessBeforeInitialization() 方法" ); } return bean; } @Override public Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException { if (EXAMPLE_BEAN_NAME.equals(beanName)) { System.out.println("10. 执行了 postProcessAfterInitialization() 方法" ); } return bean; } }
1 2 3 4 5 6 7 8 9 10 11 12 @SpringBootApplication public class A05ExtensionPoint { private static final String EXAMPLE_BEAN_NAME = "a05-example" ; public static void main (String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A05ExtensionPoint.class, args); Assert.isTrue(context.getBean(Example.class).getStr().equals("str" ), "" ); Assert.isTrue(context.getBean(Example.class).getDependence().equals(context.getBean(Dependence.class)), "" ); context.close(); } }
1. 执行了 Dependence 的无参构造
2. 执行了 postProcessBeforeInstantiation() 方法
3. 执行了 Example 的无参构造
4. 执行了 postProcessAfterInstantiation() 方法
5. 执行了 postProcessProperties() 方法
6. Example 注入 dependence
7. Example 注入 str
8. 执行了 postProcessBeforeInitialization() 方法
9. 执行了 init() 方法
10. 执行了 postProcessAfterInitialization() 方法
InstantiationAwareBeanPostProcessor
之于 BeanPostProcessor
,就好比 BeanDefinitionRegistryPostProcessor
之于 BeanFactoryPostProcessor
,这里的比较主要是在执行时机上。
InstantiationAwareBeanPostProcessor
将在 BeanPostProcessor
前执行,对于增加的三个方法有:
postProcessBeforeInstantiation()
:该方法将在 Bean 实例化前被执行。该方法有 Object
类型的返回值,可以自定义 Bean 替换原有的 Bean(比如进行了动态代理),在替换原有 Bean 后,将执行 postProcessAfterInstantiation()
,其他拓展点将不再触发;
postProcessAfterInstantiation()
:该方法将在 Bean 实例化后被执行。该方法有 boolean
类型的返回值,它表示是否需要依赖注入,如果返回 false
,将不再执行 InstantiationAwareBeanPostProcessor
实例中的其他任何拓展方法(包括父类 BeanPostProcessor
中的方法);
postProcessProperties()
:该方法将在 Bean 实例化后、属性注入前执行。在此方法中可以对注入的属性值进行更改,或替换原来的属性值。默认情况下直接返回传入的 PropertyValues
,如果返回 null
将跳过后续的属性填充。
5.3 注册
InstantiationAwareBeanPostProcessor
是 BeanPostProcessor
的子接口,因此它的注册方式与 BeanPostProcessor
的注册方式一样,参考【4.3 注册与执行】。
5.4 执行
postProcessBeforeInstantiation()
InstantiationAwareBeanPostProcessor
的第一个方法 postProcessBeforeInstantiation()
将在 Bean 实例化前执行,结合上一节的内容,可以猜到这个方法的执行与 refresh()
方法中调用的 finishBeanFactoryInitialization()
方法有关。
大致流程与上一节类似,跟随相同的流程来到 AbstractAutowireCapableBeanFactory#createBean()
方法中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @Override protected Object createBean (String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { try { Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null ) { return bean; } } try { Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isTraceEnabled()) { logger.trace("Finished creating instance of bean '" + beanName + "'" ); } return beanInstance; } }
在这个方法中调用了 resolveBeforeInstantiation()
方法,这个方法能够在 Bean 实例化前做一些操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Nullable protected Object resolveBeforeInstantiation (String beanName, RootBeanDefinition mbd) { Object bean = null ; if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) { if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { Class<?> targetType = determineTargetType(beanName, mbd); if (targetType != null ) { bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); if (bean != null ) { bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } mbd.beforeInstantiationResolved = (bean != null ); } return bean; }
当 postProcessBeforeInstantiation()
方法返回非 null
的值时,会立即执行 postProcessAfterInstantiation()
方法,而在 AbstractAutowireCapableBeanFactory#createBean()
方法中,resolveBeforeInstantiation()
方法返回的值不为 null
时,将直接返回,不再执行后续的 doCreateBean()
方法,也就是不再执行其他拓展点,Spring 将 Bean 实例化及其以后的所有操作都交给实现者。
applyBeanPostProcessorsBeforeInstantiation()
方法的实现也有点意思:
1 2 3 4 5 6 7 8 9 10 @Nullable protected Object applyBeanPostProcessorsBeforeInstantiation (Class<?> beanClass, String beanName) { for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) { Object result = bp.postProcessBeforeInstantiation(beanClass, beanName); if (result != null ) { return result; } } return null ; }
获取 InstantiationAwareBeanPostProcessor
的方式通过 getBeanPostProcessorCache().instantiationAware
完成,getBeanPostProcessorCache()
返回了 BeanPostProcessor
实例的缓存(还分了类),以便多次重复获取 BeanPostProcessor
。
postProcessAfterInstantiation()
与 postProcessProperties()
这个方法将会在 Bean 实例化之后 执行,大胆猜测很有可能在 doCreateBean()
方法中执行,这在前文已经分析过一部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 protected Object doCreateBean (String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); exposedObject = initializeBean(beanName, exposedObject, mbd); } }
前文分析的是其中的 initializeBean()
方法,这个方法完成了 Bean 的初始化。
在计算机的英语表述中,populate
常被翻译为“填充”,populateBean()
方法将使用 BeanDefinition
中的属性值填充 BeanWrapper
中的 Bean 实例。
也就是说,这个方法会被 Bean 实例进行一些操作,点进去看看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 protected void populateBean (String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) { if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { return ; } } } if (hasInstantiationAwareBeanPostProcessors()) { if (pvs == null ) { pvs = mbd.getPropertyValues(); } for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) { PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null ) { return ; } pvs = pvsToUse; } } }
在这个方法中,执行了 InstantiationAwareBeanPostProcessor
中的第二、第三个拓展方法,这些拓展方法返回特殊的返回值时,会跳过后续逻辑的执行。
5.5 内置实现
InstantiationAwareBeanPostProcessor
的实现十分有用,在 Spring 中也一个名为 AutowiredAnnotationBeanPostProcessor
的实现:
AutowiredAnnotationBeanPostProcessor
用于解析 Bean 属性注入的相关注解,比如 @Autowired
和 @Value
注解的解析。
Bean 中的字段被 @Autowired
注解标记后,可以将 Spring 容器中对应类型的 Bean 注入到当前 Bean 中,其实现逻辑就在重写的 postProcessProperties()
方法中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Override public PropertyValues postProcessProperties (PropertyValues pvs, Object bean, String beanName) { InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); try { metadata.inject(bean, beanName, pvs); } catch (BeanCreationException ex) { throw ex; } catch (Throwable ex) { throw new BeanCreationException (beanName, "Injection of autowired dependencies failed" , ex); } return pvs; }
AutowiredAnnotationBeanPostProcessor
实现了 SmartInstantiationAwareBeanPostProcessor
接口,后者则继承了 InstantiationAwareBeanPostProcessor
,那 SmartInstantiationAwareBeanPostProcessor
又是何方神圣?
6. 智能实例化感知 Bean 后置处理器
6.1 拓展点的作用
智能实例化感知 Bean 后置处理器,即:SmartInstantiationAwareBeanPostProcessor
,它并非 SpringBoot 提供,是在 Spring 中就存在的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor { @Nullable default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException { return null ; } default Class<?> determineBeanType(Class<?> beanClass, String beanName) throws BeansException { return beanClass; } @Nullable default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException { return null ; } default Object getEarlyBeanReference (Object bean, String beanName) throws BeansException { return bean; } }
可以看到,SmartInstantiationAwareBeanPostProcessor
继承了 InstantiationAwareBeanPostProcessor
,并额外提供了四个方法,其中 determineBeanType()
方法是在 Spring 6.0 中新增的。
在类注释上有一段 NOTE,简单来说就是:SmartInstantiationAwareBeanPostProcessor
接口是一个专用接口,主要在框架内部使用。一般情况下,日常开发中实现 BeanPostProcessor
接口即可。
6.2 使用方式
存在名为 Student
的类,它依赖了 Teacher
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 @Component(value = STUDENT_BEAN_NAME) static class Student { @Getter @Setter private String name = "mofan" ; @Getter @Autowired private Teacher teacher; public Student () { System.out.println("Student 的无参数构造方法被执行" ); } public Student (String name) { this .name = name; System.out.println("Student 的有参数构造方法(name)被执行" ); } public Student (Teacher teacher) { this .teacher = teacher; System.out.println("Student 的有参数构造方法(teacher)被执行" ); } public Student (String name, Teacher teacher) { this .name = name; this .teacher = teacher; System.out.println("Student 的有参数构造方法(name,teacher)被执行" ); } public void setTeacher (Teacher teacher) { System.out.println("----student中的setTeacher方法被调用" ); this .teacher = teacher; } }
存在名为 Teacher
的类,它内部依赖了 Student
,构成了循环依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Component static class Teacher { @Getter @Setter private String name = "Mr.Chen" ; @Getter @Autowired private Student student; public Teacher () { System.out.println("Teacher 的无参数构造方法被执行" ); } public void setStudent (Student student) { System.out.println("Teacher 中的 setStudent 方法被调用" ); this .student = student; } }
实现 SmartInstantiationAwareBeanPostProcessor
接口,选择性重写其中的方法,并将实现类交由 Spring 管理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 @Component static class MySmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor { @Override public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException { if (STUDENT_BEAN_NAME.equals(beanName)) { System.out.println("predictBeanType 方法被执行" ); return Student.class; } return null ; } @Override public Class<?> determineBeanType(Class<?> beanClass, String beanName) throws BeansException { if (STUDENT_BEAN_NAME.equals(beanName)) { System.out.println("determineBeanType 方法被执行" ); } return beanClass; } @Override public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException { if (STUDENT_BEAN_NAME.equals(beanName)) { System.out.println("determineCandidateConstructors 方法被执行" ); return new Constructor []{beanClass.getConstructors()[0 ]}; } return null ; } @Override public Object getEarlyBeanReference (Object bean, String beanName) throws BeansException { if (STUDENT_BEAN_NAME.equals(beanName)) { System.out.println("getEarlyBeanReference 方法被执行" ); } return bean; } @Override public Object postProcessBeforeInstantiation (Class<?> beanClass, String beanName) throws BeansException { if (STUDENT_BEAN_NAME.equals(beanName)) { System.out.println("postProcessBeforeInstantiation 方法被执行" ); } return null ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @SpringBootApplication public class A06ExtensionPoint { private static final String STUDENT_BEAN_NAME = "a06-student" ; public static void main (String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A06ExtensionPoint.class); Teacher teacher = context.getBean(Teacher.class); System.out.println(teacher.getClass().getName()); Student student = context.getBean(Student.class); System.out.println(student.getClass().getName()); context.close(); } }
predictBeanType 方法被执行
postProcessBeforeInstantiation 方法被执行
determineCandidateConstructors 方法被执行
Student 的无参数构造方法被执行
predictBeanType 方法被执行
Teacher 的无参数构造方法被执行
predictBeanType 方法被执行
predictBeanType 方法被执行
getEarlyBeanReference 方法被执行
省略了许多 predictBeanType 方法被执行
的打印。
6.3 注册
SmartInstantiationAwareBeanPostProcessor
是 BeanPostProcessor
的子接口,因此它的注册方式与 BeanPostProcessor
的注册方式一样,参考【4.3 注册与执行】。
6.4 执行
此处只介绍 determineCandidateConstructors()
方法的执行时间,该方法用于确定候选构造器,在实例化 Bean 使用。
在前文的介绍中可知,在 getBean()
方法里会对 Bean 进行实例化。跟随前文的步骤,来到 AbstractAutowireCapableBeanFactory#doCreateBean()
方法中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 protected Object doCreateBean (String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { BeanWrapper instanceWrapper = null ; if (mbd.isSingleton()) { instanceWrapper = this .factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null ) { instanceWrapper = createBeanInstance(beanName, mbd, args); } Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } }
首先就是实例化 Bean,其中调用了 createBeanInstance()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 protected BeanWrapper createBeanInstance (String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } ctors = mbd.getPreferredConstructors(); if (ctors != null ) { return autowireConstructor(beanName, mbd, ctors, null ); } return instantiateBean(beanName, mbd); }
调用了 determineConstructorsFromBeanPostProcessors()
方法,如果存在被 @Autowired
注解标记的构造器时,就使用这个构造器来实例化 Bean。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Nullable protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName) throws BeansException { if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) { for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) { Constructor<?>[] ctors = bp.determineCandidateConstructors(beanClass, beanName); if (ctors != null ) { return ctors; } } } return null ; }
可以看到,就是在此处调用了 determineCandidateConstructors()
方法。
6.5 内置实现
以 AutowiredAnnotationBeanPostProcessor
为例。
predictBeanType()
在 AutowiredAnnotationBeanPostProcessor
中并未重写 predictBeanType()
方法。
在 Spring AOP 中,AbstractAutoProxyCreator
重写了 predictBeanType()
方法,这与 AOP 的实现有关,此处不再深究, 后续另开一文详细分析 。
determineBeanType()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Override public Class<?> determineBeanType(Class<?> beanClass, String beanName) throws BeanCreationException { checkLookupMethods(beanClass, beanName); if (this .beanFactory instanceof AbstractAutowireCapableBeanFactory aacBeanFactory) { RootBeanDefinition mbd = (RootBeanDefinition) this .beanFactory.getMergedBeanDefinition(beanName); if (mbd.getFactoryMethodName() == null && mbd.hasBeanClass()) { return aacBeanFactory.getInstantiationStrategy().getActualBeanClass(mbd, beanName, aacBeanFactory); } } return beanClass; }
determineCandidateConstructors()
重写的 determineCandidateConstructors()
方法很长,简单来说就是遍历类中所有构造器,然后选取出候选构造器。该方法中有这样一段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 @Override @Nullable public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName) throws BeanCreationException { for (Constructor<?> candidate : rawCandidates) { MergedAnnotation<?> ann = findAutowiredAnnotation(candidate); if (ann == null ) { } if (ann != null ) { if (requiredConstructor != null ) { throw new BeanCreationException (); } boolean required = determineRequiredStatus(ann); if (required) { if (!candidates.isEmpty()) { throw new BeanCreationException (); } requiredConstructor = candidate; } candidates.add(candidate); } else if (candidate.getParameterCount() == 0 ) { defaultConstructor = candidate; } } return (candidateConstructors.length > 0 ? candidateConstructors : null ); }
遍历构造器时,使用 findAutowiredAnnotation()
方法查看构造器上是否有指定注解,如果有指定注解,并且使用 determineRequiredStatus()
方法求得注解标记的构造器是必需的,那么当前构造器就是必需的构造器。
1 2 3 4 5 6 7 8 9 10 11 @Nullable private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) { MergedAnnotations annotations = MergedAnnotations.from(ao); for (Class<? extends Annotation > type : this .autowiredAnnotationTypes) { MergedAnnotation<?> annotation = annotations.get(type); if (annotation.isPresent()) { return annotation; } } return null ; }
对构造器而言,遍历 this.autowiredAnnotationTypes
的值,查看构造器是否被这些注解标记。this.autowiredAnnotationTypes
的值在构造 AutowiredAnnotationBeanPostProcessor
实例时被指定,默认有以下四个值:
@org.springframework.beans.factory.annotation.Autowired
@org.springframework.beans.factory.annotation.Value
@jakarta.inject.Inject
@javax.inject.Inject
1 2 3 4 protected boolean determineRequiredStatus (MergedAnnotation<?> ann) { return (ann.getValue(this .requiredParameterName).isEmpty() || this .requiredParameterValue == ann.getBoolean(this .requiredParameterName)); }
该方法用于判断给定注解是否配置了 require
。比如以 @Autowired
注解,该注解有 require
属性,同时该属性值为 true
时,determineRequiredStatus()
方法返回 true
;以 @Value
注解来说,它不含 require
或 optional
属性,determineRequiredStatus()
方法也返回 true
。
getEarlyBeanReference()
在 AutowiredAnnotationBeanPostProcessor
中并未重写 getEarlyBeanReference()
方法。
在 Spring AOP 中,AbstractAutoProxyCreator
重写了 predictBeanType()
方法,这与 AOP 的实现有关,此处不再深究, 后续另开一文详细分析 。
7. 应用上下文感知
7.1 拓展点的作用
应用上下文感知,即:ApplicationContextAware
,它并非 SpringBoot 提供,是在 Spring 中就存在的:
1 2 3 4 5 6 7 8 public interface ApplicationContextAware extends Aware { void setApplicationContext (ApplicationContext applicationContext) throws BeansException; }
该接口实现了 Aware
接口,提供了 setApplicationContext()
方法,用于获取 ApplicationContext
,通常用于设置某个 Bean 中 ApplicationContext
类型的字段值。
Aware
接口是一个标记接口,Spring 中提供了众多的 Aware 接口,这些接口中都有以 set
开头的方法,用于获取特定的对象。比如:
EnvironmentAware
:获取 Environment
对象,该对象可用于获得系统内所有的参数,也可以通过注入的方式获取该对象;
EmbeddedValueResolverAware
:获取 StringValueResolver
对象,该对象可用于获取 String
类型的 property,也可以通过 @Value
注解获取 String
类型的 property;
ResourceLoaderAware
:获取 ResourceLoader
对象,该对象可用于获取 classpath
下的所有资源;
ApplicationEventPublisherAware
:获取 ApplicationEventPublisher
对象,该对象可用于发送事件,也可以通过注入的方式获取该对象;
MessageSourceAware
:获取 MessageSource
对象,该对象可用于获取国际化信息;
ApplicationStartupAware
:获取 ApplicationStartup
对象,该对象可用于获取 Spring 启动期间各个步骤的信息。
Aware
的子接口其实有很多,那为什么只列举上面那些呢?
因为 上面这些 Aware
接口都由 ApplicationContextAwareProcessor
处理。
7.2 使用方式
以 ApplicationContextAware
接口为例,实现 ApplicationContextAware
接口,重写 setApplicationContext()
方法,并将实现类交由 Spring 管理。
除此之外,ApplicationContext
对象还可以通过注入获取:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @Component static class MyApplicationContextAware implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext (ApplicationContext applicationContext) throws BeansException { this .applicationContext = applicationContext; System.out.println("2. Spring 上下文 ApplicationContext 被注入" ); } } @Component static class MyApplicationContext { private ApplicationContext applicationContext; @Autowired public void setApplicationContext (ApplicationContext applicationContext) { this .applicationContext = applicationContext; System.out.println("1. 使用 @Autowired 注入 ApplicationContext" ); } }
1 2 3 4 5 6 7 @SpringBootApplication public class A07ExtensionPoint { public static void main (String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A07ExtensionPoint.class, args); context.close(); } }
1. 使用 @Autowired 注入 ApplicationContext
2. Spring 上下文 ApplicationContext 被注入
可以看到,相比于通过 ApplicationContextAware
获取 ApplicationContext
对象,直接注入 ApplicationContext
会更早执行。
7.3 注册与执行
可以使用 ApplicationContextAware
获取 ApplicationContext
对象,也可以直接注入 ApplicationContext
,它们有什么区别呢?
ApplicationContextAware
接口由 ApplicationContextAwareProcessor
处理,后者实现了 BeanPostProcessor
接口并重写 postProcessBeforeInitialization()
方法,在 Bean 初始化前处理继承了 ApplicationContextAware
接口的 Bean,但 ApplicationContextAwareProcessor
并未被 @Component
等注解标记,那它是怎么添加到 Spring 容器中的呢?
这些问题在 获取 ApplicationContext 一文中可以获得准确答案,此处不再赘述。
7.4 一个重要的细节
ApplicationContextAwareProcessor
被加载的时机
ApplicationContextAwareProcessor
将在准备 BeanFactory 时被加载,也就在 refresh()
方法中的 prepareBeanFactory()
方法中被加载:
flowchart TD
1("SpringApplication#refresh()")
2("AbstractApplicationContext#refresh()")
3("AbstractApplicationContext#prepareBeanFactory()")
1 --> 2 --> 3
这一步是十分靠前的。
其他 BeanPostProcessor
相比于 ApplicationContextAwareProcessor
的注册时机
ApplicationContextAwareProcessor
实现了 BeanPostProcessor
接口,重写了其中的 postProcessBeforeInitialization()
方法, 会在 Bean 实例化后、初始化前执行。
回忆 BeanPostProcessor
的注册时机,它是在 refresh()
方法中的 registerBeanPostProcessors()
方法中被注册的。refresh()
方法中的部分流程如下:
flowchart TD
1("prepareRefresh()")
2("obtainFreshBeanFactory")
subgraph 3 ["prepareBeanFactory()"]
3.1("加载 ApplicationContextAwareProcessor")
end
4("postProcessBeanFactory()")
subgraph 5 ["invokeBeanFactoryPostProcessors()"]
5.1("执行 BeanFactoryPostProcessor")
end
subgraph 6 ["registerBeanPostProcessors()"]
6.1("注册 BeanPostProcessor")
end
7("...")
1 --> 2 --> 3 --> 4 --> 5 --> 6 --> 7
在注册其他 BeanPostProcessor
前,容器中已经存在了 ApplicationContextAwareProcessor
类型的 BeanPostProcessor
。
直接注入 ApplicationContext
的实现
注入 ApplicationContext
时会使用 @Autowired
或 @Resource
注解,前者由 AutowiredAnnotationBeanPostProcessor
实现,后者由 CommonAnnotationBeanPostProcessor
实现,它们都是 BeanPostProcessor
的实现, 它们实例化的时机是在 registerBeanPostProcessors()
方法中,相比于 ApplicationContextAwareProcessor
的实例化时机更加靠后。
这说明了什么呢?
也就是说,如果想要在 registerBeanPostProcessors()
方法前创建的 Bean 中拿到 ApplicationContext
实例,只能通过实现 ApplicationContextAware
接口完成,而不能通过注入 ApplicationContext
获取,因为那时还没加载用于解析相关注解的 BeanPostProcessor
。
比如在 BeanFactoryPostProcessor
的实现类中获取 ApplicationContext
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @Component static class MyFirstBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Autowired private ApplicationContext context; @Override public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) throws BeansException { Assert.isNull(context, "依赖注入的 ApplicationContext 不是 null" ); } } @Component static class MySecondBeanFactoryPostProcessor implements BeanFactoryPostProcessor , ApplicationContextAware { private ApplicationContext context; @Override public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) throws BeansException { Assert.notNull(context, "使用 ApplicationContextAware 注入的 ApplicationContext 为 null" ); } @Override public void setApplicationContext (ApplicationContext applicationContext) throws BeansException { this .context = applicationContext; } }
BeanFactoryPostProcessor
将在 invokeBeanFactoryPostProcessors()
方法中完成实例化与执行,实例化是通过 getBean()
方法完成的,如果容器中存在指定名称的 Bean,就直接获取,否则先创建再获取,这在前文已经说过了。
在通过 getBean()
实例化 BeanFactoryPostProcessor
前,会获取当前容器中的所有 BeanPostProcessor
实例,并执行它们的 postProcessBeforeInitialization()
方法,此时容器中存在 ApplicationContextAwareProcessor
类型的 BeanPostProcessor
,使得实现 ApplicationContextAware
接口的 Bean 能够拿到 ApplicationContext
实例,而利用注入方式获取的 ApplicationContext
实例,由于还未加载相关的解析类,因此注入是无效的。
7.5 另一个 Aware
除了使用 ApplicationContextAwareProcessor
处理的一众 Aware
外,还有一个名为 BeanNameAware
的接口,它提供了获取某个 Bean 的 name 的能力:
1 2 3 public interface BeanNameAware extends Aware { void setBeanName (String name) ; }
使用方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 @SpringBootApplication public class A14ExtensionPoint { public static void main (String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A14ExtensionPoint.class); MyBean myBean = context.getBean(MyBean.class); Assert.isTrue(BEAN_NAME.equals(myBean.beanName), "Bean 的 name 不相等" ); context.close(); } private static final String BEAN_NAME = "A Yi A Yi A" ; static class MyBean implements BeanNameAware { private String beanName; @Override public void setBeanName (String name) { this .beanName = name; } } @Configuration static class MyConfig { @Bean(BEAN_NAME) public MyBean myBean () { return new MyBean (); } } }
执行
它将在 Bean 初始化之前被执行,在 AbstractAutowireCapableBeanFactory#initializeBean()
方法的首行调用了 invokeAwareMethods()
方法,此方法完成了 BeanNameAware
等多个 Aware
的执行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 private void invokeAwareMethods (String beanName, Object bean) { if (bean instanceof Aware) { if (bean instanceof BeanNameAware beanNameAware) { beanNameAware.setBeanName(beanName); } if (bean instanceof BeanClassLoaderAware beanClassLoaderAware) { ClassLoader bcl = getBeanClassLoader(); if (bcl != null ) { beanClassLoaderAware.setBeanClassLoader(bcl); } } if (bean instanceof BeanFactoryAware beanFactoryAware) { beanFactoryAware.setBeanFactory(AbstractAutowireCapableBeanFactory.this ); } } }
至于到 initializeBean()
的具体流程,可以参考前文【Bean 后置处理器】的执行逻辑。
8. @PostConstruct
8.1 拓展点的作用
该注解的全限定类名是 @javax.annotation.PostConstruct
,它并非 Spring 提供,但 Spring 为其提供了实现:
1 2 3 4 5 @Documented @Retention (RUNTIME)@Target(METHOD) public @interface PostConstruct {}
在 JDK8 之前,该注解可以直接使用;JDK9 之后引入模块系统,将该注解剔除了 JDK,因此需要引入额外的依赖:
1 2 3 4 5 <dependency > <groupId > jakarta.annotation</groupId > <artifactId > jakarta.annotation-api</artifactId > <version > 2.1.1</version > </dependency >
@PostConstruct
只能作用于方法上, 在依赖注入完成后,执行一次被 @PostConstruct
注解标记的方法。
在一个类中,被 @PostConstruct
注解标记的方法只能有一个。
被 @PostConstruct
注解标记的方法必须满足以下条件:
该方法不能有任何参数,除非是拦截器,在这种情况下,需要一个由拦截器规范定义的 InvocationContext
对象;
在拦截器类或拦截器类的超类上定义的方法必须具有以下签名之一:
1 2 void <METHOD>(InvocationContext) Object <METHOD>(InvocationContext) throws Exception
注意:@PostConstruct
标记的拦截方法不得抛出应用程序异常,但如果在同一个拦截方法中除了生命周期事件外还对业务或超时方法进行了拦截,则可以通过 throws
抛出包括 java.lang.Exception
在内的受检异常。如果 @PostConstruct
标记的拦截方法有返回值,容器会忽略该值;
在非拦截器类上定义的方法必须具有以下签名:
被 @PostConstruct
注解标记的方法可以是 public
、protected
、package private
或 private
;
除应用程序客户端外,该方法不能是静态方法;
该方法不能是 final
的;
如果该方法抛出一个非受检异常,则该类不会投入使用,除非该异常被拦截器处理。
8.2 使用方式
比如存在 A07Example
类,将其交由 Spring 管理,内部依赖了 A07Dependence
类型的 Bean:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 private static final String BEAN_NAME = "a07Example" ;@Component static class A07Dependence { public A07Dependence () { System.out.println("1. 执行了 A07Dependence 的无参构造" ); } } @Component(BEAN_NAME) static class A07Example { private A07Dependence dependence; public A07Example (A07Dependence dependence) { System.out.println("2. 执行了 A07Example 的无参构造" ); } @Autowired public void setDependence (A07Dependence dependence) { this .dependence = dependence; System.out.println("3. A07Example 注入 dependence" ); } @PostConstruct public void init () { System.out.println("5. 执行了 @PostConstruct 标记的方法" ); } }
再提供一个 BeanPostProcessor
的实现类,用于确定被 @PostConstruct
注解标记的方法是什么时候执行的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Component static class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException { if (BEAN_NAME.equals(beanName)) { System.out.println("4. 执行了 postProcessBeforeInitialization 方法" ); } return bean; } @Override public Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException { if (BEAN_NAME.equals(beanName)) { System.out.println("6. 执行了 postProcessAfterInitialization 方法" ); } return bean; } }
1 2 3 4 5 6 7 @SpringBootApplication public class A08ExtensionPoint { public static void main (String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A08ExtensionPoint.class, args); context.close(); } }
1. 执行了 A07Dependence 的无参构造
2. 执行了 A07Example 的无参构造
3. A07Example 注入 dependence
4. 执行了 postProcessBeforeInitialization 方法
5. 执行了 @PostConstruct 标记的方法
6. 执行了 postProcessAfterInitialization 方法
A07Example
还实现了 InitializingBean
接口,这会在下一节讲到。
可以看到,被 @PostConstruct
标记的方法会在依赖注入后、postProcessBeforeInitialization()
方法后、postProcessAfterInitialization()
方法前执行。
8.3 执行
被 @PostConstruct
标记的方法是什么时候执行的呢?
前文的使用示例可以确定大致范围,如果需要确定准确的时间点,最好的方式还是在被 @PostConstruct
标记的方法里打一个断点,通过方法调用栈进行追踪:
在调用栈中可以看到熟悉的 AbstractAutowireCapableBeanFactory#doCreateBean()
方法,最终来到 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization()
方法中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Override public Object applyBeanPostProcessorsBeforeInitialization (Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessBeforeInitialization(result, beanName); if (current == null ) { return result; } result = current; } return result; }
这个方法很熟悉,在前文介绍 BeanPostProcessor
中方法的执行时机时进行了讲解,难道说 @PostConstruct
注解会由 BeanPostProcessor
的一个实现类进行解析?
定位到那一步,查看遍历的 processor
是何许人也:
引出了一个新类:CommonAnnotationBeanPostProcessor
。
CommonAnnotationBeanPostProcessor
并未直接实现 BeanPostProcessor
接口,而是继承了 InitDestroyAnnotationBeanPostProcessor
,后者实现了 BeanPostProcessor
的子接口,重写的 postProcessBeforeInitialization()
方法也在这个类中:
1 2 3 4 5 6 7 8 9 @Override public Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException { LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass()); try { metadata.invokeInitMethods(bean, beanName); } return bean; }
一共就两部:
先找到生命周期元数据,即:LifecycleMetadata
;
然后根据 LifecycleMetadata
执行初始化方法。
InitDestroyAnnotationBeanPostProcessor#findLifecycleMetadata()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 private LifecycleMetadata findLifecycleMetadata (Class<?> beanClass) { if (this .lifecycleMetadataCache == null ) { return buildLifecycleMetadata(beanClass); } LifecycleMetadata metadata = this .lifecycleMetadataCache.get(beanClass); if (metadata == null ) { synchronized (this .lifecycleMetadataCache) { metadata = this .lifecycleMetadataCache.get(beanClass); if (metadata == null ) { metadata = buildLifecycleMetadata(beanClass); this .lifecycleMetadataCache.put(beanClass, metadata); } return metadata; } } return metadata; }
重点是其中的 buildLifecycleMetadata()
方法:
1 2 3 4 5 6 7 8 9 private LifecycleMetadata buildLifecycleMetadata (final Class<?> beanClass) { if (!AnnotationUtils.isCandidateClass(beanClass, this .initAnnotationTypes) && !AnnotationUtils.isCandidateClass(beanClass, this .destroyAnnotationTypes)) { return this .emptyLifecycleMetadata; } }
重点是 AnnotationUtils.isCandidateClass()
方法,这里调用了两次,如果都返回 false
则直接返回 emptyLifecycleMetadata
。
除此之外,initAnnotationTypes
和 destroyAnnotationTypes
应该是目标注解类型,那它们的值是什么呢?
1 2 3 private final Set<Class<? extends Annotation >> initAnnotationTypes = new LinkedHashSet <>(2 );private final Set<Class<? extends Annotation >> destroyAnnotationTypes = new LinkedHashSet <>(2 );
以 initAnnotationTypes
为例,提供了 addInitAnnotationType()
方法:
1 2 3 4 5 public void addInitAnnotationType (@Nullable Class<? extends Annotation> initAnnotationType) { if (initAnnotationType != null ) { this .initAnnotationTypes.add(initAnnotationType); } }
该方法在 CommonAnnotationBeanPostProcessor
的构造函数中被调用,利用 loadAnnotationType()
加载指定全限定类名的注解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public CommonAnnotationBeanPostProcessor () { setOrder(Ordered.LOWEST_PRECEDENCE - 3 ); addInitAnnotationType(loadAnnotationType("jakarta.annotation.PostConstruct" )); addDestroyAnnotationType(loadAnnotationType("jakarta.annotation.PreDestroy" )); addInitAnnotationType(loadAnnotationType("javax.annotation.PostConstruct" )); addDestroyAnnotationType(loadAnnotationType("javax.annotation.PreDestroy" )); if (jndiPresent) { this .jndiFactory = new SimpleJndiBeanFactory (); } }
至于 loadAnnotationType()
的实现逻辑,无非是对 Class.forName()
的包装,这不是重点。
再回到 AnnotationUtils.isCandidateClass()
方法:
1 2 3 4 5 6 7 8 public static boolean isCandidateClass (Class<?> clazz, Collection<Class<? extends Annotation>> annotationTypes) { for (Class<? extends Annotation > annotationType : annotationTypes) { if (isCandidateClass(clazz, annotationType)) { return true ; } } return false ; }
内部调用了 isCandidateClass()
方法:
1 2 3 public static boolean isCandidateClass (Class<?> clazz, @Nullable Class<? extends Annotation> annotationType) { return (annotationType != null && isCandidateClass(clazz, annotationType.getName())); }
又调用重载的 isCandidateClass()
方法:
1 2 3 4 5 6 7 8 9 10 public static boolean isCandidateClass (Class<?> clazz, String annotationName) { if (annotationName.startsWith("java." )) { return true ; } if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) { return false ; } return true ; }
最后调用了 AnnotationsScanner.hasPlainJavaAnnotationsOnly()
方法,如果它返回 true
,最终返回 false
,否则最终返回 true
:
1 2 3 4 static boolean hasPlainJavaAnnotationsOnly (Class<?> type) { return (type.getName().startsWith("java." ) || type == Ordered.class); }
分析了半天,好像并没有什么有意思的东西… 😅
InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata#invokeInitMethods()
回到 invokeInitMethods()
方法,看看是怎么执行目标方法的,多半是遍历每个目标方法然后利用反射去执行:
1 2 3 4 5 6 7 8 9 10 11 12 13 public void invokeInitMethods (Object target, String beanName) throws Throwable { Collection<LifecycleMethod> checkedInitMethods = this .checkedInitMethods; Collection<LifecycleMethod> initMethodsToIterate = (checkedInitMethods != null ? checkedInitMethods : this .initMethods); if (!initMethodsToIterate.isEmpty()) { for (LifecycleMethod lifecycleMethod : initMethodsToIterate) { if (logger.isTraceEnabled()) { logger.trace("Invoking init method on bean '" + beanName + "': " + lifecycleMethod.getMethod()); } lifecycleMethod.invoke(target); } } }
又是遍历,然后执行了 InitDestroyAnnotationBeanPostProcessor.LifecycleMethod#invoke()
方法:
1 2 3 4 public void invoke (Object target) throws Throwable { ReflectionUtils.makeAccessible(this .method); this .method.invoke(target); }
果不其然,印证了前面的猜想。
总结
执行逻辑很简单,概括后就两步:
遍历目标类中的每个方法,收集被指定注解标记的方法;
反射执行被指定注解标记的方法
9. 初始化 Bean
9.1 拓展点的作用
初始化 Bean,即:InitializingBean
,它并非 SpringBoot 提供,是在 Spring 中就存在的:
1 2 3 4 5 6 7 8 public interface InitializingBean { void afterPropertiesSet () throws Exception; }
其中仅有一个无参无返回值的 afterPropertiesSet()
,根据方法名称可知,这个方法很有可能在属性注入后执行。
9.2 使用方式
实现 InitializingBean
接口并重写 afterPropertiesSet()
方法,将实现类交由 Spring 管理,并且在类中使用 @PostConstruct
注解标记:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 private static final String EXAMPLE_BEAN_NAME = "a08-example" ;@Component static class A08Dependence {} static class A08Example implements InitializingBean { private A08Dependence dependence; @Autowired public void setDependence (A08Dependence dependence) { this .dependence = dependence; System.out.println("1. A08Example 注入 dependence" ); } @Override public void afterPropertiesSet () throws Exception { System.out.println("4. 执行了 afterPropertiesSet 方法" ); } @PostConstruct public void init () { System.out.println("3. 执行了 init 方法" ); } public void initMethod () { System.out.println("5. 执行了 init-method" ); } } @Configuration static class MyConfig { @Bean(value = EXAMPLE_BEAN_NAME, initMethod = "initMethod") public A08Example a08Example () { return new A08Example (); } }
同样提供一个 BeanPostProcessor
的实现类,用于确定 afterPropertiesSet()
方法是什么时候执行的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Component static class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException { if (EXAMPLE_BEAN_NAME.equals(beanName)) { System.out.println("2. 执行了 postProcessBeforeInitialization 方法" ); } return bean; } @Override public Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException { if (EXAMPLE_BEAN_NAME.equals(beanName)) { System.out.println("5. 执行了 postProcessAfterInitialization 方法" ); } return bean; } }
1 2 3 4 5 6 7 @SpringBootApplication public class A09ExtensionPoint { public static void main (String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A09ExtensionPoint.class, args); context.close(); } }
1. A08Example 注入 dependence
2. 执行了 postProcessBeforeInitialization 方法
3. 执行了 init 方法
4. 执行了 afterPropertiesSet 方法
5. 执行了 init-method
6. 执行了 postProcessAfterInitialization 方法
可以看到,afterPropertiesSet()
方法在 postProcessAfterInitialization()
方法前执行,同时还在 init-method
方法前执行。
9.3 执行
前文的使用示例可以确定大致范围,要确定准确的范围也可以利用断点查看方法调用栈:
又见熟悉的 doCreateBean()
方法,之后进入 initializeBean()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 protected Object initializeBean (String beanName, Object bean, @Nullable RootBeanDefinition mbd) { invokeAwareMethods(beanName, bean); Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException ( (mbd != null ? mbd.getResourceDescription() : null ), beanName, ex.getMessage(), ex); } if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
而后调用 invokeInitMethods()
方法,根据调用方法栈可知,在调用 invokeInitMethods()
方法后,就执行了重写的 afterPropertiesSet()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 protected void invokeInitMethods (String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable { boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet" ))) { ((InitializingBean) bean).afterPropertiesSet(); } if (mbd != null && bean.getClass() != NullBean.class) { String[] initMethodNames = mbd.getInitMethodNames(); if (initMethodNames != null ) { for (String initMethodName : initMethodNames) { if (StringUtils.hasLength(initMethodName) && !(isInitializingBean && "afterPropertiesSet" .equals(initMethodName)) && !mbd.hasAnyExternallyManagedInitMethod(initMethodName)) { invokeCustomInitMethod(beanName, bean, mbd, initMethodName); } } } } }
在第一个 if
判断中执行了 InitializingBean
的 afterPropertiesSet()
方法。
如果对使用示例的 initMethod()
方法进行断点,则会进入第二个 if
分支,在内部调用 invokeCustomInitMethod()
方法利用反射执行 initMethod()
方法。
9.4 内置实现
利用 InitializingBean
接口可以修改默认设置的属性值、添加额外的属性值,或者对某些属性值进行校验,在 Spring MVC 中有个名为 RequestMappingHandlerMapping
的类,用于实现 Controller 与 URL 的映射。它也实现了 InitializingBean
接口:
10. 智能初始化单例
10.1 拓展点的作用
智能初始化单例,即:SmartInitializingSingleton
,它并非 SpringBoot 提供,是在 Spring 中就存在的:
1 2 3 4 5 6 7 8 9 10 11 12 public interface SmartInitializingSingleton { void afterSingletonsInstantiated () ; }
其中仅有一个无参无返回值的 afterSingletonsInstantiated()
,根据方法名称可知,这个方法很有可能在 Bean 初始化后执行。
注意: 是在所有单例 Bean 初始化完成后执行,对懒加载单例 Bean 和多例 Bean 则没要求。
10.2 使用方式
实现 SmartInitializingSingleton
接口,重写 afterSingletonsInstantiated()
方法,并将实现类交由 Spring 管理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 private static final String BEAN_NAME = "myBean" ;@Component(BEAN_NAME) static class MySmartInitializingSingleton implements InitializingBean , SmartInitializingSingleton { @Override public void afterPropertiesSet () { System.out.println("1. 执行了 afterPropertiesSet 方法" ); } @Override public void afterSingletonsInstantiated () { System.out.println("3. 执行了 afterSingletonsInstantiated 方法" ); } }
同样提供一个 BeanPostProcessor
的实现类,只重写 postProcessAfterInitialization()
方法,用于确定 afterSingletonsInstantiated()
方法是什么时候执行的:
1 2 3 4 5 6 7 8 9 10 @Component static class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException { if (BEAN_NAME.equals(beanName)) { System.out.println("2. 执行了 postProcessAfterInitialization 方法" ); } return bean; } }
1 2 3 4 5 6 7 @SpringBootApplication public class A10ExtensionPoint { public static void main (String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A10ExtensionPoint.class, args); context.close(); } }
1. 执行了 afterPropertiesSet 方法
2. 执行了 postProcessAfterInitialization 方法
3. 执行了 afterSingletonsInstantiated 方法
可以看到,afterSingletonsInstantiated()
会在 postProcessAfterInitialization()
方法后执行,确实是在 Bean 初始化完成后执行。
10.3 执行
至于执行时机,其实在【4.3 注册与执行】中介绍 BeanPostProcessor
的执行时机时已经介绍过。
目前已知的情报是会在单例 Bean 初始化完成后执行 afterSingletonsInstantiated()
方法。
以 AbstractApplicationContext#refresh()
方法为入口:
flowchart TD
1("AbstractApplicationContext#refresh()")
2("AbstractApplicationContext#finishBeanFactoryInitialization()")
3("DefaultListableBeanFactory#preInstantiateSingletons()")
1 --> 2 --> 3
在 preInstantiateSingletons()
方法中有:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Override public void preInstantiateSingletons () throws BeansException { for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton smartSingleton) { StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize" ) .tag("beanName" , beanName); smartSingleton.afterSingletonsInstantiated(); smartInitialize.end(); } } }
执行过程很简单,几步就走到了 afterSingletonsInstantiated()
的执行点。
11. 两个执行器
11.1 拓展点的作用
本节拓展点的名字并不是真的叫“两个执行器”,😂 而是将在本节介绍两个拓展点,它们以 Runner
结尾,翻译成执行器也没啥问题。
这两个执行器分别是 CommandLineRunner
和 ApplicationRunner
。
为什么要在本节一起介绍,是因为它们很类似,执行时间点也很靠近,它们都拥有名为 run()
的方法,只是参数不同:
1 2 3 4 5 6 7 8 9 @FunctionalInterface public interface CommandLineRunner { void run (String... args) throws Exception; } @FunctionalInterface public interface ApplicationRunner { void run (ApplicationArguments args) throws Exception; }
前面介绍的拓展点都是在 Spring 中本身就存在的,而不是 SpringBoot 单独提供的,而本节的这两个执行器则是由 SpringBoot 提供。
ApplicationRunner
会早于 CommandLineRunner
执行,它们都将在 Spring 容器、Web 容器启动后,正式处理业务请求前(即项目启动的最后一步)执行。
这两个接口可用于正式处理业务请求前预加载热点数据、清除临时文件、读取自定义配置信息等。
在一个应用程序上下文中可以定义多个 ApplicationRunner
或 CommandLineRunner
,此时可以使用 Ordered
接口或 @Order
注解对这些执行器的执行顺序进行排序。
11.2 使用方式
分别实现 ApplicationRunner
和 CommandLineRunner
接口,重写其中的 run()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 private static final String COMMAND_LINE_BEAN = "command-line-bean" ;private static final String APPLICATION_BEAN = "application-bean" ;@Component(COMMAND_LINE_BEAN) static class MyCommandLineRunner implements CommandLineRunner { @Override public void run (String... args) throws Exception { System.out.println("执行 CommandLineRunner" ); } } @Component(APPLICATION_BEAN) static class MyApplicationRunner implements ApplicationRunner { @Override public void run (ApplicationArguments args) throws Exception { System.out.println("执行 ApplicationRunner" ); } }
再次提供一个 BeanPostProcessor
的实现类,只重写 postProcessAfterInitialization()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 private static final Set<String> BEAN_NAMES = Set.of(COMMAND_LINE_BEAN, APPLICATION_BEAN);@Component static class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException { if (BEAN_NAMES.contains(beanName)) { System.out.printf("检测到指定 Bean:[%s] 的 postProcessAfterInitialization 方法%n" , beanName); } return bean; } }
1 2 3 4 5 6 7 @SpringBootApplication public class A11ExtensionPoint { public static void main (String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A11ExtensionPoint.class); context.close(); } }
检测到指定 Bean:[application-bean] 的 postProcessAfterInitialization 方法
检测到指定 Bean:[command-line-bean] 的 postProcessAfterInitialization 方法
执行 ApplicationRunner
执行 CommandLineRunner
根据使用示例可知 ApplicationRunner
确实会早于 CommandLineRunner
执行。
11.3 执行
前文中许多拓展点都与 refresh()
方法有关,refresh
一词可译为“刷新”,表示刷新上下文,其中最重要的就是将 Bean 添加到 Spring 容器(Spring 容器是 Spring 上下文的一部分)中。从使用示例可知,本节的两个拓展点会在 Bean 初始化之后执行,那么很有可能不会在 refresh()
方法中执行。
从 Spring 主启动类出发:
flowchart TD
1("SpringApplication#run(java.lang.Class<?>, java.lang.String...)")
2("SpringApplication#run(java.lang.Class<?>[], java.lang.String[])")
3("SpringApplication#run(java.lang.String...)")
1 --> 2 --> 3
执行时机既不在 refreshContext()
中,也不在 afterRefresh()
中,而是在最后的 callRunners()
中,这方法名称也很明确——调用执行器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private void callRunners (ApplicationContext context, ApplicationArguments args) { List<Object> runners = new ArrayList <>(); runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); AnnotationAwareOrderComparator.sort(runners); for (Object runner : new LinkedHashSet <>(runners)) { if (runner instanceof ApplicationRunner applicationRunner) { callRunner(applicationRunner, args); } if (runner instanceof CommandLineRunner commandLineRunner) { callRunner(commandLineRunner, args); } } }
12. 工厂 Bean
12.1 拓展点的作用
工厂 Bean,即:FactoryBean
,它并非 SpringBoot 提供,是在 Spring 中就存在的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public interface FactoryBean <T> { String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType" ; @Nullable T getObject () throws Exception; @Nullable Class<?> getObjectType(); default boolean isSingleton () { return true ; } }
FactoryBean
其实并不能认为是拓展点,它是创建复杂 Bean 的一种方式。
在 Spring 中有一个类似的接口,名为 BeanFactory
,有一道常见的面试题:BeanFactory
与 FactoryBean
有什么异同?
它们之间的异倒是很大,至于同就只有名字长得比较相似了。BeanFactory
译为“Bean 工厂”,即生产存储 Bean 的地方,也就是常说的 Spring 容器;FactoryBean
译为“工厂 Bean”,是创建 Bean 的一种方式,就像设计模式中的工厂模式一样。
FactoryBean
中有三个方法:
getObject()
:获取 Bean 对象,用于创建一些难以使用常规方式创建的 Bean;
getObjectType()
:用于获取返回 Bean 的类型;
isSingleton()
:创建的 Bean 是否是单例 Bean,默认 true
。
12.2 使用方式
假设存在名为 Owl
的“复杂类”,尽管并不复杂:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 static class Owl { @Getter @Setter private String name; public Owl () { System.out.println("执行了无参构造" ); } public Owl (String name) { this .name = name; System.out.println("执行了有参(name)构造" ); } }
编写 FactoryBean
的实现类,重写其中的抽象方法,其中的 getObject()
方法返回 Owl
实例,并将实现类交由 Spring 管理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 private static final String OWL_BEAN_NAME = "owl" ;@Component(OWL_BEAN_NAME) static class OwlFactoryBean implements FactoryBean <Owl> { public OwlFactoryBean () { System.out.println("执行了 OwlFactoryBean 的无参构造" ); } @Override public Owl getObject () throws Exception { System.out.println("执行 getObject--start" ); Owl owl = new Owl (); System.out.println("执行 getObject--end" ); return owl; } @Override public Class<?> getObjectType() { return Owl.class; } @Override public boolean isSingleton () { return true ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 @SpringBootApplication public class A12ExtensionPoint { public static void main (String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A12ExtensionPoint.class); Object bean = context.getBean(OWL_BEAN_NAME); Assert.isInstanceOf(Owl.class, bean); bean = context.getBean(BeanFactory.FACTORY_BEAN_PREFIX + OWL_BEAN_NAME); Assert.isInstanceOf(OwlFactoryBean.class, bean); context.close(); } }
执行了 OwlFactoryBean 的无参构造
执行 getObject--start
执行了无参构造
执行 getObject--end
从容器中按照名称获取与 OwlFactoryBean
同名的 Bean 时,得到的 Bean 的类型并不是 OwlFactoryBean
,而是 Owl
类型的,如果要获取原始类型,则需要在名称前添加 &
(有点 C 语言的味道)。
12.3 注册
在注册 FactoryBean
类型的 Bean 时,按照给定的 Bean 名称或者默认规则进行注册,在 Spring 容器中只会存在 FactoryBean
类型的 Bean,不会存在 getObjectType()
返回的类型、 getObject()
返回的对象的 Bean。
通过 getBean()
方法按照注册的 FactoryBean
类型的 Bean 的名称在 Spring 容器中获取 Bean 时,获取到的是 getObject()
返回的对象,能够获取到这样的对象是 getBean()
方法中的细节,而不是在 Spring 容器中真实存在的。
12.4 执行
名称的细微差别能够通过 getBean()
方法获取到不同的 Bean 对象,那么就看看 getBean()
中的细节吧。
flowchart TD
1("AbstractBeanFactory#getBean(java.lang.String)")
2("AbstractBeanFactory#doGetBean()")
1 --> 2
来到 doGetBean()
方法后,不会像前文分析的那样来到 createBean()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 protected <T> T doGetBean ( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { String beanName = transformedBeanName(name); Object beanInstance; Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null ) { beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null ); } else { } }
而是会进入 getObjectForBeanInstance()
方法:
1 2 3 4 5 6 7 8 9 10 11 @Override protected Object getObjectForBeanInstance ( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { String currentlyCreatedBean = this .currentlyCreatedBean.get(); if (currentlyCreatedBean != null ) { registerDependentBean(beanName, currentlyCreatedBean); } return super .getObjectForBeanInstance(beanInstance, name, beanName, mbd); }
然后调用父类的 getObjectForBeanInstance()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 protected Object getObjectForBeanInstance ( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { if (BeanFactoryUtils.isFactoryDereference(name)) { if (beanInstance instanceof NullBean) { return beanInstance; } if (!(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException (beanName, beanInstance.getClass()); } if (mbd != null ) { mbd.isFactoryBean = true ; } return beanInstance; } if (!(beanInstance instanceof FactoryBean<?> factoryBean)) { return beanInstance; } Object object = null ; if (mbd != null ) { mbd.isFactoryBean = true ; } else { object = getCachedObjectForFactoryBean(beanName); } if (object == null ) { if (mbd == null && containsBeanDefinition(beanName)) { mbd = getMergedLocalBeanDefinition(beanName); } boolean synthetic = (mbd != null && mbd.isSynthetic()); object = getObjectFromFactoryBean(factoryBean, beanName, !synthetic); } return object; }
然后调用 getObjectFromFactoryBean()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 protected Object getObjectFromFactoryBean (FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { if (factory.isSingleton() && containsSingleton(beanName)) { synchronized (getSingletonMutex()) { Object object = this .factoryBeanObjectCache.get(beanName); if (object == null ) { object = doGetObjectFromFactoryBean(factory, beanName); Object alreadyThere = this .factoryBeanObjectCache.get(beanName); if (alreadyThere != null ) { object = alreadyThere; } else { if (shouldPostProcess) { if (isSingletonCurrentlyInCreation(beanName)) { return object; } beforeSingletonCreation(beanName); try { object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException (beanName, "Post-processing of FactoryBean's singleton object failed" , ex); } finally { afterSingletonCreation(beanName); } } if (containsSingleton(beanName)) { this .factoryBeanObjectCache.put(beanName, object); } } } return object; } } else { Object object = doGetObjectFromFactoryBean(factory, beanName); if (shouldPostProcess) { try { object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException (beanName, "Post-processing of FactoryBean's object failed" , ex); } } return object; } }
概括一下:
如果是单例的,先尝试从 factoryBeanObjectCache
中获取,保证每次获取到的都是同一个对象;如果在缓存中不存在,那么调用 getObject()
方法拿到 Bean,并进行后置处理,最后存储到 factoryBeanObjectCache
中;
如果不是单例、或者在 beanName
在 singletonObjects
中不存在,每次调用 getObject()
方法拿到新的 Bean,同样进行后置处理。
13. 废弃 Bean
13.1 拓展点的作用
废弃 Bean,即:DisposableBean
,它并非 SpringBoot 提供,是在 Spring 中就存在的:
1 2 3 public interface DisposableBean { void destroy () throws Exception; }
接口内部只有一个无参无返回值的 destroy()
方法,为 Spring Bean 提供了一种释放资源的方式,能够在 Spring 容器关闭,销毁所有 Bean 时回调。
DisposableBean
接口与 InitializingBean
接口有些类似,但触发时机不同。
13.2 使用方式
实现 DisposableBean
接口并重写 destroy()
方法,将实现类交由 Spring 管理,还提供 ApplicationRunner
的实现类,作为对比:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 @Component static class MyRunner implements ApplicationRunner { @Override public void run (ApplicationArguments args) throws Exception { System.out.printf("1. [%s]: 执行了 ApplicationRunner 方法\n" , getCurrentThreadName()); } } static class A13DisposableBean implements DisposableBean { @Override public void destroy () { System.out.printf("4. [%s]: 执行了 destroy 方法\n" , getCurrentThreadName()); } @PreDestroy public void preDestroy () { System.out.printf("3. [%s]: 执行了 @preDestroy 方法\n" , getCurrentThreadName()); } public void destroyMethod () { System.out.printf("5. [%s]: 执行了 destroy-method\n" , getCurrentThreadName()); } } @Configuration static class MyConfig { @Bean(destroyMethod = "destroyMethod") public A13DisposableBean a13DisposableBean () { return new A13DisposableBean (); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @SpringBootApplication public class A13ExtensionPoint { @SneakyThrows public static void main (String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A13ExtensionPoint.class); System.out.printf("2. [%s]: main 方法执行完毕,准备关闭容器\n" , getCurrentThreadName()); TimeUnit.SECONDS.sleep(1 ); context.close(); } public static String getCurrentThreadName () { return Thread.currentThread().getName(); } }
1. [main]: 执行了 ApplicationRunner 方法
2. [main]: main 方法执行完毕,准备关闭容器
3. [main]: 执行了 @preDestroy 方法
4. [main]: 执行了 destroy 方法
5. [main]: 执行了 destroy-method
对于 Bean 的初始化来说,有三个类似的拓展点,并 按顺序依次执行:
@PostConstruct
InitializingBean#afterPropertiesSet()
@Bean
注解的 initMethod
属性
而对于 Bean 的销毁来说,也有三个类似的拓展点,也 按顺序依次执行:
@PreDestroy
DisposableBean#destroy()
@Bean
注解的 destroyMethod
属性
调用的线程
destroy()
方法会在 main
线程中被调用。
如果去掉 context.close()
方法,而是手动或者通过 System.exit(0);
关闭程序,销毁方法们 则会在 SpringApplicationShutdownHook
线程中被调用。在这种情况下,运用了多线程技术,异步执行销毁方法,这涉及到 SpringBoot Shutdown Hook,后续另开一文详细分析, 本节依旧以 context.close()
方法为入口进行探索。
13.3 执行
以 context.close()
方法为入口,来到 AbstractApplicationContext#close()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Override public void close () { synchronized (this .startupShutdownMonitor) { doClose(); if (this .shutdownHook != null ) { try { Runtime.getRuntime().removeShutdownHook(this .shutdownHook); } catch (IllegalStateException ex) { } } } }
重点在 doClose()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 protected void doClose () { if (this .active.get() && this .closed.compareAndSet(false , true )) { if (logger.isDebugEnabled()) { logger.debug("Closing " + this ); } try { publishEvent(new ContextClosedEvent (this )); } catch (Throwable ex) { logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent" , ex); } if (this .lifecycleProcessor != null ) { try { this .lifecycleProcessor.onClose(); } catch (Throwable ex) { logger.warn("Exception thrown from LifecycleProcessor on context close" , ex); } } destroyBeans(); closeBeanFactory(); onClose(); resetCommonCaches(); if (this .earlyApplicationListeners != null ) { this .applicationListeners.clear(); this .applicationListeners.addAll(this .earlyApplicationListeners); } this .active.set(false ); } }
其中的 destroyBeans()
方法用于销毁 Spring 容器中缓存的单例,在这个方法前会执行两件应用关闭前的操作,它们都类似一种通知机制,但在使用场景上也有区别:
ContextClosedEvent
是应用级别的事件,监听该事件可以做一些全局性的行为;
Lifecycle
是 Bean 级别的通知,更适用于特定 Bean 的行为。
回到 destroyBeans()
方法:
1 2 3 protected void destroyBeans () { getBeanFactory().destroySingletons(); }
再来到 destroySingletons()
,方法有两个实现,主要的实现是 DefaultSingletonBeanRegistry#destroySingletons()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public void destroySingletons () { if (logger.isTraceEnabled()) { logger.trace("Destroying singletons in " + this ); } synchronized (this .singletonObjects) { this .singletonsCurrentlyInDestruction = true ; } String[] disposableBeanNames; synchronized (this .disposableBeans) { disposableBeanNames = StringUtils.toStringArray(this .disposableBeans.keySet()); } for (int i = disposableBeanNames.length - 1 ; i >= 0 ; i--) { destroySingleton(disposableBeanNames[i]); } this .containedBeanMap.clear(); this .dependentBeanMap.clear(); this .dependenciesForBeanMap.clear(); clearSingletonCache(); }
最后几步清除了当前类中用到的一些缓存包括:
containedBeanMap
dependentBeanMap
dependenciesForBeanMap
插播一下:几个 Map
的含义
对于 dependentBeanMap
与 dependenciesForBeanMap
来说:
1 2 3 4 5 private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap <>(64 );private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap <>(64 );
dependentBeanMap
:Bean 名称和所有依赖于它的 Bean 的名称的映射关系
dependenciesForBeanMap
:Bean 名称和它依赖的 Bean 的名称的映射关系
flowchart TD
1("A")
2("B")
3("C")
1 --> 2
1 --> 3
在上图中,A 依赖了 B(A --> B
),A 依赖了 C(A --> C
),则:
dependentBeanMap
:<B, [A]>
和 <C, [A]>
dependenciesForBeanMap
:<A, [B, C]>
至于 containedBeanMap
:
1 2 private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap <>(16 );
它表示 Bean 名称与它包含的 Bean 的名称的映射关系。这似乎与 dependenciesForBeanMap
很类似,也确实很类似,但它是在 XML 配置中使用的,在当前流行基于注解的 Spring 配置的环境下,它的使用场景越来越小。比如:
1 2 3 4 5 6 7 8 9 public class Foo { private Bar bar; public Foo (Bar bar) { this .bar = bar; } } public class Bar {}
Foo
类中依赖了 Bar
,那么基于 XML 的配置有:
1 2 3 4 5 <bean id ="foo" class ="com.example.demo.Foo" > <constructor-arg > <bean class ="com.example.demo.Bar" /> </constructor-arg > </bean >
这是不是就相当于 Foo
包含了 Bar
?这仅供了解,现在几乎没有使用场景。
再插播下:disposableBeans
的初始化
disposableBeans
的初始化是在熟悉的 doCreateBean()
方法中最后完成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 protected Object doCreateBean (String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException ( mbd.getResourceDescription(), beanName, "Invalid destruction signature" , ex); } return exposedObject; }
回到主线
查看 destroySingleton()
方法,如何根据 Bean 的 name 来进行销毁:
1 2 3 4 5 6 7 8 9 10 11 12 13 public void destroySingleton (String beanName) { removeSingleton(beanName); DisposableBean disposableBean; synchronized (this .disposableBeans) { disposableBean = this .disposableBeans.remove(beanName); } destroyBean(beanName, disposableBean); }
removeSingleton()
方法从多个 Map
中移除即可,DisposableBean
已经被缓存了一份,先删除再销毁也没啥问题。
销毁的主要逻辑在 destroyBean()
中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 protected void destroyBean (String beanName, @Nullable DisposableBean bean) { Set<String> dependencies; synchronized (this .dependentBeanMap) { dependencies = this .dependentBeanMap.remove(beanName); } if (dependencies != null ) { for (String dependentBeanName : dependencies) { destroySingleton(dependentBeanName); } } if (bean != null ) { try { bean.destroy(); } catch (Throwable ex) { } } Set<String> containedBeans; synchronized (this .containedBeanMap) { containedBeans = this .containedBeanMap.remove(beanName); } if (containedBeans != null ) { for (String containedBeanName : containedBeans) { destroySingleton(containedBeanName); } } synchronized (this .dependentBeanMap) { for (Iterator<Map.Entry<String, Set<String>>> it = this .dependentBeanMap.entrySet().iterator(); it.hasNext();) { Map.Entry<String, Set<String>> entry = it.next(); Set<String> dependenciesToClean = entry.getValue(); dependenciesToClean.remove(beanName); if (dependenciesToClean.isEmpty()) { it.remove(); } } } this .dependenciesForBeanMap.remove(beanName); }
逻辑分为几步:
首先在 dependentBeanMap
中移除 (一个递归操作) 其他 Bean 对目标 Bean 的依赖,依赖的都没了,那它自己也该被销毁;
执行目标 Bean 的销毁(DisposableBean
的执行时机);
在 containedBeanMap
中移除当前 Bean 包含的 Bean;
从其他 Bean 的依赖项中删除销毁的目标 Bean;
最终删除目标 Bean 对其他 Bean 的依赖关系信息。
14. 智能生命周期
14.1 拓展点的作用
智能生命周期,即:SmartLifecycle
,它并非 SpringBoot 提供,是在 Spring 中就存在的:
classDiagram
direction BT
class Lifecycle {
<<Interface>>
+ stop() void
+ isRunning() boolean
+ start() void
}
class Phased {
<<Interface>>
+ getPhase() int
}
class SmartLifecycle {
<<Interface>>
+ getPhase() int
+ stop(Runnable) void
+ isAutoStartup() boolean
}
SmartLifecycle --> Lifecycle
SmartLifecycle --> Phased
它继承了 Lifecycle
接口和 Phased
接口,一共定义了六个方法:
方法
作用
start()
Spring 刷新上下文的最后一步,Bean 初始化完成后,执行该方法
stop()
Spring 容器关闭时,执行 Lifecycle
的 stop()
方法
isRunning()
判断当前组件是否在运行
getPhase()
存在多个组件时的回调顺序。值越大,越先执行 start()
方法,越晚执行 stop()
方法
isAutoStartup()
判断是否需要执行 start()
方法,返回 true
才执行
stop(Runnable callback)
Spring 容器关闭时,执行 SmartLifecycle
的 stop(Runnable callback)
方法
对于 SmartLifecycle
来说,在容器关闭时,只会 执行它的 stop(Runnable callback)
方法,不会 执行 stop()
方法。
和 DisposableBean
的 destroy()
方法类似,两个 stop()
方法也与 SpringBoot Shutdown Hook 有关。
14.2 Lifecycle
先从 Lifecycle
入手,它提供了三个抽象方法,重写它们并将实现类交由 Spring 管理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @Component static class MyLifecycle implements Lifecycle { private boolean running = true ; @Override public void start () { System.out.printf("[%s]: lifecycle start\n" , getCurrentThreadName()); } @Override public void stop () { System.out.printf("[%s]: lifecycle stop\n" , getCurrentThreadName()); this .running = false ; } @Override public boolean isRunning () { return this .running; } } public static String getCurrentThreadName () { return Thread.currentThread().getName(); }
直接使用 close()
方法关闭 Spring 容器:
1 2 3 4 5 6 7 8 9 @SpringBootApplication public class A15ExtensionPoint { public static void main (String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A15ExtensionPoint.class); context.close(); } }
[main]: lifecycle stop
在容器启动时并没有执行 start()
方法,但在容器关闭时执行了 close()
方法。
这是因为在 SpringBoot 应用启动过程中并没有 显式 调用 AbstractApplicationContext#start()
,而是调用 AbstractApplicationContext#finishRefresh()
,但在应用退出(Spring 容器关闭)时会执行 Lifecycle#isRunning()
方法判断组件是否正在运行,如果返回 true
则会调用 Lifecycle#stop()
方法,这些在后续源码分析中介绍。
那么问题来了,要显式调用 AbstractApplicationContext#start()
才会执行 Lifecycle
的 start()
方法,但 SpringBoot 在容器启动时并不会显式调用,那 start()
方法岂不是很尴尬?
此时需要一个更“智能”的类,也就是 SmartLifecycle
。
14.3 SmartLifecycle
它继承了 Lifecycle
和 Phased
,相比于 Lifecycle
,SmartLifecycle
提供了自动执行 start()
方法的能力,并且具有执行编排(存在多个 SmartLifecycle
时能够控制对应方法的执行顺序)的能力:
重写 isAutoStartup()
方法,并返回 true
,使得在容器刷新完成后 自动 执行 start()
方法;
重写 getPhase()
方法,根据返回值的大小编排多个 SmartLifecycle
的执行顺序,值越大,越先执行 start()
方法,越靠后执行 stop()
方法;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 @Component static class FirstSmartLifecycle implements SmartLifecycle { private boolean running = false ; @Override public void start () { System.out.printf("[%s]: first start\n" , getCurrentThreadName()); this .running = true ; } @Override public void stop () { System.out.printf("[%s]: first stop\n" , getCurrentThreadName()); this .running = false ; } @Override public boolean isRunning () { return this .running; } @Override public void stop (Runnable callback) { System.out.printf("[%s]: first stop(Runnable)\n" , getCurrentThreadName()); callback.run(); this .running = false ; } @Override public int getPhase () { return 1 ; } } @Component static class SecondSmartLifecycle implements SmartLifecycle { private boolean running = false ; @Override public void start () { System.out.printf("[%s]: second start\n" , getCurrentThreadName()); this .running = true ; } @Override public void stop () { System.out.printf("[%s]: second stop\n" , getCurrentThreadName()); this .running = false ; } @Override public boolean isRunning () { return this .running; } @Override public void stop (Runnable callback) { System.out.printf("[%s]: second stop(Runnable)\n" , getCurrentThreadName()); callback.run(); this .running = false ; } @Override public int getPhase () { return 2 ; } }
[main]: first start
[main]: second start
[main]: second stop(Runnable)
[main]: first stop(Runnable)
对于 SmartLifecycle
来说,在容器关闭时不会执行父类 Lifecycle
的 stop()
方法,而是执行自身提供的 stop(Runnable callback)
方法。
14.4 容器启动时
在熟悉的 AbstractApplicationContext#refresh()
方法中,所有单例 Bean 都实例化完成后,会执行 finishRefresh()
方法,源码中的注释表明这是 refresh 的最后一步,发布相关的事件:
进入该方法内部:
1 2 3 4 5 6 7 8 9 10 11 12 13 protected void finishRefresh () { clearResourceCaches(); initLifecycleProcessor(); getLifecycleProcessor().onRefresh(); publishEvent(new ContextRefreshedEvent (this )); }
重点放在中间的两步,它们一个用于初始化 Lifecycle
处理器,一个用于调用 Lifecycle
处理器的 onRefresh()
方法。
initLifecycleProcessor()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Nullable private LifecycleProcessor lifecycleProcessor;public static final String LIFECYCLE_PROCESSOR_BEAN_NAME = "lifecycleProcessor" ;protected void initLifecycleProcessor () { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) { this .lifecycleProcessor = beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class); } else { DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor (); defaultProcessor.setBeanFactory(beanFactory); this .lifecycleProcessor = defaultProcessor; beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this .lifecycleProcessor); } }
方法内部逻辑比较简单,首先获取 BeanFactory
,判断容器中是否存在名为 lifecycleProcessor
的 Bean:
如果存在,就获取这个 Bean,并将其赋值给成员变量 this.lifecycleProcessor
;
如果不存在,自行实例化 DefaultLifecycleProcessor
,将其赋值给成员变量 this.lifecycleProcessor
,然后再把这个对象注册到 Spring 容器中。
现在已经拿到了 LifecycleProcessor
,接下来就是调用它的 onRefresh()
方法了。
getLifecycleProcessor().onRefresh()
来到 DefaultLifecycleProcessor#onRefresh()
方法:
1 2 3 4 5 @Override public void onRefresh () { startBeans(true ); this .running = true ; }
再进入 startBeans()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 private void startBeans (boolean autoStartupOnly) { Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans(); Map<Integer, LifecycleGroup> phases = new TreeMap <>(); lifecycleBeans.forEach((beanName, bean) -> { if (!autoStartupOnly || (bean instanceof SmartLifecycle smartLifecycle && smartLifecycle.isAutoStartup())) { int phase = getPhase(bean); phases.computeIfAbsent( phase, p -> new LifecycleGroup (phase, this .timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly) ).add(beanName, bean); } }); if (!phases.isEmpty()) { phases.values().forEach(LifecycleGroup::start); } }
获取到所有 Lifecycle
后,对它们进行过滤并分组,然后执行它们的 start()
方法。执行逻辑由 LifecycleGroup#start()
完成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public void start () { if (this .members.isEmpty()) { return ; } if (logger.isDebugEnabled()) { logger.debug("Starting beans in phase " + this .phase); } Collections.sort(this .members); for (LifecycleGroupMember member : this .members) { doStart(this .lifecycleBeans, member.name, this .autoStartupOnly); } }
对每组 Lifecycle
按 phased
值升序排序,排序完成后依次调用 doStart()
方法。Spring 中喜欢将真正执行逻辑的方法名以 do
开头,可以断定此处的 doStart()
方法是真的用来执行 Lifecycle#start()
方法的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 private void doStart (Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) { Lifecycle bean = lifecycleBeans.remove(beanName); if (bean != null && bean != this ) { String[] dependenciesForBean = getBeanFactory().getDependenciesForBean(beanName); for (String dependency : dependenciesForBean) { doStart(lifecycleBeans, dependency, autoStartupOnly); } if (!bean.isRunning() && (!autoStartupOnly || !(bean instanceof SmartLifecycle smartLifecycle) || smartLifecycle.isAutoStartup())) { try { bean.start(); } catch (Throwable ex) { } } } }
先获取 Bean 的依赖项,递归调用执行依赖项的 start()
方法,之后才执行 start()
方法。
14.5 容器关闭时
在分析 DisposableBean
的执行逻辑时,调用的 AbstractApplicationContext#close()
方法又会调用 AbstractApplicationContext#doClose()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 protected void doClose () { if (this .active.get() && this .closed.compareAndSet(false , true )) { if (this .lifecycleProcessor != null ) { try { this .lifecycleProcessor.onClose(); } catch (Throwable ex) { } } } }
内部会调用 this.lifecycleProcessor.onClose()
,通过前文的分析可知,这里调用的是 DefaultLifecycleProcessor
的 onClose()
方法:
1 2 3 4 5 @Override public void onClose () { stopBeans(); this .running = false ; }
再进入 stopBeans()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private void stopBeans () { Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans(); Map<Integer, LifecycleGroup> phases = new HashMap <>(); lifecycleBeans.forEach((beanName, bean) -> { int shutdownPhase = getPhase(bean); LifecycleGroup group = phases.get(shutdownPhase); if (group == null ) { group = new LifecycleGroup (shutdownPhase, this .timeoutPerShutdownPhase, lifecycleBeans, false ); phases.put(shutdownPhase, group); } group.add(beanName, bean); }); if (!phases.isEmpty()) { List<Integer> keys = new ArrayList <>(phases.keySet()); keys.sort(Collections.reverseOrder()); for (Integer key : keys) { phases.get(key).stop(); } } }
这里和前文的 startBeans(boolean autoStartupOnly)
方法很类似,对容器中的所有 Lifecycle
按 phased
值进行分组,逆序排序后一一执行。
说句题外话:stopBeans()
的实现其实可以 startBeans()
保持一致,即引入 TreeMap
,更简单地使用 Map#computeIfAbsent()
实现分组,但我发现这点并想向 Spring 提交 PR 时,却发现在 4 月已经存在被合并的相关 PR ,可惜向 Spring 提交 PR 的计划泡汤了。本文使用的 Spring 版本是此时最新的 6.0.12,不知道修改会在哪个版本上生效呢?👻
回到正题,继续看 LifecycleGroup#stop()
里的逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public void stop () { if (this .members.isEmpty()) { return ; } this .members.sort(Collections.reverseOrder()); CountDownLatch latch = new CountDownLatch (this .smartMemberCount); Set<String> countDownBeanNames = Collections.synchronizedSet(new LinkedHashSet <>()); Set<String> lifecycleBeanNames = new HashSet <>(this .lifecycleBeans.keySet()); for (LifecycleGroupMember member : this .members) { if (lifecycleBeanNames.contains(member.name)) { doStop(this .lifecycleBeans, member.name, latch, countDownBeanNames); } else if (member.bean instanceof SmartLifecycle) { latch.countDown(); } } try { latch.await(this .timeout, TimeUnit.MILLISECONDS); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } }
这个方法内部有两个要点:
引入 CountDownLatch
;
引入 lifecycleBeanNames
,并在遍历每个 Lifecycle
时,执行 contains()
方法。
为了提高执行效率,在实现 SmartLifecycle
接口重写 stop(Runnable callback)
方法时,可以开一个线程中执行内部逻辑,使多个 SmartLifecycle
的 stop()
方法并行执行。
当前线程必须等待所有执行 stop()
方法的线程执行完才继续向下执行,因此引入了 CountDownLatch
。
假设有两个 Bean 分别叫 A 和 B,A 依赖了 B,但 A 的 phased
小于 B,因此会先执行 B 的 stop()
方法。在执行了 B 的 stop()
方法时,发现 A 依赖了它,于是会更先一步执行 A 的 stop()
方法,之后再执行 B 的 stop()
方法。等到 B 的 stop()
执行完,按照 phased
的大小,接下来应该执行 A 的 stop()
方法,但由于 A 的 stop()
方法在先前已经执行过了,再来一遍肯定是不合适的,因此引入 lifecycleBeanNames
判断 A 不在该集合中,那么直接执行 CountDownLatch#countDown()
即可。这里涉及到 doStop()
方法的分析,它内部有什么奥秘呢?
与 doStart()
方法类似,doStop()
也是用来真正执行 Lifecycle#stop()
的,其处理逻辑也和 doStart()
类似:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 private void doStop (Map<String, ? extends Lifecycle> lifecycleBeans, final String beanName, final CountDownLatch latch, final Set<String> countDownBeanNames) { Lifecycle bean = lifecycleBeans.remove(beanName); if (bean != null ) { String[] dependentBeans = getBeanFactory().getDependentBeans(beanName); for (String dependentBean : dependentBeans) { doStop(lifecycleBeans, dependentBean, latch, countDownBeanNames); } try { if (bean.isRunning()) { if (bean instanceof SmartLifecycle smartLifecycle) { countDownBeanNames.add(beanName); smartLifecycle.stop(() -> { latch.countDown(); countDownBeanNames.remove(beanName); }); } else { bean.stop(); } } else if (bean instanceof SmartLifecycle) { latch.countDown(); } } catch (Throwable ex) { } } }
实现还是比较简单,但有一个重要的注意点:如果 Bean 的类型是 SmartLifecycle
时,传入了一个 Runnable
,并且 在 Runnable
中执行了 CountDownLatch#countDown()
,这要求 在重写 stop(Runnable callback)
方法时一定要在内部调用 callback.run()
,否则 CountDownLatch
的计数减不下去,就会在达到设置的超时时间前一直阻塞线程。
15. Spring 生命周期
Spring 的生命周期,其实指的是 Spring Bean 的生命周期,Bean 的生命周期概括起来共三步:
将 Java 类抽象为 BeanDefinition
对象;
根据 BeanDefinition
对象完成 Bean 的实例化、初始化和其他拓展操作;
使用 Spring 管理的 Bean,直至销毁。
前文花了大量篇幅介绍 SpringBoot 的拓展点,而这些拓展点是贯穿 Bean 的生命周期的,按照执行先后可以绘制出包含大多数拓展点的执行流程图:
16. 总结
本文介绍了 BeanFactory 周围、Bean 实例化周围、Bean 初始化周围共十多个拓展点,每个拓展点分为作用、使用方式、实例化(注册)、执行、内置实现等小节,并结合源码进行讲解,最终将这些拓展点汇总指向 Spring Bean 的生命周期。
行文过程中留下了一些坑:
这些内容慢慢来吧,今年应该能够整完?! 🤔