《Spring篇》--- 生命周期扩展点

概要

一直以来,一直在项目中反复的使用了实现InitializingBean和**ApplicationListener<ContextRefreshedEvent>**中特定方法来对一些特殊的bean或者业务进行预处理,这里就结合和参考网上大佬的总结,来谈一下对Spring生命周期扩展点的一些说明。

执行顺序

执行顺序就是目录顺序。

1. ApplicationContextInitializer

接口
实现方法:

  • initialize(ConfigurableApplicationContext applicationContext)
public class TTT1 implements ApplicationContextInitializer {
    
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
         System.out.println(111);
    }
}

调用时机: 配置初始化完成

  1. 用于在spring容器刷新之前初始化Spring ConfigurableApplicationContext的回调接口。(就是在容器刷新之前调用该类的 initialize 方法。并将 ConfigurableApplicationContext 类的实例传递给该方法)
  2. 通常用于需要对应用程序上下文进行编程初始化的web应用程序中。例如,根据上下文环境注册属性源或激活配置文件等。
  3. 可排序的(实现Ordered接口,或者添加@Order注解)

因为是在ApplicationContext之前调用的,所以无法由它管理初始化,只能通过配置。有3种方法

1.1 配置文件

context.initializer.classes=com.example.demo.test.TTT1

1.2 Main方法里

public class TTT2 {

    public static void main(String[] args) {
        SpringApplication sa = new SpringApplication(TTT2.class);
        sa.addInitializers(new TTT1());
        sa.run(args);
    }
}

日志打印情况:
加载优先级挺高

1.3 SpringBoot的SPI扩展—META-INF/spring.factories中配置

org.springframework.context.ApplicationContextInitializer=com.example.demo.test.TTT1

只会执行一次

2. @Import

注解
会在ApplicationContextInitializer 后执行,无论写在哪里
@Import(xx.class)
xx.class 要实现ImportBeanDefinitionRegistrar 接口

@Import(TTT3.class)
public class TTT2 {

    public static void main(String[] args) {
        SpringApplication sa = new SpringApplication(TTT2.class);
        sa.addInitializers(new TTT1());
        sa.run(args);

    }
}

日志结果
在这里插入图片描述

3. BeanDefinitionRegistryPostProcessor

接口 继承自 BeanFactoryPostProcessor
实现方法:

  • postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException
  • postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
public class TTT4 implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        
    }
}

调用时机:这个接口在读取项目中的beanDefinition之后执行,提供一个补充的扩展点
使用场景:你可以在这里动态注册自己的beanDefinition,可以加载classpath之外的bean

实现这个接口的类必须是被Spring容器管理的类,也就是类上要有@Component等注解
两个函数会在构造函数执行完之后执行

只会执行一次

4.BeanFactoryPostProcessor

接口
实现方法:

  • postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
public class TTT5 implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        
    }
}

调用时机:这个接口在读取项目中的beanDefinition之后执行,提供一个补充的扩展点
使用场景:你可以在这里动态注册自己的beanDefinition,可以加载classpath之外的bean

5.InstantiationAwareBeanPostProcessor

接口 实现InstantiationAwareBeanPostProcessor 继承与 BeanPostProcessor
实现方法:

postProcessBeforeInstantiation:实例化bean(构造函数)之前,相当于new这个bean之前
可以自定义实例化逻辑,如返回一个代理对象等,(如果此处返回的Bean不为null将中断后续Spring创建Bean的流程,且只执行postProcessAfterInitialization回调方法,如当AbstractAutoProxyCreator的实现者注册了TargetSourceCreator(创建自定义的TargetSource)将改变执行流程,不注册TargetSourceCreator我们默认使用的是SingletonTargetSource(即AOP代理直接保证目标对象),此处我们还可以使用如ThreadLocalTargetSource(线程绑定的Bean)、CommonsPoolTargetSource(实例池的Bean)等等,大家可以去spring官方文档了解TargetSource详情;
postProcessAfterInstantiation:实例化bean(构造函数)之后,相当于new这个bean之后
postProcessPropertyValues(5.1之前):
postProcessProperties(5.1开始用这个)
bean已经实例化完成,在属性注入时阶段触发,@Autowired,@Resource等注解原理基于此方法实现
postProcessBeforeInitialization:初始化bean之前,相当于把bean注入spring上下文之前
postProcessAfterInitialization:初始化bean之后,相当于把bean注入spring上下文之后
使用场景:这个扩展点非常有用 ,无论是写中间件和业务中,都能利用这个特性。比如对实现了某一类接口的bean在各个生命期间进行收集,或者对某个类型的bean进行统一的设值等等。

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

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

    /** @deprecated */
    @Deprecated
    @Nullable
    default PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
        return pvs;
    }
}

