深入探索 Spring 16 个 Bean 生命周期扩展接口

背景

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

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

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

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

在这里插入图片描述

ApplicationContextInitializer

org.springframework.context.ApplicationContextInitializer

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

应用场景

  • 定制应用上下文配置:通过实现 ApplicationContextInitializer 接口,可以在 Spring 容器加载任何 bean 定义之前调用自定义逻辑,从而允许对配置进行编程式的修改。在应用启动前检查或准备外部资源,如消息队列
  • 环境依赖的设置:它常用于根据不同的环境(如开发、测试、生产)设置不同的配置参数。例如,可以根据不同的配置文件或环境变量来调整数据源设置。如:根据环境变量动态设置数据库连接参数
  • 与 Spring Profiles 集成:可以在 ApplicationContextInitializer 中激活或修改 Spring Profiles,从而改变应用程序的行为和配置。
  • 动态字节码注入:利用这时候class还没被类加载器加载的时机,进行动态字节码注入等操作

扩展方式

1
2
3
4
5
6
java复制代码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

使用案例

在这里插入图片描述

BeanDefinitionRegistryPostProcessor

org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor

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

应用场景

  • 修改或增加Bean定义:在 Spring 容器加载了 Bean 定义后,但在实例化 Beans 之前,您可以使用这个接口来修改或添加 Bean 定义。
  • 条件性的Bean注册:基于特定条件(比如环境变量或配置参数),动态地注册或修改 Bean。
  • 自定义注解处理:如果你需要开发自己的注解并在 Spring 上下文中处理它们,可以使用这个接口。

扩展方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
java复制代码@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 的属性

使用案例

在这里插入图片描述

BeanFactoryPostProcessor

org.springframework.beans.factory.config.BeanFactoryPostProcessor

应用场景

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

扩展方式

1
2
3
4
5
6
7
java复制代码public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

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

使用案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
java复制代码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 上下文之后

扩展方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
java复制代码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;
}
}

使用案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
java复制代码@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 的早期引用。

扩展方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
java复制代码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;
}

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

使用案例

在这里插入图片描述

BeanFactoryAware

org.springframework.beans.factory.BeanFactoryAware

应用场景

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

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

扩展方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
java复制代码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

应用场景

在这里插入图片描述
针对您提到的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尤为重要

扩展方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
java复制代码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的名字进行模拟或者特定的测试设置。

扩展方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
java复制代码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

应用场景

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

扩展方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
java复制代码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的属性被注入后,检查或校验这些属性。
  • 复杂的初始化逻辑:执行复杂的初始化逻辑,这些逻辑可能依赖于多个属性

扩展方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
java复制代码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的创建过程。

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

扩展方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
java复制代码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都已经准备好。
  • 复杂的启动流程:例如,当应用需要在启动时执行一系列复杂的初始化步骤

扩展方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
java复制代码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应用的命令行参数。
  • 启动时数据初始化:在应用启动时加载数据,例如从文件读取数据或者数据库初始化。
  • 启动后的检查:进行一些启动后的健康检查或者环境检查。
  • 启动任务:如启动一个定时任务或触发一些仅需执行一次的操作。

扩展方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
java复制代码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在系统或服务中进行了注册,可以在销毁时注销

扩展方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
java复制代码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接口用于实现事件监听机制。这个接口允许应用对各种应用事件(如上下文事件、请求处理事件等)作出响应。它是基于观察者设计模式的实现,允许你在特定事件发生时执行自定义的逻辑。

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

扩展方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
java复制代码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()
}

// 其他方法...
}

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%