赞
踩
Spring Bean
的生命周期对Spring框架原理理解的重要性,所以接下来我们就来分析一下Bean
生命周期的整体流程。首先Bean
就是一些Java
对象,只不过这些Bean
不是我们主动new出来的,而是交个Spring IOC
容器创建并管理的,因此Bean
的生命周期受Spring IOC
容器控制,Bean
生命周期大致分为以下几个阶段:
Bean
的实例化(Instantiation
):Spring
框架会取出BeanDefinition
的信息进行判断当前Bean
的范围是否是singleton
的,是否不是延迟加载的,是否不是FactoryBean
等,最终将一个普通的singleton
的Bean通过反射进行实例化Bean
的属性赋值(Populate
):Bean
实例化之后还仅仅是个"半成品",还需要对Bean实例的属性进行填充,Bean
的属性赋值就是指 Spring
容器根据BeanDefinition
中属性配置的属性值注入到 Bean 对象中的过程。Bean
的初始化(Initialization
):对Bean
实例的属性进行填充完之后还需要执行一些Aware
接口方法、执行BeanPostProcessor
方法、执行InitializingBean
接口的初始化方法、执行自定义初始化init方法等。该阶段是Spring
最具技术含量和复杂度的阶段,并且Spring
高频面试题Bean
的循环引用问题也是在这个阶段体现的;Bean
的使用阶段:经过初始化阶段,Bean
就成为了一个完整的Spring Bean
,被存储到单例池singletonObjects
中去了,即完成了Spring Bean的整个生命周期,接下来Bean
就可以被随心所欲地使用了。Bean
的销毁(Destruction
):Bean
的销毁是指 Spring
容器在关闭时,执行一些清理操作的过程。在 Spring
容器中, Bean
的销毁方式有两种:销毁方法destroy-method
和 DisposableBean
接口。我们在spring
的BeanFactory
工厂列举了很多接口,代表着bean
的生命周期,我们主要记住的是圈红线圈出来的接口, 再结合spring
的源码来看这些接口主要是在哪里调用的
AbstractAutowireCapableBeanFactory
类的doCreateBean
方法是创建bean
的开始,我们可以看到首先需要实例化这个bean
,也就是在堆中开辟一块内存空间给这个对象,createBeanInstance
方法里面逻辑大概就是采用反射生成实例对象,进行到这里表示对象还并未进行属性的填充,也就是@Autowired
注解的属性还未得到注入
Spring
将管理的一个个的依赖对象称之为Bean
,这从xml
配置文件中也可以看出。
Spring IOC
容器就好像一个生产产品的流水线上的机器,Spring
创建出来的Bean
就好像是流水线的终点生产出来的一个个精美绝伦的产品。既然是机器,总要先启动,Spring也不例外。因此Bean的一生从总体上来说可以分为两个阶段:
容器的启动阶段做了很多的预热工作,为后面Bean
的实例化做好了充分的准备,我们首先看一下容器的启动阶段都做了哪些预热工作。
我们说Spring IOC
容器将对象实例的创建与对象实例的使用分离,我们的业务中需要依赖哪个对象不再依靠我们自己手动创建,只要向Spring
要,Spring
就会以注入的方式交给我们需要的依赖对象。
既然我们将对象创建的任务交给了Spring
,那么Spring
就需要知道创建一个对象所需要的一些必要的信息。而这些必要的信息可以是Spring
过去支持最完善的xml
配置文件,或者是其他形式的例如properties
的磁盘文件,也可以是现在主流的注解,甚至是直接的代码硬编码。总之,这些创建对象所需要的必要信息称为配置元信息。
<bean id="role" class="com.wbg.springxmlbean.entity.Role">
<!-- property元素是定义类的属性,name属性定义的是属性名称 value是值
相当于:
Role role=new Role();
role.setId(1);
role.setRoleName("高级工程师");
role.setNote("重要人员");-->
<property name="id" value="1"/>
<property name="roleName" value="高级工程师"/>
<property name="note" value="重要人员"/>
</bean>
我们大家都知道,在Java
世界中,万物皆对象,散落于程序代码各处的注解以及保存在磁盘上的xml或者其他文件等等配置元信息,在内存中总要以一种对象的形式表示,就好比我们活生生的人对应到Java
世界中就是一个Person
类。
而Spring
选择在内存中表示这些配置元信息的方式就是BeanDefination
,这里我们只是需要知道配置元信息被加载到内存之后是以BeanDefination
的形存在的
大家肯定很好奇,我们是看得懂Spring
中xml
配置文件中一个个的Bean
定义,但是Spring
是如何看懂这些配置元信息的呢?这个就要靠我们的BeanDefinationReader
了。
不同的BeanDefinationReader
就像葫芦兄弟一样,各自拥有各自的本领。如果我们要读取xml
配置元信息,那么可以使用XmlBeanDefinationReader
。如果我们要读取properties
配置文件,那么可以使用PropertiesBeanDefinitionReader
加载。而如果我们要读取注解配置元信息,那么可以使用 AnnotatedBeanDefinitionReader
加载。我们也可以很方便的自定义BeanDefinationReader
来自己控制配置元信息的加载。假如我们的配置元信息现有的不能满足,那么我们可以自定义From BeanDefinationReader
总的来说,BeanDefinationReader
的作用就是加载配置元信息,并将其转化为内存形式的BeanDefination
,存在某一个地方
执行到这里,总算不遗余力的将存在于各处的配置元信息加载到内存,并转化为BeanDefination
的形式,这样我们需要创建某一个对象实例的时候,找到相应的BeanDefination
然后创建对象即可。那么我们需要某一个对象的时候,去哪里找到对应的BeanDefination
呢?
这种通过Bean
定义的id
找到对象的BeanDefination
的对应关系或者说映射关系又是如何保存的呢?这就引出了BeanDefinationRegistry
了。
Spring
通过BeanDefinationReader
将配置元信息加载到内存生成相应的BeanDefination
之后,就将其注册到BeanDefinationRegistry
中,BeanDefinationRegistry
就是一个存放BeanDefination
的大篮子,它也是一种键值对的形式,通过特定的Bean
定义的id
,映射到相应的BeanDefination
。
BeanFactoryPostProcessor
是容器启动阶段Spring
提供的一个扩展点,主要负责对注册到BeanDefinationRegistry
中的一个个的BeanDefination
进行一定程度上的修改与替换。
例如我们的配置元信息中有些可能会修改的配置信息散落到各处,不够灵活,修改相应配置的时候比较麻烦,这时我们可以使用占位符的方式来配置。例如配置Jdbc的DataSource连接的时候可以这样配置:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="maxIdle" value="${jdbc.maxIdle}"></property> <property name="maxActive" value="${jdbc.maxActive}"></property> <property name="maxWait" value="${jdbc.maxWait}"></property> <property name="minIdle" value="${jdbc.minIdle}"></property> <property name="driverClassName" value="${jdbc.driverClassName}"> </property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean>
BeanFactoryPostProcessor
就会对注册到BeanDefinationRegistry
中的BeanDefination
做最后的修改,替换$
占位符为配置文件中的真实的数据。
至此,整个容器启动阶段就算完成了,容器的启动阶段的最终产物就是注册到BeanDefinationRegistry
中的一个个BeanDefination
了,这就是Spring为
Bean实例化所做的预热的工作。让我们再通过一张图的形式回顾一下容器启动阶段都是搞了什么事吧。
需要指出,容器启动阶段与Bean
实例化阶段存在多少时间差,如果我们选择懒加载的方式,那么直到我们伸手向Spring
要依赖对象实例之前,其都是以BeanDefinationRegistry
中的一个个的BeanDefination
的形式存在,也就是Spring
只有在我们需要依赖对象的时候才开启相应对象的实例化阶段。
而如果我们不是选择懒加载的方式,容器启动阶段完成之后,将立即启动Bean
实例化阶段,通过隐式的调用所有依赖对象的getBean
方法来实例化所有配置的Bean
并保存起来。
对象的创建采用了策略模式
,借助我们前面BeanDefinationRegistry
中的BeanDefination
,我们可以使用反射的方式创建对象,也可以使用CGlib
字节码生成创建对象。
同时我们可以灵活的配置来告诉Spring
采用什么样的策略创建指定的依赖对象。Spring中Bean
的创建是策略设计模式的经典应用。这个时候,内存中应该已经有一个我们想要的具体的依赖对象的实例了,但是故事的发展还没有我们想象中的那么简单。
Spring
中的Bean
并不是以一个个的本来模样存在的,由于Spring IOC
容器中要管理多种类型的对象,因此为了统一对不同类型对象的访问,Spring
给所有创建的Bean
实例穿上了一层外套,这个外套就是BeanWrapper
BeanWrapper
实际上是对反射相关API
的简单封装,使得上层使用反射完成相关的业务逻辑大大的简化,我们要获取某个对象的属性,调用某个对象的方法,现在不需要在写繁杂的反射API
了以及处理一堆麻烦的异常,直接通过BeanWrapper
就可以完成相关操作
上一步包裹在BeanWrapper
中的对象还是一个少不经事的孩子,需要为其设置属性以及依赖对象
基本类型属性
: 如果配置元信息中有配置,那么将直接使用配置元信息中的设置值赋值即可,即使基本类型的属性没有设置值,那么得益于JVM对象实例化过程,属性依然可以被赋予默认的初始化零值。引用类型属性
: Spring
会将所有已经创建好的对象放入一个Map
结构中,此时Spring
会检查所依赖的对象是否已经被纳入容器的管理范围之内,也就是Map
中是否已经有对应对象的实例了。如果有,那么直接注入,如果没有,那么Spring
会暂时放下该对象的实例化过程,转而先去实例化依赖对象,再回过头来完成该对象的实例化过程我们可以看到第二步就是填充bean
的成员属性,populateBean
方法里面的逻辑大致就是对使用到了注入属性的注解就会进行注入,如果在注入的过程发现注入的对象还没生成,则会跑去生产要注入的对象,第三步就是调用initializeBean
方法初始化bean
,也就是调用我们上述所提到的接口
Bean初始化阶段中重要接口
可以看到initializeBean
方法中,首先调用的是使用的Aware
接口的方法,我们具体看一下invokeAwareMethods
方法中会调用Aware
接口的那些方法
我们可以知道如果我们实现了BeanNameAware
,BeanClassLoaderAware
,BeanFactoryAware
三个Aware
接口的话,会依次调用setBeanName(), setBeanClassLoader(), setBeanFactory()
方法,再看applyBeanPostProcessorsBeforeInitialization
源码
发现会如果有类实现了BeanPostProcessor
接口,就会执行postProcessBeforeInitialization
方法,这里需要注意的是:如果多个类实现BeanPostProcessor
接口,那么多个实现类都会执行postProcessBeforeInitialization
方法,可以看到是for
循环依次执行的,还有一个注意的点就是如果加载A类到spring
容器中,A类也重写了BeanPostProcessor
接口的postProcessBeforeInitialization
方法,这时要注意A类的postProcessBeforeInitialization
方法并不会得到执行,因为A类还未加载完成,还未完全放到spring
的singletonObjects
一级缓存中。
再看一个注意的点
可以看到ApplicationContextAwareProcessor
也实现了BeanPostProcessor
接口,重写了postProcessBeforeInitialization
方法,方法里面并调用了invokeAwareInterfaces
方法,而invokeAwareInterfaces
方法也写着如果实现了众多的Aware
接口,则会依次执行相应的方法,值得注意的是ApplicationContextAware
接口的setApplicationContext
方法,再看一下invokeInitMethods
源码
发现如果实现了InitializingBean
接口,重写了afterPropertiesSet
方法,则会调用afterPropertiesSet
方法,最后还会调用是否指定了init-method
,可以通过标签,或者@Bean
注解的initMethod
指定,最后再看一张applyBeanPostProcessorsAfterInitialization
源码图
发现跟之前的postProcessBeforeInitialization
方法类似,也是循环遍历实现了BeanPostProcessor
的接口实现类,执行postProcessAfterInitialization
方法。整个bean
的生命执行流程就如上面截图所示,哪个接口的方法在哪里被调用,方法的执行流程。
最后,对bean的生命流程进行一个流程图的总结
或者看简单版本:
如果有@PostConstruct
那么初始化顺序为
BeanPostProcessor
的postProcessBeforeInitialization
方法@PostConstruct
的方法InitializingBean
的afterPropertiesSet
方法bean
的指定的初始化方法: init-method
BeanPostProcessor
的postProcessAftrInitialization
方法以下是 spring
容器中 Bean
的生命周期内所有可扩展的点的调用顺序,下面会一个个分析
所属类:org.springframework.context.ApplicationContextInitializer
这是整个spring
容器在刷新之前初始化 ConfigurableApplicationContext
的回调接口,简单来说,就是在容器刷新之前调用此类的initialize
方法。允许被用户自己扩展。用户可以在整个spring
容器还没被初始化之前做一些事情。
可以想到的场景可能为,在最开始激活一些配置,或者利用这时候class
还没被类加载器加载的时机,进行动态字节码注入等操作。
扩展方式为:
public class TestApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("[ApplicationContextInitializer]");
}
}
因为这时候spring
容器还没被初始化,所以想要扩展的生效,有以下三种方式:
SpringBoot
启动类中用springApplication.addInitializers(new TestApplicationContextInitializer())
语句加入application.properties
中添加:context.initializer.classes=com.example.demo.TestApplicationContextInitializer
context:
initializer:
classes: com.example.demo.TestApplicationContextInitializer
Spring SPI
扩展,在 META-INF/services
下的spring.factories
中加入org.springframework.context.ApplicationContextInitializer=com.example.demo.TestApplicationContextInitializer
所属类:org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor
这个接口在读取项目中的 beanDefinition
之后执行,提供一个补充的扩展点
使用场景:可以在这里动态注册自己的 beanDefinition
,可以加载classpath之外的bean
扩展方式为:
public class TestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("[BeanDefinitionRegistryPostProcessor] postProcessBeanDefinitionRegistry");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("[BeanDefinitionRegistryPostProcessor] postProcessBeanFactory");
}
}
所属类:org.springframework.beans.factory.config.BeanFactoryPostProcessor
这个接口是 beanFactory
的扩展接口,调用时机在 spring
在读取beanDefinition
信息之后,实例化bean之前。
在这个时机,用户可以通过实现这个扩展接口来自行处理一些东西,比如修改已经注册的beanDefinition
的元信息。
扩展方式为:
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("[BeanFactoryPostProcessor]");
}
}
所属类:org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor
该接口继承了 BeanPostProcess
接口,区别如下:
BeanPostProcess
接口只在bean的初始化阶段
进行扩展(注入spring上下文前后)InstantiationAwareBeanPostProcessor
接口在此基础上增加了3个方法,把可扩展的范围增加了实例化
阶段和属性注入
阶段。该类主要的扩展点有以下5个方法,主要在bean生命周期的两大阶段:实例化阶段和初始化阶段,下面一起进行说明,按调用顺序为:
postProcessBeforeInstantiation
:实例化bean之前,相当于new这个bean之前postProcessAfterInstantiation
:实例化bean之后,相当于new这个bean之后postProcessPropertyValues
:bean已经实例化完成,在属性注入时阶段触发,@Autowired,@Resource等注解原理基于此方法实现postProcessBeforeInitialization
:初始化bean之前,相当于把bean注入spring上下文之前postProcessAfterInitialization
:初始化bean之后,相当于把bean注入spring上下文之后使用场景:这个扩展点非常有用 ,无论是写中间件和业务中,都能利用这个特性。比如对实现了某一类接口的bean在各个生命期间进行收集,或者对某个类型的bean进行统一的设值等等。
扩展方式为:
public class TestInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("[TestInstantiationAwareBeanPostProcessor] before initialization " + beanName); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("[TestInstantiationAwareBeanPostProcessor] after initialization " + beanName); return bean; } @Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { System.out.println("[TestInstantiationAwareBeanPostProcessor] before instantiation " + beanName); return null; } @Override public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { System.out.println("[TestInstantiationAwareBeanPostProcessor] after instantiation " + beanName); return true; } @Override public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { System.out.println("[TestInstantiationAwareBeanPostProcessor] postProcessPropertyValues " + beanName); return pvs; }
所属类:org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor
该扩展接口有3个触发点方法:
predictBeanType
:该触发点发生在postProcessBeforeInstantiation
之前(在图上并没有标明,因为一般不太需要扩展这个点),这个方法用于预测Bean
的类型,返回第一个预测成功的Class类型,如果不能预测返回null;当你调用BeanFactory.getType(name)时当通过bean的名字无法得到bean类型信息时就调用该回调方法来决定类型信息。determineCandidateConstructors
:该触发点发生在postProcessBeforeInstantiation
之后,用于确定该bean的构造函数之用,返回的是该bean的所有构造函数列表。用户可以扩展这个点,来自定义选择相应的构造器来实例化这个bean。getEarlyBeanReference
:该触发点发生在postProcessAfterInstantiation
之后,当有循环依赖的场景,当bean实例化好之后,为了防止有循环依赖,会提前暴露回调方法,用于bean实例化的后置处理。这个方法就是在提前暴露的回调方法中触发。扩展方式为:
public class TestSmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor { @Override public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException { System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] predictBeanType " + beanName); return beanClass; } @Override public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException { System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] determineCandidateConstructors " + beanName); return null; } @Override public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException { System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] getEarlyBeanReference " + beanName); return bean; } }
所属类:org.springframework.beans.factory.BeanFactoryAware
这个类只有一个触发点,发生在bean的实例化之后,注入属性之前,也就是Setter之前。这个类的扩展点方法为setBeanFactory
,可以拿到BeanFactory这个属性。
使用场景为,你可以在bean实例化之后,但还未初始化之前,拿到 BeanFactory
,在这个时候,可以对每个bean作特殊化的定制。也或者可以把BeanFactory拿到进行缓存,日后使用。
扩展方式为:
public class TestBeanFactoryAware implements BeanFactoryAware {
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("[TestBeanFactoryAware] " + beanFactory.getBean(TestBeanFactoryAware.class).getClass().getSimpleName());
}
}
所属类:org.springframework.context.support.ApplicationContextAwareProcessor
该类本身并没有扩展点,但是该类内部却有6个扩展点可供实现 ,这些类触发的时机在bean实例化之后,初始化之前
可以看到,该类用于执行各种驱动接口,在bean实例化之后,属性填充之后,通过执行以上红框标出的扩展接口,来获取对应容器的变量。所以这里应该来说是有6个扩展点,这里就放一起来说了
EnvironmentAware
:用于获取EnviromentAware
的一个扩展类,这个变量非常有用, 可以获得系统内的所有参数。当然个人认为这个Aware没必要去扩展,因为spring内部都可以通过注入的方式来直接获得。EmbeddedValueResolverAware
:用于获取StringValueResolver
的一个扩展类, StringValueResolver
用于获取基于String类型的properties的变量,一般我们都用@Value
的方式去获取,如果实现了这个Aware接口,把StringValueResolver
缓存起来,通过这个类去获取String类型的变量,效果是一样的。ResourceLoaderAware
:用于获取ResourceLoader
的一个扩展类,ResourceLoader
可以用于获取classpath内所有的资源对象,可以扩展此类来拿到ResourceLoader对象。ApplicationEventPublisherAware
:用于获取ApplicationEventPublisher
的一个扩展类,ApplicationEventPublisher
可以用来发布事件,结合ApplicationListener
来共同使用。这个对象也可以通过spring注入的方式来获得。MessageSourceAware
:用于获取MessageSource
的一个扩展类,MessageSource
主要用来做国际化。ApplicationContextAware
:用来获取ApplicationContext
的一个扩展类,ApplicationContext
应该是很多人非常熟悉的一个类了,就是spring
上下文管理器,可以手动的获取任何在spring
上下文注册的bean,我们经常扩展这个接口来缓存spring
上下文,包装成静态方法。同时ApplicationContext
也实现了BeanFactory
,MessageSource
,ApplicationEventPublisher
等接口,也可以用来做相关接口的事情。所属类:org.springframework.beans.factory.BeanNameAware
可以看到,这个类也是Aware扩展的一种,触发点在bean的初始化之前,也就是postProcessBeforeInitialization
之前,这个类的触发点方法只有一个:setBeanName
使用场景为:用户可以扩展这个点,在初始化bean之前拿到spring容器中注册的的beanName
,来自行修改这个beanName的值。
扩展方式为:
public class NormalBeanA implements BeanNameAware{
public NormalBeanA() {
System.out.println("NormalBean constructor");
}
@Override
public void setBeanName(String name) {
System.out.println("[BeanNameAware] " + name);
}
}
所属类:org.springframework.beans.factory.InitializingBean
这个类,顾名思义,也是用来初始化bean的。InitializingBean
接口为bean
提供了初始化方法的方式,它只包括afterPropertiesSet
方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法。这个扩展点的触发时机在postProcessAfterInitialization
之前。
使用场景:用户实现此接口,来进行系统启动的时候一些业务指标的初始化工作。
扩展方式为:
public class NormalBeanA implements InitializingBean{
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("[InitializingBean] NormalBeanA");
}
}
所属类:org.springframework.beans.factory.FactoryBean
使用场景:用户可以扩展这个类,来为要实例化的bean作一个代理,比如为该对象的所有的方法作一个拦截,在调用前后输出一行log,模仿ProxyFactoryBean的功能。
点击了解 Spring核心之FactoryBean,BeanFactory,ApplicationContext的区别
所属类:org.springframework.beans.factory.SmartInitializingSingleton
这个接口中只有一个方法afterSingletonsInstantiated
,其作用是是 在spring
容器管理的所有单例对象(非懒加载对象)初始化完成之后调用的回调接口。其触发时机为postProcessAfterInitialization
之后。
使用场景:用户可以扩展此接口在对所有单例对象初始化完毕后,做一些后置的业务处理。
扩展方式为:
public class TestSmartInitializingSingleton implements SmartInitializingSingleton {
@Override
public void afterSingletonsInstantiated() {
System.out.println("[TestSmartInitializingSingleton]");
}
}
所属类:org.springframework.boot.CommandLineRunner
这个接口属于 SpringBoot
只有一个方法:run(String... args)
,触发时机为整个项目启动完毕后,自动执行。如果有多个CommandLineRunner
,可以利用@Order
来进行排序。
使用场景:用户扩展此接口,进行启动项目之后一些业务的预处理。
扩展方式为:
public class TestCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("[TestCommandLineRunner]");
}
}
所属类:org.springframework.beans.factory.DisposableBean
这个扩展点也只有一个方法:destroy()
,其触发时机为当此对象销毁时,会自动执行这个方法。比如说运行applicationContext.registerShutdownHook
时,就会触发这个方法。
扩展方式为:
public class NormalBeanA implements DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("[DisposableBean] NormalBeanA");
}
}
所属类:org.springframework.context.ApplicationListener
准确的说,这个应该不算spring&springboot当中的一个扩展点,ApplicationListener
可以监听某个事件的event
,触发时机可以穿插在业务方法执行过程中,用户可以自定义某个业务事件。
但是spring
内部也有一些内置事件,这种事件,可以穿插在启动调用中。我们也可以利用这个特性,来自己做一些内置事件的监听器来达到和前面一些触发点大致相同的事情。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。