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> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {// 获取环境对象ConfigurableEnvironment environment = applicationContext.getEnvironment();// 设置或修改环境属性environment.getPropertySources().addFirst(new MyCustomPropertySource());// 注册自定义的BeanapplicationContext.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 {@Overridepublic 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");}}@Overridepublic 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 {@Overridepublic 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 {@Overridepublic 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}@Overridepublic 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;}@Overridepublic 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 {@PostConstructpublic 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 {// ...其他方法@PreDestroypublic 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;@Overridepublic 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 {@Overridepublic 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 属性值的阶段调用,允许在注入属性值之后,初始化方法调用之前修改属性值。