请注意

这个接口的方法是对于所有被Spring管理的Bean而言的
如果:你有3个类 Bean1,Bean2,Bean3。
每初始化一个bean,上面的5个方法都会走一遍
如果 Bean 实现了BeanDefinitionRegistryPostProcessor 或 BeanFactoryPostProcessor
上面5个方法将不会接收到它

6.SmartInstantiationAwareBeanPostProcessor

接口 继承自 InstantiationAwareBeanPostProcessor
实现方法:

  • predictBeanType:该触发点发生在postProcessBeforeInstantiation之前,这个方法用于预测Bean的类型,返回第一个预测成功的Class类型,如果不能预测返回null;当你调用BeanFactory.getType(name)时当通过bean的名字无法得到bean类型信息时就调用该回调方法来决定类型信息。
  • 通过@Autowared注入的时候 会校验类型,也会调用这个方法
  • 通过@Reaource注入就不会调用这个方法
  • determineCandidateConstructors:该触发点发生在postProcessBeforeInstantiation之后,构造函数调用之前,用于确定该bean的构造函数之用,返回的是该bean的所有构造函数列表。用户可以扩展这个点,来自定义选择相应的构造器来实例化这个bean。
  • getEarlyBeanReference:该触发点发生在postProcessAfterInstantiation之后,当有循环依赖的场景,当bean实例化好之后,为了防止有循环依赖,会提前暴露回调方法,用于bean实例化的后置处理。这个方法就是在提前暴露的回调方法中触发。
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
    @Nullable
    default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
        return null;
    }

    @Nullable
    default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
        return null;
    }

    default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

使用场景:看类名Smart就知道,可以让你智能的处理,BeanType,Constructor, 循环依赖。

7.BeanFactoryAware

接口 继承自 Aware
实现方法:

  • setBeanFactory:获得BeanFactory,发生在bean的实例化之后,注入属性之后,postProcessBeforeInitialization 之前
public interface BeanFactoryAware extends Aware {
    void setBeanFactory(BeanFactory var1) throws BeansException;
}

8.ApplicationContextAwareProcessor

实现了 BeanPostProcessor
在Bean初始化之前注入一些属性
同时这个类 印证了 postProcessBeforeInitialization 的用法

class ApplicationContextAwareProcessor implements BeanPostProcessor {
    private final ConfigurableApplicationContext applicationContext;
    private final StringValueResolver embeddedValueResolver;

