Spring中bean的生命周期及bean的扩展点总结

自有博客:Bean的作用域+生命周期+加载过程_bean加载过程和生命周期_keep one's resolveY的博客-CSDN博客

Bean的生命周期图:

专用和通用扩展点图:

Spring 在每个阶段都提供了扩展点,扩展点可以分为两类:

  • 专用扩展点:用于单个 Bean 的扩展,定义 Bean 类时实现接口来扩展功能。
  • 通用扩展点:用于所有 Bean 的扩展,单独定义类实现接口来扩展功能。

博客一

1.背景

Spring的核心思想就是容器,当容器refresh的时候,外部看上去风平浪静,其实内部则是一片惊涛骇浪,汪洋一片。Springboot更是封装了Spring,遵循约定大于配置,加上自动装配的机制。很多时候我们只要引用了一个依赖,几乎是零配置就能完成一个功能的装配。

我非常喜欢这种自动装配的机制,所以在自己开发中间件和公共依赖工具的时候也会用到这个特性。让使用者以最小的代价接入。想要把自动装配玩的转,就必须要了解spring对于bean的构造生命周期以及各个扩展接口。当然了解了bean的各个生命周期也能促进我们加深对spring的理解。业务代码也能合理利用这些扩展点写出更加漂亮的代码。

在网上搜索spring扩展点,发现很少有博文说的很全的,只有一些常用的扩展点的说明。

所以在这篇文章里,我总结了几乎Spring & Springboot所有的扩展接口,以及各个扩展点的使用场景。并且整理出了一个bean在spring内部从被加载到最后初始化完成所有可扩展点的顺序调用图。从而我们也能窥探到bean是如何一步步加载到spring容器中的。

2.可扩展的接口启动调用顺序图

以下是我整理的spring容器中Bean的生命周期内所有可扩展的点的调用顺序,下面会一个个分析

3.ApplicationContextInitializer

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容器还没被初始化,所以想要自己的扩展的生效,有以下三种方式:

  • 在启动类中用springApplication.addInitializers(new TestApplicationContextInitializer())语句加入

  • 配置文件配置context.initializer.classes=com.example.demo.TestApplicationContextInitializer

  • Spring SPI扩展,在spring.factories中加入org.springframework.context.ApplicationContextInitializer=com.example.demo.TestApplicationContextInitializer

4.BeanDefinitionRegistryPostProcessor

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");
    }
}

5.BeanFactoryPostProcessor

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]");
    }
}

6.InstantiationAwareBeanPostProcessor

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;
    }

7.SmartInstantiationAwareBeanPostProcessor

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;
    }
}

8.BeanFactoryAware

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());
    }
}

9.ApplicationContextAwareProcessor

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来共同使用,下文在介绍ApplicationListener时会详细提到。这个对象也可以通过spring注入的方式来获得。

  • MessageSourceAware:用于获取MessageSource的一个扩展类,MessageSource主要用来做国际化。

  • ApplicationContextAware:用来获取ApplicationContext的一个扩展类,ApplicationContext应该是很多人非常熟悉的一个类了,就是spring上下文管理器,可以手动的获取任何在spring上下文注册的bean,我们经常扩展这个接口来缓存spring上下文,包装成静态方法。同时ApplicationContext也实现了BeanFactoryMessageSourceApplicationEventPublisher等接口,也可以用来做相关接口的事情。

10.BeanNameAware

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);
    }
}

11.@PostConstruct

javax.annotation.PostConstruct

这个并不算一个扩展点,其实就是一个标注。其作用是在bean的初始化阶段,如果对一个方法标注了@PostConstruct,会先调用这个方法。这里重点是要关注下这个标准的触发点,这个触发点是在postProcessBeforeInitialization之后,InitializingBean.afterPropertiesSet之前。

使用场景:用户可以对某一方法进行标注,来进行初始化某一个属性

扩展方式为:

public class NormalBeanA {
    public NormalBeanA() {
        System.out.println("NormalBean constructor");
    }

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

12.InitializingBean

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");
    }
}

