likes
comments
collection
share

深入探索 Spring 16 个 Bean 生命周期扩展接口,打造高效优雅代码

作者站长头像
站长
· 阅读数 1

背景

Spring的核心是其容器机制,表面看似平静,实则在内部进行着复杂的操作。Springboot进一步封装了Spring,强调“约定优于配置”原则,并采用自动装配机制。通常,引入一个依赖后,我们几乎无需配置即可完成功能的集成。

我特别喜欢这种自动装配机制,并在开发中间件和公共工具时应用它。深入理解 Spring 中bean的生命周期和各扩展接口对于掌握自动装配至关重要,同时也有助于深化对 Spring 的理解,并编写更优雅的业务代码。

本文总结了Spring和Springboot的所有扩展接口及其使用场景,并制作了一个展示bean在Spring内部从加载到初始化的所有可扩展点顺序的图表,帮助理解bean是如何被逐步加载到Spring容器中的。

Bean的生命周期内可扩展点调用顺序图

深入探索 Spring 16 个 Bean 生命周期扩展接口,打造高效优雅代码

ApplicationContextInitializer

org.springframework.context.ApplicationContextInitializer

用于在 Spring 应用上下文 (ApplicationContext) 刷新之前对其进行编程式配置。这个接口在 Spring 应用启动过程中的早期阶段被调用,允许开发者在加载任何 bean 之前对应用上下文进行定制。

应用场景

  • 定制应用上下文配置:通过实现 ApplicationContextInitializer 接口,可以在 Spring 容器加载任何 bean 定义之前调用自定义逻辑,从而允许对配置进行编程式的修改。在应用启动前检查或准备外部资源,如消息队列

  • 环境依赖的设置:它常用于根据不同的环境(如开发、测试、生产)设置不同的配置参数。例如,可以根据不同的配置文件或环境变量来调整数据源设置。如:根据环境变量动态设置数据库连接参数

  • 与 Spring Profiles 集成:可以在 ApplicationContextInitializer 中激活或修改 Spring Profiles,从而改变应用程序的行为和配置。

  • 动态字节码注入:利用这时候class还没被类加载器加载的时机,进行动态字节码注入等操作

扩展方式

public class MyApplicationContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        // 自定义逻辑处理
    }
}

生效方式

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

  • 配置文件配置context.initializer.classes=com.tf.demo.MyApplicationContextInitializer

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

使用案例

深入探索 Spring 16 个 Bean 生命周期扩展接口,打造高效优雅代码

BeanDefinitionRegistryPostProcessor

org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor

用于在标准初始化之后和 Bean 实例化之前修改应用程序上下文的 Bean 定义。这个接口扩展了 BeanFactoryPostProcessor,提供了更加灵活的操作 Bean 定义的能力

应用场景

  • 修改或增加Bean定义:在 Spring 容器加载了 Bean 定义后,但在实例化 Beans 之前,您可以使用这个接口来修改或添加 Bean 定义。

  • 条件性的Bean注册:基于特定条件(比如环境变量或配置参数),动态地注册或修改 Bean。

  • 自定义注解处理:如果你需要开发自己的注解并在 Spring 上下文中处理它们,可以使用这个接口。

扩展方式

@Component
public class CustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        // 在这里添加或修改Bean定义
        RootBeanDefinition beanDefinition = new RootBeanDefinition(SomeClass.class);
        registry.registerBeanDefinition("someBeanName", beanDefinition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 可以修改已注册的Bean属性
        // 例如:设置属性,调用自定义初始化方法等
    }
}

生效方式

  • 实现接口:您需要创建一个类实现 BeanDefinitionRegistryPostProcessor 接口,并重写 postProcessBeanDefinitionRegistry 和 postProcessBeanFactory 方法。

  • 注册到Spring容器:可以通过注解(如 @Component)或在配置类中显式注册。

  • 执行顺序:首先执行 postProcessBeanDefinitionRegistry 方法,允许添加或修改 Bean 定义。随后执行 postProcessBeanFactory 方法,这一步通常用于修改已经注册的 Bean 的属性

使用案例

深入探索 Spring 16 个 Bean 生命周期扩展接口,打造高效优雅代码

