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#customizeBeanFactory
org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences
org.springframework.context.support.AbstractApplicationContext#refresh