13.FactoryBean

org.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> {

    @Override
    public TestFactoryBean.TestFactoryInnerBean getObject() throws Exception {
        System.out.println("[FactoryBean] getObject");
        return new TestFactoryBean.TestFactoryInnerBean();
    }

    @Override
    public Class<?> getObjectType() {
        return TestFactoryBean.TestFactoryInnerBean.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    public static class TestFactoryInnerBean{

    }
}

14.SmartInitializingSingleton

org.springframework.beans.factory.SmartInitializingSingleton

这个接口中只有一个方法afterSingletonsInstantiated,其作用是是 在spring容器管理的所有单例对象(非懒加载对象)初始化完成之后调用的回调接口。其触发时机为postProcessAfterInitialization之后。

使用场景:用户可以扩展此接口在对所有单例对象初始化完毕后,做一些后置的业务处理。

扩展方式为:

public class TestSmartInitializingSingleton implements SmartInitializingSingleton {
    @Override
    public void afterSingletonsInstantiated() {
        System.out.println("[TestSmartInitializingSingleton]");
    }
}

15.CommandLineRunner

org.springframework.boot.CommandLineRunner

这个接口也只有一个方法:run(String... args),触发时机为整个项目启动完毕后,自动执行。如果有多个CommandLineRunner,可以利用@Order来进行排序。

使用场景:用户扩展此接口,进行启动项目之后一些业务的预处理。

扩展方式为:

public class TestCommandLineRunner implements CommandLineRunner {

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

16.DisposableBean

org.springframework.beans.factory.DisposableBean

这个扩展点也只有一个方法:destroy(),其触发时机为当此对象销毁时,会自动执行这个方法。比如说运行applicationContext.registerShutdownHook时,就会触发这个方法。

扩展方式为:

public class NormalBeanA implements DisposableBean {
    @Override
    public void destroy() throws Exception {
        System.out.println("[DisposableBean] NormalBeanA");
    }
}

17.ApplicationListener

org.springframework.context.ApplicationListener

准确的说,这个应该不算spring&springboot当中的一个扩展点,ApplicationListener可以监听某个事件的event,触发时机可以穿插在业务方法执行过程中,用户可以自定义某个业务事件。但是spring内部也有一些内置事件,这种事件,可以穿插在启动调用中。我们也可以利用这个特性,来自己做一些内置事件的监听器来达到和前面一些触发点大致相同的事情。

接下来罗列下spring主要的内置事件:

  • ContextRefreshedEvent

    ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在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启动的各个阶段内做一些事情。以达到自定义初始化的目的。此篇总结,如果有错误或者疏漏的地方,恳请指正。

----------------------------------------------------------------------------------------------------------------------------

博客二

Spring 的核心是 IoC 容器,了解 Bean 的生命周期非常重要,这对 Spring 在项目中的应用和扩展都很有帮助。

一、生命周期

Bean 的生命周期主要为实例化、属性填充、初始化和销毁 4 个阶段,加上类加载和使用阶段,整个流程如下:

二、Bean 的扩展

Spring 在每个阶段都提供了扩展点,扩展点可以分为两类:

  • 专用扩展点:用于单个 Bean 的扩展,定义 Bean 类时实现接口来扩展功能。
  • 通用扩展点:用于所有 Bean 的扩展,单独定义类实现接口来扩展功能。

1. 专用扩展点

Aware 接口

Aware 接口可以在属性填充的时候注入 Bean 信息或上下文等信息。

例如可以通过实现 BeanNameAware 接口将当前 Bean 的名称注入到类中。

public class OneBeanExample implements BeanNameAware {

    private String beanName;

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }
}

Spring 提供了许多 Aware 的子接口可以使用,常用的有:

Aware接口注入依赖
BeanNameAwareBean 的名称
BeanFactoryAware当前上下文的 BeanFactory
ApplicationContextAware当前上下文的 ApplicationContext
ApplicationEventPublisherAware当前上下文的事件发布者 ApplicationEventPublisher
BeanClassLoaderAware加载 Bean 类的类加载器

InitializingBean 和 DisposableBean 接口

如果要在 Bean 初始化时添加自定义逻辑,可以实现 InitializingBean 接口。

如果要在 Bean 销毁时添加自定义逻辑,可以实现 DisposableBean 接口。

public class OneBeanExample implements InitializingBean, DisposableBean {

    @Override
    public void afterPropertiesSet() {
		// do some initialization work
    }

    @Override
    public void destroy() {
		// do some destruction work
    }
}

除了上面两个回调接口,也可以在注册 Bean 的时候指定自定义初始化和销毁方法。

@Bean 注解的 initMethod 属性指定 Bean 初始化方法,destroyMethod 属性指定 Bean 销毁方法。

public class OneBeanExample {

    public void init() {
        // do some initialization work
    }

    public void destroy() {
        // do some destruction work
    }
}

@Configuration
public class AppConfig {

    @Bean(initMethod = "init", destroyMethod = "destroy")
    public OneBeanExample oneBeanExample() {
        return new OneBeanExample();
    }
}

对应 XML 配置 <bean> 标签的 init-method 和 destroy-method 属性。

还可以使用 JDK 的 @PostConstruct 和 @PreDestroy 注解来指定初始化方法和销毁方法。

public class OneBeanExample {

    @PostConstruct
    public void init() {
        // do some initialization work
    }

    @PreDestroy
    public void destroy() {
        // do some destruction work
    }
}

前面提供的三种方式都可以定义 Bean 初始化和销毁时执行的方法。

InitializingBean 和 DisposableBean 接口会和 Spring 强耦合。

当项目中没有依赖 Spring 时,推荐使用第二种或第三种方式。

2. 通用扩展点

通用扩展点对所有 Bean 有效,需要定义单独的类来实现,主要有三个接口:

  • BeanPostProcessor 接口
  • InstantiationAwareBeanPostProcessor 接口
  • DestructionAwareBeanPostProcessor 接口

BeanPostProcessor 接口

实现该接口可以在 Bean 初始化前后添加自定义逻辑。

@Component
public class BeanInitProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // before initialization work
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // after initialization work
        return bean;
    }
}