BeanFactoryPostProcessor

org.springframework.beans.factory.config.BeanFactoryPostProcessor

应用场景

  • 修改或替换 Bean 定义:如果需要对 Spring 容器中的 Bean 定义进行修改或替换,可以实现此接口。
  • 环境检查或配置:在 Spring 容器实例化 beans 之前,进行一些环境的检查或者对配置信息的修改。
  • 动态注册 Bean 定义:可以动态地向 Spring 容器添加新的 Bean 定义

扩展方式

public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 在这里修改 bean 定义或执行其他逻辑
    }
}

使用案例

public class DataSourceBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    private String url;
    private String username;
    private String password;

    // 构造函数和属性的 setter

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition bd = beanFactory.getBeanDefinition("dataSource");
        MutablePropertyValues pv = bd.getPropertyValues();
        if (pv.contains("url")) {
            pv.add("url", url);
        }
        if (pv.contains("username")) {
            pv.add("username", username);
        }
        if (pv.contains("password")) {
            pv.add("password", password);
        }
    }
}

InstantiationAwareBeanPostProcessor

org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor InstantiationAwareBeanPostProcessor 继承 BeanPostProcess ,BeanPostProcess 接口只在bean的初始化阶段进行扩展(注入spring上下文前后),而InstantiationAwareBeanPostProcessor 接口在此基础上增加了3个方法,把可扩展的范围增加了实例化阶段和属性注入阶段。

应用场景

该类主要的扩展点有以下 5 个方法,主要在 bean 生命周期的两大阶段:实例化阶段和初始化阶段 ,下面一起进行说明,按调用顺序为:

  • postProcessBeforeInstantiation:实例化 bean 之前,相当于 new 这个 bean 之前,可用于修改动态环境 RocketMQ 消费者组名称,以及一些中间件 bean 属性的动态修改
  • postProcessAfterInstantiation:实例化 bean 之后,相当于 new 这个 bean 之后
  • postProcessPropertyValues:bean 已经实例化完成,在属性注入时阶段触发,@Autowired、@Resource等注解原理基于此方法实现
  • postProcessBeforeInitialization:初始化 bean 之前,相当于把 bean 注入 spring 上下文之前
  • postProcessAfterInitialization:初始化 bean 之后,相当于把 bean 注入 spring 上下文之后

扩展方式

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;

public class CustomBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        // 在实例化之前执行的逻辑
        // 例如,可以在这里返回一个代理对象
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        // 在实例化之后执行的逻辑,但在设置属性之前
        // 可以用来修改 bean 或执行某些操作
        return true;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 在初始化(例如 @PostConstruct)之前执行
        // 可以对 bean 进行修改
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 在初始化之后执行
        // 例如,可以在这里包装 bean 为一个代理
        return bean;
    }
}

使用案例

@Slf4j
public class DynamicRocketMQPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Value("${spring.profiles.active}")
    String envProfile;

    @Autowired
    Environment env;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (StringUtils.isEmpty(envProfile) || (!envProfile.contains(DynamicEnvManager.DEV_ENV) && !envProfile.contains(DynamicEnvManager.TEST_ENV))) {
            return bean;
        }

        if (bean instanceof RocketMQListener) {
            try {
                log.info("postProcessProperties bean -> {} beanName -> {}", bean, beanName);
                RocketMQListener<?> rocketMQListener = (RocketMQListener<?>) bean;
                Class<? extends RocketMQListener> rocketmqListener = rocketMQListener.getClass();

                RocketMQMessageListener annotation = rocketmqListener.getAnnotation(RocketMQMessageListener.class);

                //获取 这个代理实例所持有的 InvocationHandler
                InvocationHandler invocationHandler = Proxy.getInvocationHandler(annotation);

                // 获取 AnnotationInvocationHandler 的 memberValues 字段
                Field declaredField = invocationHandler.getClass().getDeclaredField("memberValues");

                // 因为这个字段事 private final 修饰,所以要打开权限
                declaredField.setAccessible(true);

                // 获取 memberValues
                Map memberValues = (Map) declaredField.get(invocationHandler);

                // 修改 value 属性值
                String oldConsumer = annotation.consumerGroup();

                String property = env.getProperty(DynamicEnvManager.GLOBAL_ENV_NAME);
                if (StringUtils.isBlank(property)) {
                    property = "";
                    log.error("postProcessBeforeInitialization env error property -> {}", property);
                }
                String newConsumer = oldConsumer + property;
                memberValues.put("consumerGroup", newConsumer);

                log.info("postProcessBeforeInitialization annotation -> {} oldConsumer -> {} newConsumer -> {} ", annotation, oldConsumer, newConsumer);
            } catch (Exception e) {
                log.error("postProcessBeforeInitialization consumerGroup replace error : ", e);
            }
        }
        return bean;
    }

}

