1、背景Spring的核心思想就是容器,当容器refresh的时候,内部看上去惊涛骇浪,其实外部则是一片风平浪静,汪洋一片。Springboot更是封装了Spring,遵循约定大于配置,加上主动拆卸的机制。很多时候咱们只有援用了一个依赖,简直是零配置就能实现一个性能的拆卸。我十分喜爱这种主动拆卸的机制,所以在本人开发中间件和公共依赖工具的时候也会用到这个个性。让使用者以最小的代价接入。想要把主动拆卸玩的转,就必须要理解spring对于bean的结构生命周期以及各个扩大接口。当然理解了bean的各个生命周期也能促成咱们加深对spring的了解。业务代码也能正当利用这些扩大点写出更加丑陋的代码。在网上搜寻spring扩大点,发现很少有博文说的很全的,只有一些罕用的扩大点的阐明。所以在这篇文章里,我总结了简直Spring & Springboot所有的扩大接口,以及各个扩大点的应用场景。并且整顿出了一个bean在spring外部从被加载到最初初始化实现所有可扩大点的顺序调用图。从而咱们也能窥探到bean是如何一步步加载到spring容器中的。2.可扩大的接口启动调用程序图以下是我整顿的spring容器中Bean的生命周期内所有可扩大的点的调用程序,上面会一个个剖析