InstantiationAwareBeanPostProcessor 接口

实现该接口可以在 Bean 实例化前后添加自定义逻辑。

@Component
public class BeanInstanceProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        // before instantiation work
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        // after instantiation work
        return true;
    }
}

DestructionAwareBeanPostProcessor 接口

实现该接口可以在 Bean 销毁前添加自定义逻辑。

@Component
public class BeanDestroyProcessor implements DestructionAwareBeanPostProcessor {

    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        // before destruction work
    }
}

3. 生命周期扩展点示例

Bean 生命周期的 4 个阶段都支持扩展,每个阶段都可以添加自定义逻辑。

3.1 实例化

Spring 容器在这步实例化 Bean 对象。

实现 InstantiationAwareBeanPostProcessor 接口的两个扩展方法,在实例化前后添加扩展。

3.2 属性填充

Spring 容器在这步填充属性,例如通过 Setter 方法注入依赖。

属性填充后通过 Aware 接口扩展来注入 Bean 信息或上下文等信息。

3.2 初始化

Spring 容器在这步初始化 Bean。

实现 BeanPostProcessor 接口的两个扩展方法,在初始化前后添加扩展。

在初始化阶段,前面讲到三种方式来指定初始化方法,一般情况下使用一种就行。

如果同时使用三种,三种方式指定的方法相同,该方法只执行一次,当三种方式指定的方法不同,按图中顺序执行。

3.4 销毁

Spring 容器在这步销毁 Bean,可以释放外部资源。

实现 DestructionAwareBeanPostProcessor 接口的扩展方法,可以在销毁前添加扩展。

在销毁阶段,前面讲到三种方式来指定销毁方法,一般情况下使用一种就行。

