Appearance
customizeBeanFactory方法扩展点
一、customizeBeanFactory的定位:容器初始化流程中的关键节点
customizeBeanFactory是AbstractRefreshableApplicationContext类中的protected方法,属于Spring容器初始化流程中BeanFactory定制的核心扩展点。其调用链路如下:
1. 容器初始化入口:refresh()方法
Spring ApplicationContext的初始化核心是AbstractApplicationContext#refresh()方法,该方法定义了容器启动的标准流程(共12个步骤)。其中,获取/刷新BeanFactory是第2步(obtainFreshBeanFactory())。
2. 刷新BeanFactory:refreshBeanFactory()
obtainFreshBeanFactory()会调用AbstractRefreshableApplicationContext#refreshBeanFactory(),该方法负责销毁旧BeanFactory(若存在)、创建新BeanFactory并加载Bean定义。其关键逻辑如下:
java
@Override
protected final void refreshBeanFactory() throws BeansException {
// 1. 销毁旧BeanFactory(若已存在)
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 2. 创建新的DefaultListableBeanFactory(Spring默认的BeanFactory实现)
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId()); // 设置序列化ID,用于跨JVM反序列化
// 3. 定制BeanFactory(扩展点:子类重写此方法)
customizeBeanFactory(beanFactory);
// 4. 加载Bean定义(如XML、注解、配置类等)
loadBeanDefinitions(beanFactory);
// 5. 保存BeanFactory实例
this.beanFactory = beanFactory;
} catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source", ex);
}
}3. 定制BeanFactory:customizeBeanFactory()
customizeBeanFactory()是refreshBeanFactory()中的第3步,位于BeanFactory创建之后、Bean定义加载之前。其作用是允许子类修改BeanFactory的配置,如全局属性、类型转换器、Scope等。
二、customizeBeanFactory的默认实现与核心作用
AbstractRefreshableApplicationContext中customizeBeanFactory()的默认实现如下:
java
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
// 1. 设置是否允许Bean定义覆盖(默认:true)
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 2. 设置是否允许循环引用(默认:true)
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}1. 核心作用1:控制Bean定义覆盖(allowBeanDefinitionOverriding)
- 默认值:
true(允许同名Bean定义覆盖,后定义的Bean会覆盖前定义的)。 - 场景:若需禁止同名Bean覆盖(如防止配置错误),可将其设为
false,此时重复定义会抛出BeanDefinitionStoreException。 - 源码逻辑:
DefaultListableBeanFactory#registerBeanDefinition()会检查该属性,若为false且存在同名Bean定义,则抛出异常。
2. 核心作用2:控制循环引用(allowCircularReferences)
- 默认值:
true(允许循环引用,如A依赖B、B依赖A)。 - 场景:若需禁止循环引用(如避免复杂依赖导致的初始化问题),可将其设为
false,此时循环引用会抛出BeanCurrentlyInCreationException。 - 源码逻辑:
DefaultListableBeanFactory#doCreateBean()会根据该属性决定是否提前暴露半成品Bean(addSingletonFactory()),以解决循环引用。
三、customizeBeanFactory的扩展场景:除了默认属性,还能做什么?
customizeBeanFactory()的价值远不止修改默认的两个属性,它允许开发者深度定制BeanFactory,满足各种复杂需求。以下是常见的扩展场景:
1. 注册自定义Scope(如线程范围、会话范围)
Scope用于定义Bean的生命周期(如singleton、prototype)。通过beanFactory.registerScope()可注册自定义Scope,例如线程范围(SimpleThreadScope):
java
@Override
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
super.customizeBeanFactory(beanFactory);
// 注册线程范围的Scope(key为"thread")
beanFactory.registerScope("thread", new SimpleThreadScope());
}使用场景:需为每个线程创建独立的Bean实例(如Controller中的线程局部变量)。
2. 添加自定义ConversionService(类型转换)
ConversionService用于将配置中的字符串(如XML/注解中的值)转换为目标类型(如String→LocalDate)。通过beanFactory.setConversionService()可添加自定义转换器:
java
@Override
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
super.customizeBeanFactory(beanFactory);
// 创建默认转换服务
DefaultConversionService conversionService = new DefaultConversionService();
// 添加自定义转换器(String→LocalDate)
conversionService.addConverter(new Converter<String, LocalDate>() {
@Override
public LocalDate convert(String source) {
return LocalDate.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
}
});
// 设置转换服务
beanFactory.setConversionService(conversionService);
}使用场景:需自定义类型转换规则(如日期格式、枚举转换)。
3. 设置自定义BeanExpressionResolver(SpEL扩展)
BeanExpressionResolver用于解析SpEL表达式(如@Value("#{systemProperties['user.name']}"))。通过beanFactory.setBeanExpressionResolver()可扩展SpEL功能:
java
@Override
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
super.customizeBeanFactory(beanFactory);
// 创建标准SpEL解析器
StandardBeanExpressionResolver resolver = new StandardBeanExpressionResolver();
// 扩展SpEL:添加自定义函数(如"myFunction")
ExpressionParser parser = new SpelExpressionParser();
parser.getConfiguration().addFunction("myFunction", MyUtil.class.getMethod("myMethod", String.class));
resolver.setExpressionParser(parser);
// 设置表达式解析器
beanFactory.setBeanExpressionResolver(resolver);
}使用场景:需在SpEL中调用自定义函数(如加密/解密、字符串处理)。
4. 手动注册BeanPostProcessor
BeanPostProcessor用于拦截Bean的初始化过程(如@Autowired注入、@PostConstruct处理)。虽然通常通过@Component注册,但也可在customizeBeanFactory()中手动添加:
java
@Override
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
super.customizeBeanFactory(beanFactory);
// 手动注册自定义BeanPostProcessor(无需@Component注解)
beanFactory.addBeanPostProcessor(new CustomBeanPostProcessor());
}注意:手动注册的BeanPostProcessor不会参与Spring的排序(如@Order注解),执行顺序为添加顺序。
5. 修改BeanFactory的类加载器
通过beanFactory.setBeanClassLoader()可设置自定义类加载器(如加载外部Jar包中的类):
java
@Override
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
super.customizeBeanFactory(beanFactory);
// 设置类加载器为当前线程的上下文类加载器(常用于动态加载类)
beanFactory.setBeanClassLoader(Thread.currentThread().getContextClassLoader());
}四、customizeBeanFactory与其他扩展点的区别
为了更清晰地理解customizeBeanFactory的定位,我们将其与Spring中其他常见扩展点对比:
| 扩展点 | 触发时机 | 核心作用 | 示例场景 |
|---|---|---|---|
customizeBeanFactory | BeanFactory创建后,Bean定义加载前 | 定制BeanFactory的全局配置 | 修改allowBeanDefinitionOverriding、注册Scope |
BeanFactoryPostProcessor | Bean定义加载后,Bean实例化前 | 修改Bean定义(如属性值) | 修改@Value中的占位符 |
BeanPostProcessor | Bean实例化后,初始化前后 | 拦截Bean初始化(如注入) | 处理@Autowired注解 |
InitializingBean | Bean初始化完成后 | 执行Bean的自定义初始化逻辑 | 初始化数据库连接 |
五、customizeBeanFactory的实践案例:禁止Bean定义覆盖
假设我们需要禁止同名Bean定义覆盖(防止配置错误),可通过以下步骤实现:
1. 自定义ApplicationContext
继承AbstractRefreshableApplicationContext(或其子类,如AnnotationConfigApplicationContext),重写customizeBeanFactory():
java
public class NoOverrideApplicationContext extends AnnotationConfigApplicationContext {
@Override
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
super.customizeBeanFactory(beanFactory);
// 禁止Bean定义覆盖(设为false)
beanFactory.setAllowBeanDefinitionOverriding(false);
}
}2. 使用自定义ApplicationContext启动容器
java
@SpringBootApplication
public class Application {
public static void main(String[] args) {
// 使用自定义ApplicationContext启动Spring Boot
SpringApplication application = new SpringApplication(Application.class);
application.setApplicationContextClass(NoOverrideApplicationContext.class);
application.run(args);
}
}3. 测试效果
若存在同名Bean定义(如两个@Component("user")),容器启动时会抛出BeanDefinitionStoreException:
org.springframework.beans.factory.BeanDefinitionStoreException:
Cannot register bean definition [Root bean: class [com.example.User]; scope=singleton; ...]
for bean 'user': There is already [Root bean: class [com.example.User]; scope=singleton; ...] bound.六、注意事项
- 调用时机:
customizeBeanFactory()在loadBeanDefinitions()之前执行,此时Bean定义尚未加载,无法获取Bean实例(如beanFactory.getBean())。 - BeanFactory类型:
customizeBeanFactory()的参数是DefaultListableBeanFactory(Spring默认的BeanFactory实现),若需使用自定义BeanFactory,可重写createBeanFactory()方法(如返回CustomBeanFactory子类)。 - 属性默认值:
allowBeanDefinitionOverriding和allowCircularReferences的默认值为true,若未修改,customizeBeanFactory()不会改变其值。 - 扩展边界:
customizeBeanFactory()主要用于定制BeanFactory的配置,而非修改Bean定义(后者应使用BeanFactoryPostProcessor)。
七、总结
customizeBeanFactory是Spring容器初始化过程中最早期的扩展点之一,其核心价值在于允许开发者深度定制BeanFactory的全局配置。通过重写该方法,我们可以:
- 控制Bean定义覆盖和循环引用;
- 注册自定义Scope、ConversionService、BeanExpressionResolver;
- 手动添加BeanPostProcessor;
- 修改类加载器等。
理解customizeBeanFactory的底层逻辑与应用场景,有助于我们在Spring框架中实现更灵活、更符合需求的容器定制,提升系统的可扩展性和稳定性。
参考源码:
org.springframework.context.support.AbstractRefreshableApplicationContext#customizeBeanFactoryorg.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverridingorg.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferencesorg.springframework.context.support.AbstractApplicationContext#refresh