img3.ApplicationContextInitializerorg.springframework.context.ApplicationContextInitializer
这是整个spring容器在刷新之前初始化 ConfigurableApplicationContext 的回调接口,简略来说,就是在容器刷新之前调用此类的 initialize 办法。这个点容许被用户本人扩大。用户能够在整个spring容器还没被初始化之前做一些事件。能够想到的场景可能为,在最开始激活一些配置,或者利用这时候class还没被类加载器加载的机会,进行动静字节码注入等操作。扩大形式为:public class TestApplicationContextInitializer implements ApplicationContextInitializer {

@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {    System.out.println("[ApplicationContextInitializer]");}

}
因为这时候spring容器还没被初始化,所以想要本人的扩大的失效,有以下三种形式:在启动类中用 springApplication.addInitializers(new TestApplicationContextInitializer()) 语句退出配置文件配置 context.initializer.classes=com.example.demo.TestApplicationContextInitializerSpring SPI扩大,在spring.factories中退出 org.springframework.context.ApplicationContextInitializer=com.example.demo.TestApplicationContextInitializer4.BeanDefinitionRegistryPostProcessororg.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor
这个接口在读取我的项目中的 beanDefinition 之后执行,提供一个补充的扩大点应用场景:你能够在这里动静注册本人的 beanDefinition ,能够加载classpath之外的bean扩大形式为:public class TestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {    System.out.println("[BeanDefinitionRegistryPostProcessor] postProcessBeanDefinitionRegistry");}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {    System.out.println("[BeanDefinitionRegistryPostProcessor] postProcessBeanFactory");}

}
5.BeanFactoryPostProcessororg.springframework.beans.factory.config.BeanFactoryPostProcessor
这个接口是 beanFactory 的扩大接口,调用机会在spring在读取 beanDefinition 信息之后,实例化bean之前。在这个机会,用户能够通过实现这个扩大接口来自行处理一些货色,比方批改曾经注册的 beanDefinition 的元信息。扩大形式为:public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {    System.out.println("[BeanFactoryPostProcessor]");}

}
6.InstantiationAwareBeanPostProcessororg.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor
该接口继承了 BeanPostProcess 接口,区别如下:BeanPostProcess 接口只在bean的初始化阶段进行扩大(注入spring上下文前后),而 InstantiationAwareBeanPostProcessor 接口在此基础上减少了3个办法,把可扩大的范畴减少了实例化阶段和属性注入阶段。该类次要的扩大点有以下5个办法,次要在bean生命周期的两大阶段: 实例化阶段 和 初始化阶段 ,上面一起进行阐明,按调用程序为:postProcessBeforeInstantiation :实例化bean之前,相当于new这个bean之前postProcessAfterInstantiation :实例化bean之后,相当于new这个bean之后postProcessPropertyValues @Autowired @ResourcepostProcessBeforeInitialization :初始化bean之前,相当于把bean注入spring上下文之前postProcessAfterInitialization :初始化bean之后,相当于把bean注入spring上下文之后应用场景:这个扩大点十分有用 ,无论是写中间件和业务中,都能利用这个个性。比方对实现了某一类接口的bean在各个生命期间进行收集,或者对某个类型的bean进行对立的设值等等。扩大形式为:public class TestInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {    System.out.println("[TestInstantiationAwareBeanPostProcessor] before initialization " + beanName);    return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {    System.out.println("[TestInstantiationAwareBeanPostProcessor] after initialization " + beanName);    return bean;}@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {    System.out.println("[TestInstantiationAwareBeanPostProcessor] before instantiation " + beanName);    return null;}@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {    System.out.println("[TestInstantiationAwareBeanPostProcessor] after instantiation " + beanName);    return true;}@Overridepublic PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {    System.out.println("[TestInstantiationAwareBeanPostProcessor] postProcessPropertyValues " + beanName);    return pvs;}

7.SmartInstantiationAwareBeanPostProcessororg.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor
该扩大接口有3个触发点办法:predictBeanType postProcessBeforeInstantiation BeanFactory.getType(name)determineCandidateConstructors :该触发点产生在 postProcessBeforeInstantiation 之后,用于确定该bean的构造函数之用,返回的是该bean的所有构造函数列表。用户能够扩大这个点,来自定义抉择相应的结构器来实例化这个bean。getEarlyBeanReference :该触发点产生在 postProcessAfterInstantiation 之后,当有循环依赖的场景,当bean实例化好之后,为了避免有循环依赖,会提前裸露回调办法,用于bean实例化的后置解决。这个办法就是在提前裸露的回调办法中触发。扩大形式为:public class TestSmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {

@Overridepublic Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {    System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] predictBeanType " + beanName);    return beanClass;}@Overridepublic Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {    System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] determineCandidateConstructors " + beanName);    return null;}@Overridepublic Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {    System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] getEarlyBeanReference " + beanName);    return bean;}

}
8.BeanFactoryAwareorg.springframework.beans.factory.BeanFactoryAware
这个类只有一个触发点,产生在bean的实例化之后,注入属性之前,也就是Setter之前。这个类的扩大点办法为 setBeanFactory ,能够拿到 BeanFactory 这个属性。应用场景为,你能够在bean实例化之后,但还未初始化之前,拿到 BeanFactory ,在这个时候,能够对每个bean作特殊化的定制。也或者能够把 BeanFactory 拿到进行缓存,日后应用。扩大形式为:public class TestBeanFactoryAware implements BeanFactoryAware {

@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {    System.out.println("[TestBeanFactoryAware] " + beanFactory.getBean(TestBeanFactoryAware.class).getClass().getSimpleName());}

}
9.ApplicationContextAwareProcessororg.springframework.context.support.ApplicationContextAwareProcessor
该类自身并没有扩大点,然而该类外部却有6个扩大点可供实现 ,这些类触发的机会在bean实例化之后,初始化之前