如果同时使用三种,三种方式指定的方法相同,该方法只执行一次,当三种方式指定的方法不同,按图中顺序执行。

4. 生命周期扩展点顺序

Bean 的生命周期中,通用扩展点和专用扩展点,以及它们对应的方法,执行顺序如下图:

三、附录

1. 配置属性

属性描述
<bean>init-method属性基于 XML 配置容器中,指定自定义初始化方法
<bean>destroy-method属性基于 XML 配置容器中,指定自定义销毁方法

2. 常用注解

注解描述
@BeaninitMethod属性基于 Java 配置容器中,指定自定义初始化方法
@BeandestroyMethod属性基于 Java 配置容器中,指定自定义销毁方法
@PostConstruct使用 JDK 注解指定初始化执行的方法
@PreDestroy使用 JDK 注解指定销毁执行的方法

3. 示例代码

Gitee 仓库:spring: Spring 学习相关代码

项目模块:spring-ioc

示例路径:cn.codeartist.spring.bean.life

本文来自博客园,作者:码匠_CodeArtist,转载请注明原文链接:第7章-Spring的Bean生命周期和扩展点 - 码匠_CodeArtist - 博客园

博客三

一、SpringBean的生命周期

Spring Bean的生命周期

二、后置处理器postProcessor

一个是针对BeanDefinition的容器级别的后处理器 - BeanFactoryPostProcessor

  • 一个是针对getBean操作获得的对象的后处理器 - BeanPostProcessor

两者的不同:

触发时机不同,前者BeanFactoryPostProcessor是在容器refresh方法中调用,而后者实际调用时机是在getBean方法获取对象时调用;

因触发时机不同导致二者处理的对象不同。BeanFactoryPostProcessor处理的是解析完配置文件后注册在容器中的BeanDefinition,而BeanPostProcessor处理的是通过反射生成的实例Bean

接口样式不同,BeanFactoryPostProcessor只有一个后处理方法,而BeanPostProcessor有一个前置处理方法一个后置处理方法。

三、BeanPostProcessor

Spring主要提供了两类扩展点BeanPostProcessor和BeanFactoryPostProcessor。前者是操作bean的实例,后者使对bean的元数据定义进行扩展。

BeanPostProcessor提供对bean实例的操作扩展,在spring容器对bean实例化和设置依赖之后,其回调开始执行。BeanPostProcessor接口定义的两个方法,分别在bean的初始化方法(InitializingBean接口,或者init-method定义)执行的前后执行:

如果你想在Spring容器完成实例化,配置和初始化bean之后实现一些自定义逻辑,则可以插入一个或多个自定义BeanPostProcessor实现。这些实现成为后置处理器。

BeanPostProcessor接口包含两个回调方法。

当实现此接口类通过容器注册为后处理器时,由Spring容器实例的Bean,Spring容器会在bean 的init方法执行前回调postProcessBeforeInitialization方法,

然后会在bean初始化之后回调postProcessAfterInitialization方法。

后置处理器可以对这些Bean做任何自定义操作。一些Spring Aop 的基础实现类就是通过实现BeanPostProcessor从而提供代理包装逻辑 。

Spring容器能够自动检测任何实现了BeanPostProcessor接口的Bean。容器会自动将这些bean注册成后置处理器以便后续调用。

另外我们可以定义多个BeanPostProcessor,他们执行的顺序可以通过实现PriorityOrdered、Ordered接口来控制。

我们定义一个类实现了BeanPostProcessor,默认会对整个Spring容器中所有的bean进行处理

方法的参数:

  1. 每个Bean的实例
  2. 每个Bean的name 或者 id属性

实现 PriorityOrdered、Ordered,可以定义顺序

