ApplicationContextInitializer的initialize方法。
时机 : 所有的配置文件都已经加载,spring容器还没被刷新之前 准备阶段 this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
它允许开发人员在Spring应用上下文(ApplicationContext)被创建和刷新之前,对上下文进行自定义的初始化设置。通过实现ApplicationContextInitializer接口,您可以执行以下类型的自定义功能:
-
定制ApplicationContext配置:
- 添加或修改ApplicationContext的属性。
- 设置环境变量(Environment)或系统属性。
- 注册自定义的
PropertySources,以便在上下文初始化时注入自定义的属性值。
-
注册额外的Bean Definition:
- 在Spring IoC容器初始化之前预先注册自定义的Bean,这样在容器启动时就可用。
- 注册自定义的
BeanPostProcessor、Advisor等,用于增强或修改容器中其他Bean的行为。
-
定制资源加载:
修改上下文的资源加载策略,例如添加自定义的ResourceLoader或修改其默认行为。 -
初始化第三方库或中间件:
初始化与Spring容器一起使用的第三方库或中间件,例如数据库连接池、缓存服务、消息队列客户端等。 -
初始化应用级基础设施:
设置应用启动时所需的基础设施,如初始化日志框架、加密服务、国际化设置等。 -
执行特定的初始化逻辑:
执行一次性的初始化动作,比如配置系统层面的设定、读取外部配置文件并注入到环境中等。
示例代码如下:
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.core.env.ConfigurableEnvironment;
public class CustomApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// 获取环境对象
ConfigurableEnvironment environment = applicationContext.getEnvironment();
// 设置或修改环境属性
environment.getPropertySources().addFirst(new MyCustomPropertySource());
// 注册自定义的Bean
applicationContext.registerBean("customBean", CustomBean.class);
// 执行其他初始化逻辑
// ...
}
}
BeanDefinitionRegistryPostProcessor
refresh()的 this.invokeBeanFactoryPostProcessors(beanFactory);此时此bean的定义信息 都已经加载完毕 但是还没到实例化以及初始化阶段。
主要用于在Spring IoC容器初始化过程中对Bean定义进行进一步的加工或扩展,可以拓展的功能包括但不限于:
-
添加自定义Bean定义:
在容器完成所有默认的Bean定义扫描和注册之后,但在任何Bean实例化之前,可以动态地向容器中注册新的Bean定义,这对于实现动态扩展Bean的集合非常有用。 -
修改现有的Bean定义:
改变Bean的属性,如修改构造函数参数、修改Bean的scope(作用域)、修改初始化方法或销毁方法等。 -
删除不必要的Bean定义:
根据运行时条件或配置,可以选择性地移除已经注册的Bean定义,避免某些Bean实例化和初始化。 -
调整Bean之间的依赖关系:
动态地更改Bean之间的依赖关系,例如添加额外的depends-on属性,确保Bean按期望的顺序初始化。 -
配置元数据处理:
处理基于注解的Bean定义,例如解析自定义注解并据此更新Bean定义的元数据。 -
处理第三方库或遗留系统的Bean定义:
当第三方库没有使用Spring的@Component注解,但又需要纳入Spring容器管理时,可以使用BeanDefinitionRegistryPostProcessor来注册这些类为Spring Bean。
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
@Configuration
public class CustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 注册新的Bean定义
GenericBeanDefinition customBeanDef = new GenericBeanDefinition();
customBeanDef.setBeanClass(CustomBean.class);
registry.registerBeanDefinition("customBean", customBeanDef);
// 修改已有Bean定义
BeanDefinition existingBeanDef = registry.getBeanDefinition("someExistingBean");
existingBeanDef.setAttribute("customAttribute", "newValue");
// 删除Bean定义
if (registry.containsBeanDefinition("toBeDeletedBean")) {
registry.removeBeanDefinition("toBeDeletedBean");
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 此方法也可以进行一些工厂级别的后处理,但主要用于处理BeanFactory而非BeanDefinitionRegistry
}
}
我们老是讲BeanDefinition,那么它是啥呢?
BeanDefinition是IoC(Inversion of Control,控制反转)容器的基本组成单元,它描述了Spring容器中Bean的元信息。每个由Spring容器管理的Bean都有一个对应的BeanDefinition对象,它包含了Bean的所有必要配置信息,如:
- Bean 类型(Class):定义了Bean的具体实现类。
- 作用域(Scope):定义了Bean的生命周期模式,如singleton(单例)或prototype(原型)。
- 构造器参数和属性值:Bean依赖的其他Bean,或者是直接的属性值。
- 初始化方法和销毁方法:定义了Bean实例化后要调用的初始化方法和容器关闭前要调用的销毁方法。
- 是否懒加载:指示Bean是否应在首次请求时才创建实例。
- 自定义属性:其他用户自定义的属性信息。
bean是怎么变成beandefinition的呢?Spring容器在启动和初始化过程中,会将各种来源的Bean配置信息转换成BeanDefinition对象,主要包括以下几个步骤:
-
XML配置文件:
当使用XML配置方式时,Spring容器读取XML配置文件,通过BeanDefinitionParserDelegate等组件解析XML标签,将标签内的配置信息转换成BeanDefinition对象。 -
注解驱动配置:
当使用注解如@Component、@Service、@Repository、@Controller等进行配置时,Spring通过组件扫描(@ComponentScan)自动检测到带有这些注解的类,并使用ClassPathBeanDefinitionScanner或其他类似组件将类转换成对应的BeanDefinition。 -
Java配置类:
在Java配置类(如带有@Configuration注解的类)中,通过@Bean注解的方法声明的Bean,Spring会自动处理这些方法并将方法体中的逻辑转换成BeanDefinition。Spring Boot中ConfigurationClassPostProcessor会处理这些Java配置类。 -
手动注册:
在代码中手动创建GenericBeanDefinition等BeanDefinition子类实例,填充相关信息后,通过DefaultListableBeanFactory或其他BeanDefinitionRegistry接口的实现注册到Spring容器。
BeanFactoryPostProcessor
允许开发者在Bean实例化之前对Spring IoC容器中的Bean定义进行修改和扩展。通过实现BeanFactoryPostProcessor接口,您可以拓展以下功能:
-
修改Bean属性:
动态修改Bean定义中的属性值,例如修改构造器参数值、属性值、初始化方法、销毁方法等。 -
自定义Bean作用域:
更改Bean的作用域(Scope),如将Singleton Bean改为Prototype Bean,或者自定义作用域。 -
注入额外的依赖:
动态地向Bean定义中注入额外的依赖,而不必在代码中显式声明。 -
配置属性替换:
能够根据运行时环境或配置文件动态替换Bean定义中的占位符属性值。 -
实现Bean的动态代理:
可以在Bean实例化前为其生成代理类,添加额外的横切逻辑,如AOP(面向切面编程)的增强功能。 -
处理遗留系统的Bean定义:
对于一些不遵循Spring规范的遗留系统,可以通过BeanFactoryPostProcessor将遗留系统中的类注册为Spring Bean,并进行必要的配置。 -
整合第三方库配置:
在Bean实例化前,整合第三方库的相关配置,将其无缝融入Spring IoC容器的管理。
示例代码:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
// 示例:修改某Bean定义的属性值
if ("someBean".equals(beanName)) {
bd.getPropertyValues().addPropertyValue("propertyName", "newPropertyValue");
}
}
}
}
那么BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor看起来好像是,有啥区别呢?BeanDefinitionRegistryPostProcessor 它继承了 BeanFactoryPostProcessor 接口。
BeanFactoryPostProcessor:
- 主要功能:允许开发人员在 Spring 容器完成所有标准 Bean 定义的读取之后但在任何 Bean 实例化之前修改这些 Bean 定义。
- 改动范围:可以修改现有 Bean 定义的各种属性,包括但不限于构造函数参数、属性值、依赖关系等。
- 应用场景:例如,可以用来替代配置文件中的占位符属性值,或者进行全局性的属性设置。
BeanDefinitionRegistryPostProcessor:
- 扩展功能:除了具有
BeanFactoryPostProcessor的能力之外,还能够注册新的 Bean 定义。 - 特殊权限:它可以直接操作
BeanDefinitionRegistry,这意味着可以在初始化过程的更早阶段添加或删除 Bean 定义。 - 应用场景:当需要动态添加、移除或修改整个 Bean 定义集合时特别有用,比如在扫描特定包下带有自定义注解的类并将其自动注册为 Spring Bean 的场景。
总结来说,两者的主要区别在于:
BeanFactoryPostProcessor更专注于修改已有的 Bean 定义属性。BeanDefinitionRegistryPostProcessor不仅能修改,还能在 Spring 容器构建过程中增加新的 Bean 定义,提供了更高的定制化程度。
执行顺序方面,BeanDefinitionRegistryPostProcessor 先于 BeanFactoryPostProcessor 执行。这样设计的原因在于,确保在 Bean 定义的最终集合形成后,再给所有 Bean 定义提供一个统一修改的机会。最后,所有经过这些后置处理器处理过的 Bean 定义才会被用来创建实际的 Bean 实例。
BeanPostProcessor
它允许开发者在 Spring 容器创建 Bean 实例后,但在 Bean 初始化前后对其进行自定义处理。通过实现 BeanPostProcessor 接口,可以拓展以下功能:
-
字段注入或方法调用:
在 Bean 初始化之前或之后添加额外的属性注入,或者调用自定义方法。 -
AOP 切面增强:
实现面向切面编程(AOP),在 Bean 创建后,对其进行代理,添加横切关注点,如事务管理、日志记录、权限控制等。 -
对象包装:
将 Bean 包装成代理对象,以实现在调用 Bean 方法时附加额外的逻辑。 -
懒加载优化:
实现自定义的懒加载策略,延迟某些 Bean 的初始化时间点。 -
属性修改:
在 Bean 初始化前后,修改 Bean 实例的属性值。 -
初始化前后自定义逻辑:
在 Bean 初始化前后执行自定义的初始化或清理逻辑。 -
自定义依赖注入:
根据自定义逻辑动态注入 Bean 的依赖,而非仅依赖于 Spring 的默认注入机制。
具体实现这两个方法:
-
Object postProcessBeforeInitialization(Object bean, String beanName): 在 Bean 初始化(调用 InitializingBean 接口的afterPropertiesSet()方法或 @PostConstruct 注解的方法)之前调用。 -
Object postProcessAfterInitialization(Object bean, String beanName): 在 Bean 初始化之后调用,但在 Bean 准备好被应用上下文使用之前调用。
如下例子将展示如何在 Spring 容器中创建 Bean 实例之后对其内容进行自定义操作。这里我们将创建一个简单的后处理器,它会打印 Bean 的名称和类名,并对具有特定注解的 Bean 进行额外处理。
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.stream.Collectors;
@Component
public class LoggingBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean '" + beanName + "' is being created. Bean class: " + bean.getClass().getName());
// 检查Bean是否带有特定注解,如果有,则进行特殊处理
if (bean.getClass().isAnnotationPresent(MySpecialAnnotation.class)) {
// 假设MySpecialAnnotation注解存在并有一些自定义逻辑
processSpecialBean(bean);
}
return bean; // 返回未经修改的原始Bean对象,也可以返回一个包装过的Bean
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean '" + beanName + "' has been initialized.");
return bean; // 返回未经修改的原始Bean对象,同样可以返回一个包装过的Bean
}
private void processSpecialBean(Object bean) {
// 假设这里的逻辑是对标注了MySpecialAnnotation的Bean的字段进行赋值或其它操作
Class<?> clazz = bean.getClass();
Arrays.stream(clazz.getDeclaredFields())
.filter(field -> field.isAnnotationPresent(MySpecialAnnotation.class))
.forEach(field -> {
try {
field.setAccessible(true);
// 这里进行自定义的字段赋值或其他操作
// ...
} catch (IllegalAccessException e) {
throw new RuntimeException("Error processing annotated field in bean", e);
}
});
}
// 假设的自定义注解
@interface MySpecialAnnotation {
// 注解的属性...
}
}
InitializingBean
允许我们在 Bean 实例化后和依赖注入完成后,被其他bean依赖或者执行前执行一些自定义的初始化逻辑。通过实现 InitializingBean 接口,可以拓展以下功能:
-
自定义初始化操作:
执行额外的数据校验、初始化状态设置、与其他Bean交互或建立内部依赖关系等操作。 -
执行一次性初始化任务:
在Bean准备就绪投入服务之前,执行必需的一次性初始化任务,如打开数据库连接、初始化缓存、设置定时任务等。 -
注入后处理:
当依赖注入完成后,可以基于注入的属性执行一些初始化逻辑。
具体执行顺序如下:
- Spring 容器创建 Bean 实例。
- 容器对 Bean 进行依赖注入(DI),也就是填充所有通过 Setter 方法、构造函数或其他注解标记的属性。
- 如果 Bean 实现了
InitializingBean接口,Spring 容器接下来会调用afterPropertiesSet()方法。 - 如果 Bean 上使用了
@PostConstruct注解的方法,这些方法将在InitializingBean.afterPropertiesSet()之后执行。 - 如果 Bean 在 XML 配置中或通过
@Configuration类定义了一个 init-method,那么这个 init-method 方法也会在这之后执行。
下面是一个简单的 InitializingBean 接口实现的例子:
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
@Component
public class MyComponent implements InitializingBean {
private String property1;
private int property2;
// 通过@Autowired注解或者其他方式注入属性
public void setProperty1(String property1) {
this.property1 = property1;
}
public void setProperty2(int property2) {
this.property2 = property2;
}
@Override
public void afterPropertiesSet() throws Exception {
// 在所有属性注入完成后,执行自定义的初始化逻辑
System.out.println("MyComponent has been instantiated with property1=" + property1 + " and property2=" + property2);
// 模拟一个初始化操作,比如初始化数据库连接
// ...
// 或者进行数据验证
if (property1 == null || property1.isEmpty()) {
throw new IllegalArgumentException("Property1 must not be empty!");
}
}
}
@PostConstruct , @PreDestroy
@PostConstruct:
- 该注解用于标记在一个无参的实例方法上,表示在依赖注入完成后,但在 Bean 正式投入使用(即任何业务方法被调用前)时执行的方法。
- 这个注解的方法通常用于初始化 Bean 的内部状态,如数据库连接、初始化缓存、加载配置等。
- 示例:
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;
@Component
public class MyComponent {
@PostConstruct
public void init() {
System.out.println("Bean is being initialized...");
// 执行初始化逻辑
}
// ...其他方法
}
@PreDestroy:
- 该注解用于标记在一个无参的实例方法上,表示在 Bean 生命周期结束时,即将从 Spring 容器中移除之前执行的方法。
- 这个注解的方法通常用于资源清理,如关闭数据库连接、清除缓存、保存状态、发送关闭通知等。
- 示例:
import javax.annotation.PreDestroy;
import org.springframework.stereotype.Component;
@Component
public class MyComponent {
// ...其他方法
@PreDestroy
public void cleanup() {
System.out.println("Bean is about to be destroyed...");
// 执行资源清理逻辑
}
}
注意:在 Spring 中,@PostConstruct 和 @PreDestroy 注解的方法的执行顺序优先级高于 InitializingBean 和 DisposableBean 接口中的 afterPropertiesSet() 和 destroy() 方法,以及在 XML 配置中定义的 init-method 和 destroy-method。
BeanNameAware
BeanNameAware 是 Spring Framework 提供的一个接口,允许 Bean 实例了解自己在 Spring 容器中的 bean 名称。当一个类实现了 BeanNameAware 接口后,Spring 容器在实例化该 Bean 并注入其属性后,会调用 setBeanName() 方法,传递给 Bean 其在 Spring 配置文件中定义的 bean 名称。
示例:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
public class MyBean implements BeanNameAware {
private String myBeanName;
@Override
public void setBeanName(String name) {
this.myBeanName = name;
System.out.println("Bean Name is: " + name);
}
// ...其他方法
}
在上面的例子中,当 Spring 容器创建 MyBean 实例时,会自动调用 setBeanName() 方法,将当前 Bean 的名字传递给 myBeanName 字段。这个特性在一些需要知道自身 Bean 名称以进行特定逻辑处理的场景中会很有用。
InstantiationAwareBeanPostProcessor
它扩展了 BeanPostProcessor 接口,提供了在 Bean 实例化阶段进行介入和定制的能力。通过实现 InstantiationAwareBeanPostProcessor 接口,除非有特殊情况,否则Spring容器中大部分由Spring管理创建的Bean在实例化过程中都会受到InstantiationAwareBeanPostProcessor的监测和处理,可以实现以下功能:
-
自定义实例化过程:
通过重写postProcessBeforeInstantiation(Class<?> beanClass, String beanName)方法,在 Spring 创建 Bean 实例之前有机会自定义实例化过程,甚至可以返回一个自定义的 Bean 实例,从而替代 Spring 默认的实例化过程。 -
修改初始化后的 Bean 实例:
同样作为BeanPostProcessor的一部分,可以重写postProcessBeforeInitialization(Object bean, String beanName)和postProcessAfterInitialization(Object bean, String beanName)方法,在 Bean 初始化前后进行自定义处理。 -
决定是否提前暴露早期引用:
通过实现getEarlyBeanReference(Object bean, String beanName)方法,可以在 Bean 初始化之前决定是否提前暴露该 Bean 的早期引用给其他 Bean 使用。 -
AOP(面向切面编程)支持:
在某些情况下,例如在实现 AOP 代理时,需要在 Bean 实例化阶段就能创建代理对象,而不是等待常规的 Bean 初始化阶段。InstantiationAwareBeanPostProcessor为此类场景提供了支持。
示例:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
public class CustomInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (YourCustomCondition.check(beanClass)) {
return new YourCustomBeanImplementation();
}
return null; // 返回null表示仍然使用Spring默认的实例化方式
}
// ...其他BeanPostProcessor方法的实现
}
InstantiationAwareBeanPostProcessor 相对于 BeanPostProcessor 提供了更早的介入时机,允许在 Bean 实例化阶段就进行自定义处理。通过实现 InstantiationAwareBeanPostProcessor,可以实现诸如自定义实例化过程、提前修改属性值等高级定制需求。
它们在作用时机上有微妙的区别:
-
BeanPostProcessor:
BeanPostProcessor接口提供了在 Spring 容器创建 Bean 实例并完成依赖注入之后,但在调用初始化方法(如@PostConstruct注解的方法或者InitializingBean接口的afterPropertiesSet()方法)之前和之后执行自定义逻辑的机会。- 有两个关键方法:
postProcessBeforeInitialization(Object bean, String beanName):在 Bean 初始化前调用。postProcessAfterInitialization(Object bean, String beanName):在 Bean 初始化后调用。
-
InstantiationAwareBeanPostProcessor:
InstantiationAwareBeanPostProcessor是BeanPostProcessor的一个子接口,它在 Bean 实例化阶段提供了更多的介入点。- 在 Bean 实例化前后,除了拥有
BeanPostProcessor的全部功能外,还提供了如下方法:postProcessBeforeInstantiation(Class<?> beanClass, String beanName):在 Spring 实际创建 Bean 实例之前调用。如果这个方法返回非空对象,那么 Spring 将不再使用默认的实例化策略,而是使用返回的对象作为 Bean 实例。postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName):在实例化后、初始化前修改 Bean 属性值的阶段调用,允许在注入属性值之后,初始化方法调用之前修改属性值。