SmartInstantiationAwareBeanPostProcessor

org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor

应用场景

SmartInstantiationAwareBeanPostProcessor 是 Spring 框架中一个更高级的扩展接口,提供了更细粒度的控制来干预和修改 Bean 的实例化过程。这个接口扩展了 InstantiationAwareBeanPostProcessor,增加了三个主要的方法,分别对应于 Bean 生命周期的不同阶段。以下是对这三个方法的优化建议:

  • predictBeanType: 此方法主要用于预测 Bean 的类型。当通过 Bean 名称无法确定其类型时,此方法被调用。它在实际 Bean 实例化之前提供了一种机制来推断 Bean 的类型。

  • determineCandidateConstructors:目的与应用场景: 该方法用于确定 Bean 的构造函数。这对于自定义选择合适的构造器来实例化 Bean 特别有用,尤其是在有多个构造函数的情况下。

  • getEarlyBeanReference:目的与应用场景: 该方法在 Bean 实例化后、初始化前被调用,主要用于解决循环依赖的问题,它允许在完全初始化之前提供 Bean 的早期引用。

扩展方式

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
import java.lang.reflect.Constructor;

public class CustomSmartBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {

    @Override
    public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
        // 在这里,根据beanName或beanClass预测Bean的类型
        if (beanName.equals("mySpecialBean")) {
            return MySpecialBeanImpl.class;
        }
        return null;
    }

    @Override
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
        // 在这里,可以自定义选择哪个构造器用于实例化Bean
        // 例如,根据特定条件选择合适的构造函数
        if (beanClass.equals(MyBean.class)) {
            // 尝试获取MyBean的特定构造函数
            try {
                return new Constructor<?>[] { beanClass.getConstructor(MyDependency.class) };
            } catch (NoSuchMethodException e) {
                // 处理异常
            }
        }
        return null;
    }

    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
        // 在这里处理循环依赖的场景,返回Bean的早期引用
        // 通常用于AOP代理或特殊处理
        return bean;
    }

    // 其他必要的方法实现...
}

使用案例

深入探索 Spring 16 个 Bean 生命周期扩展接口,打造高效优雅代码

BeanFactoryAware

org.springframework.beans.factory.BeanFactoryAware

应用场景

该类具有一个关键时机点,即在 Bean 实例化之后且属性注入(例如,通过 Setter 方法)之前。此时,通过重写 setBeanFactory 方法,类可以获得 BeanFactory 实例的引用。

在这个阶段,您可以对刚实例化但尚未完全初始化的 Bean 进行特殊处理。这为在 Bean 生命周期的早期阶段进行定制化操作提供了机会。此外,您也可以将 BeanFactory 实例缓存起来,以便于后续操作时重复使用,从而提高效率和灵活性。这种做法特别适用于需要根据运行时条件动态处理或检索 Bean 的场景

扩展方式

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;

public class CustomBeanFactoryAwareClass implements BeanFactoryAware {

    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
        // 执行额外的初始化或配置逻辑
        initializeCustomBeans();
    }

    private void initializeCustomBeans() {
        // 在这里,您可以使用 beanFactory 来创建或配置 Bean
        // 例如,根据条件动态创建 Bean
        if (/* 某个条件 */) {
            MyBean myBean = beanFactory.getBean(MyBean.class);
            // 使用 myBean 进行操作
        }
    }

    // 其他自定义方法...
}

ApplicationContextAwareProcessor

org.springframework.context.support.ApplicationContextAwareProcessor