    public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
    }

    @Nullable
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (!(bean instanceof EnvironmentAware) && !(bean instanceof EmbeddedValueResolverAware) && !(bean instanceof ResourceLoaderAware) && !(bean instanceof ApplicationEventPublisherAware) && !(bean instanceof MessageSourceAware) && !(bean instanceof ApplicationContextAware) && !(bean instanceof ApplicationStartupAware)) {
            return bean;
        } else {
            AccessControlContext acc = null;
            if (System.getSecurityManager() != null) {
                acc = this.applicationContext.getBeanFactory().getAccessControlContext();
            }

            if (acc != null) {
                AccessController.doPrivileged(() -> {
                    this.invokeAwareInterfaces(bean);
                    return null;
                }, acc);
            } else {
                this.invokeAwareInterfaces(bean);
            }

            return bean;
        }
    }

    private void invokeAwareInterfaces(Object bean) {
        if (bean instanceof EnvironmentAware) {
            ((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());
        }

        if (bean instanceof EmbeddedValueResolverAware) {
            ((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);
        }

        if (bean instanceof ResourceLoaderAware) {
            ((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);
        }

        if (bean instanceof ApplicationEventPublisherAware) {
            ((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);
        }

        if (bean instanceof MessageSourceAware) {
            ((MessageSourceAware)bean).setMessageSource(this.applicationContext);
        }

        if (bean instanceof ApplicationStartupAware) {
            ((ApplicationStartupAware)bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
        }

        if (bean instanceof ApplicationContextAware) {
            ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
        }

    }
}

9.BeanNameAware

接口 继承自 Aware
***这个在 BeanFactory 之前注入 (spring5.2.1)
实现方法:

  • setBeanName
public interface BeanNameAware extends Aware {
    void setBeanName(String var1);
}

10.@PostConstruct

这个触发点是在postProcessBeforeInitialization之后,InitializingBean.afterPropertiesSet之前。

11.InitializingBean

实现方法:

  • afterPropertiesSet
  • 这个触发点是在postProcessAfterInitialization之前。

当然还有一个 init-method (不常用)
执行顺序是
postProcessBeforeInitialization
@PostConstruct > InitializingBean > init-method
postProcessAfterInitialization

public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}

12.FactoryBean

接口
实现方法:

  • getObject: 返回一个对象的实例
  • getObjectType:返回FactoryBean管理的对象类型

故名思意:这个接口就是用来管理Bean 的生产的
但其实也可以通过@Bean来完成同样的功能
不过实现FactoryBean语义上更明确一些例如 DataSourceFactoryBean,一看就知道跟数据库相关

public interface FactoryBean<T> {
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    @Nullable
    T getObject() throws Exception;

    @Nullable
    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }

13.SmartInitializingSingleton

接口
实现方法:

  • afterSingletonsInstantiated:

在所有单例Bean加载完后调用, 因此你可以通过ApplicationContext 来拿到所有加载好的Bean,并对他们进行一些处理

只会执行一次

public interface SmartInitializingSingleton {
    void afterSingletonsInstantiated();
}

14.ApplicationRunner

接口
实现方法:

  • run: 接受ApplicationArguments 参数
@FunctionalInterface
public interface ApplicationRunner {
    void run(ApplicationArguments args) throws Exception;
}

在项目启动完之后执行
只会执行一次

15.CommandLineRunner

接口
实现方法:

  • run: 接受命令行参数
@FunctionalInterface
public interface CommandLineRunner {
    void run(String... args) throws Exception;
}

在项目启动完之后执行
只会执行一次

16.@PreDestroy

Bean被销毁之前执行

17.DisposableBean

接口
实现方法:

  • destroy
  • Bean被销毁之前执行

执行顺序
@PreDestroy > DisposableBean.destroy > destory-method

18.ApplicationListener

ApplicationEvent以及Listener是Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式,设计初衷也是为了系统业务逻辑之间的解耦,提高可扩展性以及可维护性。

通过 ApplicationEvent 类和 ApplicationListener 接口来提供在 ApplicationContext 中处理事件。如果一个 bean 实现 ApplicationListener,那么每次 ApplicationEvent 被发布到 ApplicationContext 上,那个 bean 会被通知。

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    void onApplicationEvent(E var1);

    static <T> ApplicationListener<PayloadApplicationEvent<T>> forPayload(Consumer<T> consumer) {
        return (event) -> {
            consumer.accept(event.getPayload());
        };
    }
}
序号Spring 内置事件 & 描述
1ContextRefreshedEvent ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在 ConfigurableApplicationContext 接口中使用 refresh() 方法来发生。
2ContextStartedEvent当使用 ConfigurableApplicationContext 接口中的 start() 方法启动 ApplicationContext 时,该事件被发布。你可以调查你的数据库,或者你可以在接受到这个事件后重启任何停止的应用程序。
3ContextStoppedEvent当使用 ConfigurableApplicationContext 接口中的 stop() 方法停止 ApplicationContext 时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作。
4ContextClosedEvent当使用 ConfigurableApplicationContext 接口中的 close() 方法关闭 ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启。
5RequestHandledEvent这是一个 web-specific 事件,告诉所有 bean HTTP 请求已经被服务。

具体可参考:使用ApplicationEvent和Listener快速实现业务解耦Spring执行ApplicationEvent事件顺序ServletWebServerInitializedEvent

19.@Configuration,@Bean

这两个注解并不是 spring生命周期里的
但,确实我们经常用到的

@Configuration

  • @Configuration:它本身就是一个@Component能被spring容器扫描到,所以它的加载时机与普通Bean是一样的,不同的是它内部被标注为@Bean的方法
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration

@Bean

作用与@Component一样,用它标记的方法会被当成一个工场方法,来生产Bean
在工厂方法里你可以调用非空构造函数,来创建一个复杂类的Bean
你还可以为同一个类创建多个对象
最常见的就是多数据源配置

    @Primary
    @Bean(name = "ds1")
    @ConfigurationProperties(prefix = "spring.datasource1")
    public DruidDataSource getDataSource1() {
        return DataSourceBuilder.create().type(DruidDataSource.class).build();
    }

    @Bean(name = "ds2")
    @ConfigurationProperties(prefix = "spring.datasource2")
    public DruidDataSource getDataSource2() {
        return DataSourceBuilder.create().type(DruidDataSource.class).build();
    }

参考文献

spring 生命周期 扩展点

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值