下面的示例演示如何在ApplicationContext中编写,注册和使用BeanPostProcessor实例(Spring AOP的实现方式就是如下。

@Component
public interface Person {
 
    void sayHello();
 
}
@Component("student")
public class StudentImpl implements Person {
 
    private String name;
 
    @Override
    public void sayHello() {
        System.out.println("Hello World, " + this.name);
    }
 
    @PostConstruct
    public void init() {
        this.name = "student";
    }
 
    @Override
    public String toString() {
        return "HelloWorldImpl{" +
                "name='" + name + '\'' +
                '}';
    }
}
@Component("teacher")
public class TeacherImpl implements Person {
    private String name;
 
    @Override
    public void sayHello() {
        System.out.println("Hello World, "+this.name);
    }
 
    @PostConstruct
    public void init(){
        this.name="teacher";
    }
 
    @Override
    public String toString() {
        return "TeacherImpl{" +
                "name='" + name + '\'' +
                '}';
    }
}
@Configuration
@ComponentScan(value = "com.best")
public class AppConfig {
}
/**
 * 自定义HelloWorldBeanPostProcessor实现BeanPostProcessor接口
 */
@Component
public class HelloWorldBeanPostProcessor implements BeanPostProcessor {
 
    @Autowired
    private ApplicationContext applicationContext;
 
    // 直接返回实例化的bean,在bean初始化之前执行
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization: " + bean + ", " +  beanName + ", " + applicationContext.getApplicationName());
        return bean;
    }
 
    // 直接返回实例化的bean,在bean初始化之后执行
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization: " + bean + ", " +  beanName + ", " + applicationContext.getApplicationName());
        return Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("BeanPostProcessor织入,Spring AOP实现原理");
                return method.invoke(bean, args);
            }
        });
    }
}

执行入口: 

public class Main {
 
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        Person student = (Person) applicationContext.getBean("student");
        System.out.println(student.getClass().getName());
        student.sayHello();
        Person teacher = (Person) applicationContext.getBean("teacher");
        System.out.println(teacher.getClass().getName());
        teacher.sayHello();
 
    }
}

上面程序执行的结果如下:

四、BeanFactoryPostProcessor

BeanFactory级别的处理,是针对整个Bean的工厂进行处理。

这是Spring容器的另外一个扩展点,和BeanPostProcessor不同的地方在于,它是对beanDefiniton进行操作。

实现该接口,可以在spring的bean创建之前,修改bean的定义属性。

当调用BeanFactoryPostProcess 方法时,这时候bean还没有实例化,此时Bean刚被解析成 BeanDefinition对象。

也就是说,Spring允许BeanFactoryPostProcessor在容器实例化任何其它bean之前读取配置元数据,并可以根据需要进行修改,

例如可以把bean的scope从singleton改为prototype,也可以把property的值给修改掉。可以同时配置多个BeanFactoryPostProcessor,并通过设置'order'属性或实现ordered接口来控制各个BeanFactoryPostProcessor的执行次序,

这些和BeanPostProcessor很类似,并且其启用方式和容器相关性也与之一致。

注意:BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的。接口方法的入参是ConfigurrableListableBeanFactory,使用该参数,可以获取到相关bean的定义信息:

 BeanDefinition obj = arg0.getBeanDefinition("sumBean");

 Spring内置实现了很多的BeanFactoryPostProcessor实现,例如:

org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
 
org.springframework.beans.factory.config.PropertyOverrideConfigurer
 
org.springframework.beans.factory.config.CustomEditorConfigurer:用来注册自定义的属性编辑器。
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println(" IOC 容器调用了 YjBeanFactoryPostProcessor 的 postProcessBeanFactory方法");
        for(String name:beanFactory.getBeanDefinitionNames()) {
            if("yjLog".equals(name)) {
                BeanDefinition beanDefinition = beanFactory.getBeanDefinition(name);
                //beanDefinition.setLazyInit(true);
            }
        }
    }
}

 下面示例,如何通过BeanFactoryPostProcessor动态注册Bean进去。

@Component
public class User {
 
    private Integer id;
 