应用场景

深入探索 Spring 16 个 Bean 生命周期扩展接口,打造高效优雅代码 针对您提到的ApplicationContextAwareProcessor类及其相关的六个扩展点,可以进行如下优化和概述:

  • EnvironmentAware:这个接口允许Bean获取到Spring环境相关的配置。虽然通常可以通过注入的方式直接获得环境参数,但实现这个接口可以在Bean中直接访问环境属性,有助于减少对Spring环境的直接依赖。

  • EmbeddedValueResolverAware:实现此接口使得Bean能够解析String类型的属性值。虽然@Value注解通常被用于注入属性值,但通过缓存StringValueResolver实例,可以在需要时获取这些值,提供更灵活的值解析方式。

  • ResourceLoaderAware:通过这个接口,Bean可以获得ResourceLoader,用于访问类路径内的资源。这使得Bean能够更灵活地处理外部资源,例如配置文件或类路径资源。

  • ApplicationEventPublisherAware:实现这个接口使Bean能够发布事件。虽然可以通过Spring注入来获取ApplicationEventPublisher,但直接在Bean中实现此接口可以简化事件发布流程,增强Bean的事件驱动能力。

  • MessageSourceAware:这个接口主要用于国际化支持,允许Bean访问MessageSource。这对于开发需要支持多语言的应用程序尤其重要。

  • ApplicationContextAware:通过实现这个接口,Bean可以直接访问Spring的应用程序上下文ApplicationContext。这使得Bean能够获取和操作其他Bean,以及使用上下文提供的其他功能。这对于需要进行复杂上下文操作的Bean尤为重要

扩展方式

import org.springframework.context.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.core.env.Environment;
import org.springframework.context.MessageSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringValueResolver;

public class MyAwareBean implements EnvironmentAware, EmbeddedValueResolverAware,
        ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware,
        ApplicationContextAware {

    private Environment environment;
    private StringValueResolver stringValueResolver;
    private ResourceLoader resourceLoader;
    private ApplicationEventPublisher applicationEventPublisher;
    private MessageSourceAccessor messageSourceAccessor;
    private ApplicationContext applicationContext;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.stringValueResolver = resolver;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    @Override
    public void setMessageSource(MessageSource messageSource) {
        this.messageSourceAccessor = new MessageSourceAccessor(messageSource);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    // 使用注入的依赖来实现一些业务逻辑
    public void performSomeAction() {
        // 示例:使用environment获取属性
        String dbUrl = environment.getProperty("database.url");

        // 示例:使用stringValueResolver解析字符串
        String resolvedString = stringValueResolver.resolveStringValue("some.value");

        // 示例:使用resourceLoader加载资源
        // Resource resource = resourceLoader.getResource("classpath:test.txt");

        // 示例:发布事件
        // applicationEventPublisher.publishEvent(new MyEvent(this));

        // 示例:使用messageSourceAccessor获取国际化消息
        // String message = messageSourceAccessor.getMessage("some.message.key");

        // 示例:使用applicationContext获取bean
        // MyOtherBean otherBean = applicationContext.getBean(MyOtherBean.class);
    }
}

BeanNameAware

org.springframework.beans.factory.BeanNameAware

应用场景

BeanNameAware的主要应用场景包括:

  • 日志记录:Bean可以在日志中记录自己的名字,这对于调试和跟踪Bean的创建及其在容器中的生命周期是非常有用的。

  • 依赖注入:在某些复杂的依赖注入场景中,Bean可能需要知道自己的名字来动态地处理依赖关系,尤其是在存在多个相同类型但需要不同处理的Bean时。

  • 上下文感知:对于需要根据其在容器中的角色或标识来改变行为的Bean,了解自己的名字是很重要的。例如,同一个类的不同实例可能需要根据其在Spring容器中的名字来加载不同的配置。

  • 与其他框架集成:在集成Spring与其他框架(如Quartz, Apache Camel等)时,知道Bean的名字可以帮助在框架之间传递信息,确保正确的配置和交互。

  • 测试和模拟:在测试环境中,可以利用Bean的名字进行模拟或者特定的测试设置。

扩展方式

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyCustomBean implements BeanNameAware, InitializingBean {

    private String beanName;

    @Autowired
    private SomeOtherBean someOtherBean;

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        // 在这里可以进行与bean名字相关的初始化操作
        System.out.println("Bean的名字是: " + name);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // 当所有属性被设置后,Spring会调用这个方法
        // 可以在这里执行一些初始化的逻辑
        System.out.println("正在初始化Bean: " + beanName);
    }

    // Bean的其他业务方法
    public void doSomething() {
        // 方法实现
    }

    // ... 其他可能的方法和逻辑
}