img2.png能够看到,该类用于执行各种驱动接口,在bean实例化之后,属性填充之后,通过执行以上红框标出的扩大接口,来获取对应容器的变量。 所以这里应该来说是有6个扩大点 ,这里就放一起来说了EnvironmentAware :用于获取 EnviromentAware 的一个扩大类,这个变量十分有用, 能够取得零碎内的所有参数。当然集体认为这个Aware没必要去扩大,因为spring外部都能够通过注入的形式来间接取得。EmbeddedValueResolverAware StringValueResolver StringValueResolver String @Value StringValueResolver StringResourceLoaderAware ResourceLoader ResourceLoader ResourceLoaderApplicationEventPublisherAware ApplicationEventPublisher ApplicationEventPublisher ApplicationListener ApplicationListenerMessageSourceAware MessageSource MessageSourceApplicationContextAware ApplicationContext ApplicationContext ApplicationContext BeanFactory MessageSource ApplicationEventPublisher10.BeanNameAwareorg.springframework.beans.factory.BeanNameAware
能够看到,这个类也是Aware扩大的一种,触发点在bean的初始化之前,也就是 postProcessBeforeInitialization 之前,这个类的触发点办法只有一个: setBeanName应用场景为:用户能够扩大这个点,在初始化bean之前拿到spring容器中注册的的beanName,来自行批改这个beanName的值。扩大形式为:public class NormalBeanA implements BeanNameAware{

public NormalBeanA() {    System.out.println("NormalBean constructor");}@Overridepublic void setBeanName(String name) {    System.out.println("[BeanNameAware] " + name);}

}
11.@PostConstructjavax.annota....PostConstruct
这个并不算一个扩大点,其实就是一个标注。其作用是在bean的初始化阶段,如果对一个办法标注了 @PostConstruct ,会先调用这个办法。这里重点是要关注下这个规范的触发点,这个触发点是在 postProcessBeforeInitialization 之后, InitializingBean.afterPropertiesSet 之前。应用场景:用户能够对某一办法进行标注,来进行初始化某一个属性扩大形式为:public class NormalBeanA {

public NormalBeanA() {    System.out.println("NormalBean constructor");}@PostConstructpublic void init(){    System.out.println("[PostConstruct] NormalBeanA");}

}
12.InitializingBeanorg.springframework.beans.factory.InitializingBean
这个类,顾名思义,也是用来初始化bean的。 InitializingBean 接口为bean提供了初始化办法的形式,它只包含 afterPropertiesSet 办法,但凡继承该接口的类,在初始化bean的时候都会执行该办法。这个扩大点的触发机会在 postProcessAfterInitialization 之前。应用场景:用户实现此接口,来进行系统启动的时候一些业务指标的初始化工作。扩大形式为:public class NormalBeanA implements InitializingBean{

@Overridepublic void afterPropertiesSet() throws Exception {    System.out.println("[InitializingBean] NormalBeanA");}

}
13.FactoryBeanorg.springframework.beans.factory.FactoryBean
个别状况下,Spring通过反射机制利用bean的class属性指定干线类去实例化bean,在某些状况下,实例化Bean过程比较复杂,如果依照传统的形式,则须要在bean中提供大量的配置信息。配置形式的灵活性是受限的,这时采纳编码的形式可能会失去一个简略的计划。Spring为此提供了一个 org.springframework.bean.factory.FactoryBean 的工厂类接口,用户能够通过实现该接口定制实例化Bean的逻辑。 FactoryBean 接口对于Spring框架来说占用重要的位置,Spring本身就提供了70多个 FactoryBean 的实现。它们暗藏了实例化一些简单bean的细节,给下层利用带来了便当。从Spring3.0开始, FactoryBean 开始反对泛型,即接口申明改为 FactoryBean<T> 的模式应用场景:用户能够扩大这个类,来为要实例化的bean作一个代理,比方为该对象的所有的办法作一个拦挡,在调用前后输入一行log,模拟 ProxyFactoryBean 的性能。扩大形式为:public class TestFactoryBean implements FactoryBean<TestFactoryBean.TestFactoryInnerBean> {

@Overridepublic TestFactoryBean.TestFactoryInnerBean getObject() throws Exception {    System.out.println("[FactoryBean] getObject");    return new TestFactoryBean.TestFactoryInnerBean();}@Overridepublic Class<?> getObjectType() {    return TestFactoryBean.TestFactoryInnerBean.class;}@Overridepublic boolean isSingleton() {    return true;}public static class TestFactoryInnerBean{}

}
14.SmartInitializingSingletonorg.springframework.beans.factory.SmartInitializingSingleton
这个接口中只有一个办法 afterSingletonsInstantiated ,其作用是是 在spring容器治理的所有单例对象(非懒加载对象)初始化实现之后调用的回调接口。其触发机会为 postProcessAfterInitialization 之后。应用场景:用户能够扩大此接口在对所有单例对象初始化结束后,做一些后置的业务解决。扩大形式为:public class TestSmartInitializingSingleton implements SmartInitializingSingleton {

@Overridepublic void afterSingletonsInstantiated() {    System.out.println("[TestSmartInitializingSingleton]");}

}
15.CommandLineRunnerorg.springframework.boot.CommandLineRunner
这个接口也只有一个办法: run(String... args) ,触发机会为整个我的项目启动结束后,主动执行。如果有多个 CommandLineRunner ,能够利用 @Order 来进行排序。应用场景:用户扩大此接口,进行启动我的项目之后一些业务的预处理。扩大形式为:public class TestCommandLineRunner implements CommandLineRunner {

@Overridepublic void run(String... args) throws Exception {    System.out.println("[TestCommandLineRunner]");}

}
16.DisposableBeanorg.springframework.beans.factory.DisposableBean
这个扩大点也只有一个办法: destroy() ,其触发机会为当此对象销毁时,会主动执行这个办法。比如说运行 applicationContext.registerShutdownHook 时,就会触发这个办法。扩大形式为:public class NormalBeanA implements DisposableBean {

@Overridepublic void destroy() throws Exception {    System.out.println("[DisposableBean] NormalBeanA");}

}
17.ApplicationListenerorg.springframework.context.ApplicationListener
精确的说,这个应该不算spring&springboot当中的一个扩大点, ApplicationListener 能够监听某个事件的 event ,触发机会能够穿插在业务办法执行过程中,用户能够自定义某个业务事件。然而spring外部也有一些内置事件,这种事件,能够穿插在启动调用中。咱们也能够利用这个个性,来本人做一些内置事件的监听器来达到和后面一些触发点大致相同的事件。接下来列举下spring次要的内置事件:ContextRefreshedEventApplicationContext 被初始化或刷新时,该事件被公布。这也能够在 ConfigurableApplicationContext 接口中应用 refresh() 办法来产生。此处的初始化是指:所有的Bean被胜利装载,后处理Bean被检测并激活,所有Singleton Bean 被预实例化, ApplicationContext 容器已就绪可用。ContextStartedEvent当应用 ConfigurableApplicationContext (ApplicationContext子接口)接口中的 start() 办法启动 ApplicationContext 时,该事件被公布。你能够考察你的数据库,或者你能够在承受到这个事件后重启任何进行的应用程序。ContextStoppedEvent当应用 ConfigurableApplicationContext 接口中的 stop() 进行 ApplicationContext 时,公布这个事件。你能够在承受到这个事件后做必要的清理的工作ContextClosedEvent当应用 ConfigurableApplicationContext 接口中的 close() 办法敞开 ApplicationContext 时,该事件被公布。一个已敞开的上下文达到生命周期末端;它不能被刷新或重启RequestHandledEvent这是一个 web-specific 事件,通知所有 bean HTTP 申请曾经被服务。只能利用于应用DispatcherServlet的Web利用。在应用Spring作为前端的MVC控制器时,当Spring解决用户申请完结后,零碎会主动触发该事件18.最初咱们从这些spring&springboot的扩大点当中,大抵能够窥视到整个bean的生命周期。在业务开发或者写中间件业务的时候,能够正当利用spring提供给咱们的扩大点,在spring启动的各个阶段内做一些事件。以达到自定义初始化的目标。此篇总结,如果有谬误或者疏漏的中央,恳请斧正。