    private String name;
 
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
@Configuration
@ComponentScan(value = "com.best")
public class AppConfig {
}
@Component
public class HelloWorldBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
    // 实现BeanFactoryPostProcessor,在spring的bean创建之前,对beanDefinition进行操作,修改bean的定义属性
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        beanDefinitionBuilder.addPropertyValue("id", 1);
        beanDefinitionBuilder.addPropertyValue("name", "jak");
        defaultListableBeanFactory.registerBeanDefinition("user", beanDefinitionBuilder.getBeanDefinition());
 
    }
}

程序入口,获取User并输出。

public class Main {
 
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        User user = (User) applicationContext.getBean("user");
        System.out.println(user.toString());
    }
}

 程序输出结果,如下。

 

五、BeanDefinitionRegistryPostProcessor

这个接口继承了BeanFactoryPostProcessor. 从名字上来看, 这个接口是BeanDefinitionRegistry的后处理器,

我们先介绍下BeanDefinitionRegistry.

BeanDefinitionRegistry是用来注册BeanDefinition的.

 BeanDefinition就是Bean的配置元数据或Bean的描述信息, 比如Bean的属性值, 构造方法的参数值等. 上面的BeanFactoryBeanDefinition也是由它注册的.

BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor的扩展, 允许在BeanFactoryPostProcessor被调用之前对BeanDefinition做一些操作, 尤其是它可以注册BeanFactoryPostProcessorBeanDefinition.

它提供了一个方法postProcessBeanDefinitionRegistry(), 这个方法被调用的时候, 所有的BeanDefinition已经被加载了, 但是所有的Bean还没被创建.

注意:

  • 所有的Bean生成都有个顺序: 定义 --> 创建 --> 初始化.
  • BeanDefinitionRegistryPostProcessorpostProcessBeanDefinitionRegistry方法在Bean定义但还没被创建的时候执行.
  • BeanFactoryPostProcessorpostProcessBeanFactory方法在Bean创建但还没被初始化的时候执行
@Component
public class BestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
 
    //该方法用来注册更多的bean到spring容器中
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("BestBeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法");
        //框架自己的  BeanDefiniton  Count
        System.out.println("bean定义的数据量:" + registry.getBeanDefinitionCount());
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(BestBeanDefinitionRegistryPostProcessor.class);
        registry.registerBeanDefinition("bestBeanDefinitionRegistryPostProcessor", rootBeanDefinition);
    }
 
    // 继承自BeanFactoryPostProcessor的方法 主要用来对bean定义做一些改变
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("BestBeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法");
        System.out.println("bean定义的数据量:" + beanFactory.getBeanDefinitionCount());
    }
}
public class Main {
 
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        BestBeanDefinitionRegistryPostProcessor bestBeanDefinitionRegistryPostProcessor = (BestBeanDefinitionRegistryPostProcessor) applicationContext.getBean("bestBeanDefinitionRegistryPostProcessor");
        System.out.println(bestBeanDefinitionRegistryPostProcessor.getClass().getCanonicalName());
    }
}

运行结果:

 

六、InitializingBean和DisposableBean

Spring 中定义了 3 种自定义初始化和销毁方法。

  1. 通过@Bean指定init-method和destroy-method属性
  2. Bean实现InitializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑);
  3. @PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法

Spring bean 通过实现 InitializingBean ,DisposableBean 接口实现初始化方法和销毁前操作

这个接口有一个方法:afterPropertiesSet, 该方法在所有的属性都被赋值后调用. 属性被赋值是在初始化的时候做的, 与BeanPostProcessor结合来看,

afterPropertiesSet方法将在postProcessBeforeInitializationpostProcessAfterInitialization之间被调用.

@Component
public class Student implements InitializingBean, DisposableBean {
 
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean destroy");
    }
 
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean afterPropertiesSet");
    }
}
@Configuration
@ComponentScan(value = "com.best")
public class AppConfig {
 
}
public class Test {
	public static void main(String[] args) {
 
		/**
		 * 1.把类扫描出来--扫描以后干了什么事情
		 * 2.把bean实例化
		 */
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		Student student = applicationContext.getBean(Student.class);
		System.out.println(student.getClass().getName());
		applicationContext.close();
	}
}