@PostConstruct

javax.annotation.PostConstruct

应用场景

  • 资源初始化:在数据库连接、读取配置文件或者初始化一些数据结构时使用。
  • 日志记录:应用启动时,记录一些启动日志或者系统状态。
  • 数据预加载:预加载一些必要的数据到缓存中。
  • 检查依赖:确保应用的某些依赖项已经准备就绪。

扩展方式

import javax.annotation.PostConstruct;

public class MyService {

    // 依赖注入的示例字段
    private DependencyClass dependency;

    public MyService(DependencyClass dependency) {
        this.dependency = dependency;
    }

    @PostConstruct
    public void init() {
        // 初始化逻辑
        System.out.println("依赖注入完成,执行初始化操作");
        // 比如,使用dependency进行一些设置或调用
    }

    // 类的其他方法...
}

InitializingBean

org.springframework.beans.factory.InitializingBean

应用场景

InitializingBean接口用于在设置完一个bean的所有属性之后执行初始化工作。实现InitializingBean接口允许bean在其属性被设置之后,但在任何启动逻辑(如数据库连接)之前执行自定义初始化逻辑。

  • 资源初始化:如数据库连接、文件系统的访问或其他需要在属性设置后进行初始化的资源。
  • 自定义配置校验:在bean的属性被注入后,检查或校验这些属性。
  • 复杂的初始化逻辑:执行复杂的初始化逻辑,这些逻辑可能依赖于多个属性

扩展方式

import org.springframework.beans.factory.InitializingBean;

public class MyService implements InitializingBean {

    // 依赖注入的示例字段
    private DependencyClass dependency;

    public void setDependency(DependencyClass dependency) {
        this.dependency = dependency;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // 执行初始化逻辑
        System.out.println("所有属性设置完成,执行初始化操作");
        // 例如,使用dependency进行一些设置或调用
    }

    // 类的其他方法...
}

注意:如果同时使用了InitializingBean接口和@PostConstruct注解,那么@PostConstruct注解的方法将在afterPropertiesSet()方法之前执行

FactoryBean

org.springframework.beans.factory.FactoryBean

应用场景

FactoryBean是一个特殊的bean类型,用于创建复杂对象。当你需要执行复杂的初始化逻辑,或者创建对象过程中需要多个步骤和配置时,使用FactoryBean可以是一个好选择。它允许你在Spring容器内部完全控制bean的创建过程。

  • 复杂对象的创建:当一个对象的创建过程非常复杂,例如需要多步构建过程或特定的配置逻辑时。
  • 依赖注入之外的控制:如果需要在标准依赖注入之外控制对象的创建逻辑。
  • 单例与非单例的管理:可以灵活地创建单例或原型(非单例)对象。
  • 创建特定类型的资源:例如连接到特定服务的代理或特殊类型的资源。

扩展方式

import org.springframework.beans.factory.FactoryBean;

public class MyFactoryBean implements FactoryBean<MyObject> {

    @Override
    public MyObject getObject() throws Exception {
        // 创建并返回一个MyObject实例
        MyObject myObject = new MyObject();
        // 可以在这里进行复杂的构建逻辑
        return myObject;
    }

    @Override
    public Class<?> getObjectType() {
        // 返回创建对象的类型
        return MyObject.class;
    }

    @Override
    public boolean isSingleton() {
        // 控制是否单例
        // 返回true表示创建的对象是单例
        // 返回false表示创建的对象是非单例
        return true;
    }

    // 其他可能的自定义方法或逻辑...
}

SmartInitializingSingleton

org.springframework.beans.factory.SmartInitializingSingleton

应用场景

SmartInitializingSingleton接口主要用于在单例bean的全部依赖关系都被满足后执行特定的逻辑。这个接口通常用于在Spring容器的启动阶段的最后一步,所有单例bean都已经创建且依赖关系已经注入后,执行一些后处理操作。

  • 后处理逻辑:在所有单例bean初始化完成之后执行一些后处理操作,例如数据校验、缓存预热等。
  • 依赖于多个Bean的初始化:当你的逻辑需要确保多个其他bean已经初始化完成时使用。
  • 异步操作的启动:如启动异步任务,当所有必要的bean都已经准备好。
  • 复杂的启动流程:例如,当应用需要在启动时执行一系列复杂的初始化步骤

扩展方式

import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.stereotype.Component;

@Component
public class MySmartSingleton implements SmartInitializingSingleton {

    // 依赖注入的其他Bean
    private final AnotherBean anotherBean;

    public MySmartSingleton(AnotherBean anotherBean) {
        this.anotherBean = anotherBean;
    }

    @Override
    public void afterSingletonsInstantiated() {
        // 执行一些后处理逻辑
        System.out.println("所有单例Bean都已经初始化,执行特定操作");
        // 可以使用anotherBean进行一些操作
    }

    // 其他方法...
}

CommandLineRunner

org.springframework.boot.CommandLineRunner

应用场景

CommandLineRunner接口用于在Spring应用启动后执行特定的代码。它提供了一种简单的方法来访问命令行参数,并在Spring应用上下文加载完成后立即执行一些操作。

  • 命令行参数处理:解析和处理传递给Spring应用的命令行参数。
  • 启动时数据初始化:在应用启动时加载数据,例如从文件读取数据或者数据库初始化。
  • 启动后的检查:进行一些启动后的健康检查或者环境检查。
  • 启动任务:如启动一个定时任务或触发一些仅需执行一次的操作。

扩展方式

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class MyCommandLineRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        // 执行一些启动逻辑
        System.out.println("Spring应用已启动,执行命令行处理");
        // args包含传递给应用程序的命令行参数
        for (String arg : args) {
            System.out.println(arg);
        }
    }

    // 其他方法...
}

DisposableBean

org.springframework.beans.factory.DisposableBean

应用场景

DisposableBean接口用于在bean的生命周期结束时执行清理工作,比如释放资源或执行其他清理操作。这通常用于在bean不再需要时,确保以优雅的方式释放资源,如关闭数据库连接、释放文件句柄等。

  • 资源释放:关闭打开的资源,例如文件流、数据库连接、网络连接等。
  • 停止后台线程:如果bean启动了任何后台线程,可以在销毁时停止这些线程。
  • 缓存清理:清理任何持久化的缓存或临时数据。
  • 注销注册:如果bean在系统或服务中进行了注册,可以在销毁时注销

扩展方式

import org.springframework.beans.factory.DisposableBean;
import org.springframework.stereotype.Component;

@Component
public class MyDisposableBean implements DisposableBean {

    @Override
    public void destroy() throws Exception {
        // 执行清理操作
        System.out.println("Bean正在被销毁,执行清理操作");
        // 这里可以释放资源,如关闭文件流或数据库连接
    }

    // 其他方法...
}

ApplicationListener

org.springframework.context.ApplicationListener

应用场景

ApplicationListener接口用于实现事件监听机制。这个接口允许应用对各种应用事件(如上下文事件、请求处理事件等)作出响应。它是基于观察者设计模式的实现,允许你在特定事件发生时执行自定义的逻辑。

  • 上下文事件监听:监听如上下文初始化、关闭等事件。
  • 自定义事件处理:处理自定义定义的业务事件。
  • 监控与日志:对特定事件进行监控或记录日志。
  • 性能跟踪:追踪应用的关键操作,如请求的处理时间。

扩展方式

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

@Component
public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        // 执行一些逻辑,例如在上下文刷新时
        System.out.println("Spring上下文刷新事件被触发");
        // 这里可以访问事件源,例如event.getApplicationContext()
    }

    // 其他方法...
}

转载自:https://juejin.cn/post/7315846728732901414
评论
请登录