运行结果:

七、 Aware接口

Spring中提供了各种Aware接口,如果检测到一个bean实现了Aware接口,则能在bean中获取相应的Spring资源;

如果某个对象实现了某个Aware接口,比如需要依赖Spring的上下文容器(ApplicationContext),则可以实现ApplicationContextAware接口。

Spring在Bean进行初始化(注意与实例化的区别)之前,会将依赖的ApplicationContext对象通过调用ApplicationContextAware#setApplicationContext注入。

Spring 提供的Aware接口如下

那么这些Aware接口在源码中是什么时候调用的呢?

AbstractAutowireCapableBeanFactory#invokeAwareMethods

其他的Aware接口呢?通过 ApplicationContextAwareProcessor

应用示例

@Component
public class BestApplicationContextAware implements ApplicationContextAware {
 
    ApplicationContext applicationContext;
 
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        String[] beanDefinitionNames = this.applicationContext.getBeanDefinitionNames();
        System.out.println(Arrays.toString(beanDefinitionNames));
    }
}
public class Main {
 
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        BestApplicationContextAware bestApplicationContextAware = (BestApplicationContextAware) applicationContext.getBean("bestApplicationContextAware");
        System.out.println(bestApplicationContextAware.getClass().getCanonicalName());
    }
}

运行结果:

八、FactoryBean

一般情况下,Spring通过反射机制利用bean的class属性指定实现类来实例化bean 。

在某些情况下,实例化bean过程比较复杂,如果按照传统的方式,则需要在bean中提供大量的配置信息,配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。

Spring为此提供了一个org.Springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑。

(后面Spring又提供了@Configration和@Bean这种方式,一定程度上可以替代FactoryBean)

public interface FactoryBean<T> {
 
	@Nullable
	T getObject() throws Exception;
 
	@Nullable
	Class<?> getObjectType();
 
	default boolean isSingleton() {
		return true;
	}
}

FactoryBean和BeanFactory的区别

BeanFactory

FactoryBean

应用场景

@Component
public class BestFactoryBean implements FactoryBean<User> {
 
    private String userInfo;
 
    public User getObject() throws Exception {
        User User = new User();
        String[] infos = userInfo.split(",");
        User.setId(Integer.parseInt(infos[0]));
        User.setName(infos[1]);
        return User;
    }
 
    public Class<User> getObjectType() {
        return User.class;
    }
 
    public boolean isSingleton() {
        return false;
    }
 
    public String getUserInfo() {
        return this.userInfo;
    }
 
    // 接受逗号分割符设置属性信息
    public void setUserInfo(String userInfo) {
        this.userInfo = userInfo;
    }
}

九、ApplicationListener

这跟Servlet中的监听器一样, 采用了观察者模式. 监听器往往都是监听某些事件源,

下面是配合ApplicationContextAware一起使用的例子.

我们定义一个事件, 在实现了ApplicationContextAwareBean中触发事件, 在实现了ApplicationListener的类中对事件做出反应.

// 自定义事件
public class RumenEvent extends ApplicationEvent {
    public RumenEvent(Object source) {
        super(source);
    }
}
// 自定义 Bean 实现 ApplicationContextAware 接口
@Component
public class RumenzBean implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    private String name;
    public void setApplicationContext(ApplicationContext context) {
        this.applicationContext = context;
    }
    // 当调用 setName 时, 触发事件
    public void setName(String name) {
        this.name = name;
        applicationContext.publishEvent(new RumenEvent(this));  // 这行代码执行完会立即被监听到
    }
    public String getName() {
        return name;
    }
}
// 自定义监听器, 监听上面的事件
@Component
public class MyApplicationListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof RumenEvent) {
            System.out.println(((RumenzBean)event.getSource()).getName());
        }
    }
}

参考博客参考博客参考博客参考博客参考博客参考博客参考博客参考博客参考博客视频教程

Spring常用扩展点_星夜孤帆的博客-CSDN博客_spring扩展点

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值