总结摘要
总结Bean生命周期相关知识点可能提的问题
针对Bean生命周期相关问题,我准备了一个“一句话原理 + 一句话源码 + 一句话项目/场景”的结构化回答,体现深度同时展现实战能力。
生命周期流程
Bean 的生命周期包含哪些阶段?(从实例化到销毁)
生命周期全景概览
一句话原理: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
29
30
31
32
33
34
| /**
* Bean生命周期完整流程图(源码注释形式)
*/
public class BeanLifecycleOverview {
// 1. 实例化:调用构造器创建对象
// 2. 属性赋值:注入依赖的Bean
// 3. 初始化前:BeanPostProcessor前置处理
// 4. 初始化:执行InitializingBean接口/init-method
// 5. 初始化后:BeanPostProcessor后置处理
// 6. 使用:Bean准备就绪
// 7. 销毁前:执行 DestructionAwareBeanPostProcessor
// 8. 销毁:执行DisposableBean接口/destroy-method
// AbstractAutowireCapableBeanFactory.doCreateBean() 中的核心步骤
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
// 1. 实例化
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
Object bean = instanceWrapper.getWrappedInstance();
// 2. 提前暴露(解决循环依赖)
if (mbd.isSingleton()) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// 3. 属性赋值
populateBean(beanName, mbd, instanceWrapper);
// 4. 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
return exposedObject;
}
}
|
项目场景:在开发监控组件时,需要在Bean初始化完成后自动注册到监控中心,在销毁时注销。通过实现InitializingBean和DisposableBean接口,在相应生命周期阶段执行注册和注销逻辑,确保了资源的正确管理。
实例化阶段详解
一句话原理:实例化阶段通过构造器或工厂方法创建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
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
| /**
* 实例化阶段源码分析
*/
public class InstantiationPhase {
// AbstractAutowireCapableBeanFactory.createBeanInstance()
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// 1. 检查是否有工厂方法
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// 2. 检查是否有Supplier
if (mbd.getInstanceSupplier() != null) {
return instantiateWithSupplier(beanName, mbd);
}
// 3. 使用构造器实例化
// 3.1 如果有@Autowired构造器,使用它
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 3.2 使用默认构造器
return instantiateBean(beanName, mbd);
}
// 实例化扩展点:InstantiationAwareBeanPostProcessor
// 可以在实例化前后进行干预
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
// 实例化前执行(可返回代理对象替代原始Bean)
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
return null;
}
// 实例化后执行(属性赋值前)
default boolean postProcessAfterInstantiation(Object bean, String beanName) {
return true;
}
}
}
// 示例:使用InstantiationAwareBeanPostProcessor返回代理对象
@Component
public class ProxyBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
if (beanClass == SomeService.class) {
// 创建CGLIB代理替代原始Bean
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(beanClass);
enhancer.setCallback(new MethodInterceptor() {
// 代理逻辑
});
return enhancer.create();
}
return null;
}
}
|
项目场景:在AOP实现中,AbstractAutoProxyCreator实现了InstantiationAwareBeanPostProcessor,在postProcessBeforeInstantiation阶段返回代理对象,从而在Bean实例化前就完成代理创建,实现提前织入切面逻辑。
3. 属性赋值阶段详解
一句话原理:属性赋值阶段通过依赖注入填充Bean的字段,Spring会解析@Autowired、@Resource、@Value等注解,从容器中获取依赖的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
| /**
* 属性赋值阶段源码分析
*/
public class PopulatePhase {
// AbstractAutowireCapableBeanFactory.populateBean()
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
// 1. 执行InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation
// 如果返回false,跳过后续属性赋值
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
// 2. 获取需要注入的属性
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 3. 处理自动装配(byName/byType)
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
pvs = new PropertyValues(pvs);
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, pvs);
}
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, pvs);
}
}
// 4. 执行InstantiationAwareBeanPostProcessor处理注解注入
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, bw.getWrappedInstance(), beanName);
}
}
// 5. 应用属性值
applyPropertyValues(beanName, mbd, bw, pvs);
}
// 核心注解处理:AutowiredAnnotationBeanPostProcessor
// 在postProcessPropertyValues中解析@Autowired
}
// 属性赋值阶段发生的扩展点:
// - InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
// - InstantiationAwareBeanPostProcessor.postProcessPropertyValues
|
项目场景:在配置中心组件中,通过@Value("${config.key}")注入配置值,PropertySourcesPlaceholderConfigurer作为BeanFactoryPostProcessor在属性赋值阶段解析占位符,将配置值注入到字段中。
4. 初始化阶段详解
一句话原理:初始化阶段是Bean生命周期的核心增强点,依次执行BeanNameAware、BeanClassLoaderAware、BeanFactoryAware等Aware接口,然后执行BeanPostProcessor的前置处理,接着调用InitializingBean接口和init-method,最后执行BeanPostProcessor的后置处理。
一句话源码:
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
| /**
* 初始化阶段源码分析
*/
public class InitializationPhase {
// AbstractAutowireCapableBeanFactory.initializeBean()
protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
// 1. 执行Aware接口回调(感知容器)
invokeAwareMethods(beanName, bean);
// 包括:BeanNameAware, BeanClassLoaderAware, BeanFactoryAware
// 2. 执行BeanPostProcessor的前置处理
Object wrappedBean = bean;
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
// 这里会调用所有BeanPostProcessor的postProcessBeforeInitialization
// 3. 执行初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
// - 先执行InitializingBean.afterPropertiesSet()
// - 再执行自定义init-method
// 4. 执行BeanPostProcessor的后置处理
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
// 这里会调用所有BeanPostProcessor的postProcessAfterInitialization
return wrappedBean;
}
// Aware接口回调
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
// 执行初始化方法
protected void invokeInitMethods(String beanName, Object bean, RootBeanDefinition mbd) throws Exception {
// 1. 执行InitializingBean接口
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
// 2. 执行自定义init-method
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (initMethodName != null && !(bean instanceof InitializingBean && "afterPropertiesSet".equals(initMethodName))) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
}
// 示例:完整的初始化回调
@Component
public class LifecycleBean implements BeanNameAware, InitializingBean {
private String beanName;
@Override
public void setBeanName(String name) {
this.beanName = name;
System.out.println("1. BeanNameAware回调: " + name);
}
@PostConstruct
public void postConstruct() {
System.out.println("2. @PostConstruct注解方法");
}
@Override
public void afterPropertiesSet() {
System.out.println("3. InitializingBean.afterPropertiesSet()");
}
@Bean(initMethod = "customInit")
public void customInit() {
System.out.println("4. 自定义init-method");
}
}
|
项目场景:在缓存组件中,需要在Bean初始化完成后加载预热数据。通过实现InitializingBean接口,在afterPropertiesSet()中从数据库加载热点数据到缓存,确保Bean对外提供服务前缓存已准备就绪。
5. 使用和销毁阶段详解
一句话原理:初始化完成后Bean进入就绪状态,供应用程序使用;当容器关闭时,依次执行**@PreDestroy**、DisposableBean接口、destroy-method,完成资源释放和清理工作。
一句话源码:
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
| /**
* 使用和销毁阶段源码分析
*/
public class UsageAndDestroyPhase {
// 1. 使用阶段:Bean准备就绪,可以被注入到其他Bean或通过getBean获取
// 2. 销毁阶段:容器关闭时触发
// AbstractApplicationContext.close() → doClose() → destroyBeans()
// → DefaultSingletonBeanRegistry.destroySingletons()
public void destroySingletons() {
// 获取所有单例Bean名称
String[] beanNames = StringUtils.toStringArray(this.singletonNames);
// 按依赖顺序销毁
for (int i = beanNames.length - 1; i >= 0; i--) {
destroySingleton(beanNames[i]);
}
// 清空缓存
this.singletonObjects.clear();
this.singletonFactories.clear();
this.earlySingletonObjects.clear();
}
// DisposableBeanAdapter.destroy() 执行销毁逻辑
public void destroy() {
// 1. 执行@PreDestroy注解方法
invokeCustomDestroyMethod(this.preDestroyMethods);
// 2. 执行DisposableBean接口
if (this.invokeDisposableBean) {
((DisposableBean) this.bean).destroy();
}
// 3. 执行自定义destroy-method
if (this.destroyMethod != null) {
invokeCustomDestroyMethod(this.destroyMethod);
}
}
}
// 示例:完整的销毁回调
@Component
public class DestroyLifecycleBean implements DisposableBean {
@PreDestroy
public void preDestroy() {
System.out.println("1. @PreDestroy注解方法");
// 释放资源:关闭连接、清理缓存等
}
@Override
public void destroy() {
System.out.println("2. DisposableBean.destroy()");
}
@Bean(destroyMethod = "customDestroy")
public void customDestroy() {
System.out.println("3. 自定义destroy-method");
}
}
|
项目场景:在消息队列消费者中,需要在应用关闭时优雅停止,避免消息丢失。通过@PreDestroy注解方法,先停止拉取新消息,等待当前处理完成,最后关闭连接,确保数据一致性。
完整实战指南
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
| /**
* Bean生命周期完整实战
*/
public class BeanLifecycleGuide {
/**
* 1. 生命周期执行顺序验证
*/
@Component
public class LifecycleVerificationBean implements
BeanNameAware, BeanFactoryAware, InitializingBean, DisposableBean {
public LifecycleVerificationBean() {
System.out.println("1. 实例化");
}
@Autowired
public void setDependency(OtherBean other) {
System.out.println("2. 属性赋值");
}
@Override
public void setBeanName(String name) {
System.out.println("3. BeanNameAware");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
System.out.println("4. BeanFactoryAware");
}
@PostConstruct
public void postConstruct() {
System.out.println("5. @PostConstruct");
}
@Override
public void afterPropertiesSet() {
System.out.println("6. InitializingBean");
}
@Bean(initMethod = "initMethod")
public void initMethod() {
System.out.println("7. init-method");
}
@PreDestroy
public void preDestroy() {
System.out.println("8. @PreDestroy");
}
@Override
public void destroy() {
System.out.println("9. DisposableBean");
}
@Bean(destroyMethod = "destroyMethod")
public void destroyMethod() {
System.out.println("10. destroy-method");
}
}
/**
* 2. BeanPostProcessor应用实战
*/
@Component
public class LoggingBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (bean instanceof ImportantService) {
System.out.println("重要服务" + beanName + "开始初始化");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof ImportantService) {
System.out.println("重要服务" + beanName + "初始化完成");
// 可在此处对Bean进行包装或代理
}
return bean;
}
}
/**
* 3. 自定义初始化销毁方法
*/
@Configuration
public class CustomLifecycleConfig {
@Bean(initMethod = "init", destroyMethod = "cleanup")
public CustomService customService() {
return new CustomService();
}
}
public class CustomService {
public void init() {
System.out.println("自定义初始化方法");
// 打开资源、连接等
}
public void cleanup() {
System.out.println("自定义销毁方法");
// 关闭资源
}
}
/**
* 4. 生命周期扩展点汇总
*/
public class ExtensionPoints {
// 实例化前: InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
// 实例化后: InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
// 属性赋值: InstantiationAwareBeanPostProcessor.postProcessPropertyValues
// Aware接口: BeanNameAware, BeanFactoryAware, ApplicationContextAware等
// 初始化前: BeanPostProcessor.postProcessBeforeInitialization
// 初始化: InitializingBean.afterPropertiesSet, init-method
// 初始化后: BeanPostProcessor.postProcessAfterInitialization
// 销毁前: DestructionAwareBeanPostProcessor.postProcessBeforeDestruction
// 销毁: DisposableBean.destroy, destroy-method
}
/**
* 5. 面试常见问题
*/
public class InterviewQA {
// Q: 构造器注入和属性注入分别在哪个阶段?
// A: 构造器注入在实例化阶段,属性注入在属性赋值阶段
// Q: BeanPostProcessor和BeanFactoryPostProcessor的区别?
// A: BeanPostProcessor作用于Bean实例(初始化前后),BeanFactoryPostProcessor作用于Bean定义(Bean创建前)
// Q: @PostConstruct、init-method、afterPropertiesSet执行顺序?
// A: @PostConstruct → afterPropertiesSet → init-method
// Q: 如何在所有Bean初始化完成后执行某段逻辑?
// A: 实现SmartInitializingSingleton接口的afterSingletonsInstantiated方法
}
}
/**
* 生命周期总结表
*
* 阶段 核心操作 扩展点
* 实例化 创建对象 InstantiationAwareBeanPostProcessor
* 属性赋值 注入依赖 InstantiationAwareBeanPostProcessor
* 初始化前 Aware接口回调 BeanPostProcessor.before
* 初始化 afterPropertiesSet/init-method InitializingBean
* 初始化后 后置处理 BeanPostProcessor.after
* 使用 业务调用 无
* 销毁 清理资源 DisposableBean, @PreDestroy
*
* 最佳实践:
* 1. 资源初始化用 @PostConstruct
* 2. 资源清理用 @PreDestroy
* 3. 全局处理用 BeanPostProcessor
* 4. 感知容器用 Aware接口
*/
// 面试金句
// "Bean的生命周期就像一个人的一生:
// 实例化是'出生'(来到这个世界,但还没名字),
// 属性赋值是'成长'(学习知识,建立关系),
// 初始化是'成人礼'(Aware接口是'认识自己',BeanPostProcessor是'接受祝福',
// InitializingBean是'宣誓就职',init-method是'发表感言'),
// 使用阶段是'工作'(为社会做贡献),
// 销毁是'退休清理'(@PreDestroy是'写回忆录',DisposableBean是'办理退休手续')。
// 在监控系统中,我通过BeanPostProcessor给所有服务类自动添加性能统计功能,
// 在@PreDestroy中优雅关闭线程池,确保应用重启时不丢数据。
// 理解生命周期,才能在最恰当的时机做最正确的事。"
|
你在项目中如何利用 Bean 生命周期做初始化操作?(如 @PostConstruct、InitializingBean)
三种初始化方式对比与选择
一句话原理:Spring提供三种初始化方式:@PostConstruct(注解,最常用)、InitializingBean接口(编程式)、init-method(XML/配置类),各有适用场景,项目中我优先使用@PostConstruct,因其语义清晰、与框架解耦。
一句话源码:
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
| /**
* 三种初始化方式实战对比
*/
@Service
public class OrderInitializationService {
private static final Logger log = LoggerFactory.getLogger(OrderInitializationService.class);
/**
* 方式1:@PostConstruct(推荐)
* 特点:JSR-250标准注解,与框架解耦,语义明确
* 适用:大多数业务场景,如加载配置、预热缓存
*/
@PostConstruct
public void initOrderCache() {
log.info("1. @PostConstruct:订单服务初始化开始");
// 加载订单状态字典
orderStatusMap = loadOrderStatusFromDB();
// 预热常用订单数据到缓存
warmupHotOrderCache();
// 启动订单超时扫描线程
startOrderTimeoutScanner();
log.info("订单服务初始化完成,缓存加载完毕");
}
/**
* 方式2:InitializingBean接口
* 特点:Spring专用接口,可以获取Bean名称等容器信息
* 适用:需要访问Spring容器元数据的场景
*/
@Service
public class PaymentInitializer implements InitializingBean {
@Autowired
private ApplicationContext applicationContext;
@Override
public void afterPropertiesSet() {
log.info("2. InitializingBean:支付初始化器执行");
// 从容器中获取所有支付渠道
Map<String, PaymentChannel> channels = applicationContext.getBeansOfType(PaymentChannel.class);
// 注册支付渠道
paymentChannelManager.registerChannels(channels.values());
}
}
/**
* 方式3:@Bean(initMethod = "init")
* 特点:配置分离,适合第三方组件集成
* 适用:无法修改源码的第三方类
*/
@Configuration
public class ThirdPartyIntegrationConfig {
@Bean(initMethod = "start")
public DataSourcePool dataSourcePool() {
// 第三方连接池,无法添加@PostConstruct
DataSourcePool pool = new DataSourcePool();
pool.setUrl("jdbc:mysql://localhost:3306/test");
return pool;
}
}
}
|
项目场景:在支付系统中,使用@PostConstruct加载支付渠道配置、预热风控规则缓存;使用InitializingBean注册从Spring容器中动态获取的支付处理器;对于第三方SDK(如阿里云OSS客户端),使用initMethod启动客户端连接。
实战案例一:缓存预热
一句话原理:利用@PostConstruct在应用启动完成后,异步加载热点数据到缓存,避免第一个用户请求时因缓存未命中而直接查询数据库,提升系统响应速度。
一句话源码:
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
| /**
* 缓存预热实战
*/
@Service
public class HotDataCachePreloader {
private static final Logger log = LoggerFactory.getLogger(HotDataCachePreloader.class);
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private CategoryService categoryService;
@Autowired
private HotProductService hotProductService;
@Autowired
private ThreadPoolTaskExecutor asyncExecutor;
// 缓存预热标记
private volatile boolean preloadCompleted = false;
@PostConstruct
public void preloadCache() {
log.info("开始缓存预热...");
// 使用异步线程池执行预热,不阻塞应用启动
asyncExecutor.submit(() -> {
try {
// 1. 预热商品分类(全量数据)
preloadCategories();
// 2. 预热热门商品(top 1000)
preloadHotProducts();
// 3. 预热首页推荐数据
preloadHomePageData();
preloadCompleted = true;
log.info("缓存预热完成,耗时:{}ms", System.currentTimeMillis() - start);
} catch (Exception e) {
log.error("缓存预热失败", e);
}
});
}
private void preloadCategories() {
// 从数据库加载所有分类
List<Category> categories = categoryService.findAll();
// 批量写入Redis
categories.forEach(category ->
redisTemplate.opsForValue().set("category:" + category.getId(), category, 1, TimeUnit.DAYS));
log.info("分类缓存预热完成,数量:{}", categories.size());
}
private void preloadHotProducts() {
// 加载热门商品
List<Long> hotProductIds = hotProductService.getTopHotProducts(1000);
hotProductIds.forEach(productId ->
redisTemplate.opsForValue().set("hot:product:" + productId, true, 1, TimeUnit.HOURS));
}
// 提供给业务方检查预热状态
public boolean isPreloadCompleted() {
return preloadCompleted;
}
}
// 使用时检查预热状态
@RestController
public class ProductController {
@Autowired
private HotDataCachePreloader cachePreloader;
@GetMapping("/product/{id}")
public Product getProduct(@PathVariable Long id) {
// 如果预热未完成,可以降级处理
if (!cachePreloader.isPreloadCompleted()) {
return fallbackGetProduct(id);
}
// 正常业务逻辑
return productService.getProduct(id);
}
}
|
项目场景:在电商大促前重启应用时,通过缓存预热让热门商品数据提前加载到Redis,避免了上线后第一批用户请求的慢查询,接口响应时间从500ms降低到50ms。
3. 实战案例二:资源初始化与线程池启动
一句话原理:利用InitializingBean在依赖注入完成后,启动后台守护线程(如定时任务、消息监听、过期扫描),确保资源在使用前已经准备就绪。
一句话源码:
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
73
74
75
76
77
| /**
* 资源初始化实战
*/
@Component
public class OrderTimeoutScanner implements InitializingBean, DisposableBean {
private static final Logger log = LoggerFactory.getLogger(OrderTimeoutScanner.class);
@Autowired
private OrderService orderService;
@Autowired
private NotificationService notificationService;
private ScheduledExecutorService scheduler;
private volatile boolean running = true;
@Override
public void afterPropertiesSet() {
log.info("订单超时扫描器初始化...");
// 创建守护线程池
scheduler = Executors.newScheduledThreadPool(1, r -> {
Thread t = new Thread(r, "order-timeout-scanner");
t.setDaemon(true); // 设置为守护线程,不阻止JVM退出
return t;
});
// 启动定时任务:每分钟扫描一次超时订单
scheduler.scheduleAtFixedRate(this::scanTimeoutOrders, 10, 60, TimeUnit.SECONDS);
log.info("订单超时扫描器已启动");
}
private void scanTimeoutOrders() {
if (!running) return;
try {
log.debug("开始扫描超时订单");
List<Order> timeoutOrders = orderService.findTimeoutOrders(30); // 30分钟未支付
for (Order order : timeoutOrders) {
// 处理超时订单:取消订单、释放库存
orderService.cancelOrder(order.getId(), OrderCancelReason.PAYMENT_TIMEOUT);
// 发送通知
notificationService.sendTimeoutNotification(order.getUserId(), order.getId());
}
if (!timeoutOrders.isEmpty()) {
log.info("处理超时订单{}个", timeoutOrders.size());
}
} catch (Exception e) {
log.error("扫描超时订单异常", e);
}
}
@Override
public void destroy() {
log.info("订单超时扫描器关闭中...");
running = false;
if (scheduler != null) {
// 优雅停机
scheduler.shutdown();
try {
if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
scheduler.shutdownNow();
}
} catch (InterruptedException e) {
scheduler.shutdownNow();
Thread.currentThread().interrupt();
}
}
log.info("订单超时扫描器已关闭");
}
}
|
项目场景:在订单系统中,通过InitializingBean启动超时订单扫描线程,确保应用启动后立即开始监控未支付订单。同时实现DisposableBean在应用关闭时优雅停止线程,避免资源泄露。
4. 实战案例三:动态配置加载
一句话原理:使用@PostConstruct监听配置中心变化,在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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
| /**
* 动态配置加载实战
*/
@Component
public class DynamicConfigLoader {
private static final Logger log = LoggerFactory.getLogger(DynamicConfigLoader.class);
@Autowired
private ConfigCenterClient configClient;
@Autowired
private ApplicationContext applicationContext;
// 线程池配置
private volatile ThreadPoolConfig threadPoolConfig;
// 限流规则
private volatile List<RateLimitRule> rateLimitRules;
// 开关配置
private volatile FeatureSwitches featureSwitches;
@PostConstruct
public void init() {
log.info("初始化动态配置加载器");
// 1. 首次加载所有配置
reloadAllConfigs();
// 2. 注册配置监听器(实现热更新)
registerConfigListeners();
// 3. 启动配置健康检查
startConfigHealthCheck();
}
private void reloadAllConfigs() {
// 加载线程池配置
threadPoolConfig = configClient.getConfig("threadpool", ThreadPoolConfig.class);
// 加载限流规则
rateLimitRules = configClient.getConfigList("ratelimit", RateLimitRule.class);
// 加载功能开关
featureSwitches = configClient.getConfig("features", FeatureSwitches.class);
log.info("配置加载完成:threadPool={}, rateLimitRules={}, features={}",
threadPoolConfig, rateLimitRules.size(), featureSwitches);
}
private void registerConfigListeners() {
// 监听线程池配置变化
configClient.addListener("threadpool", (config) -> {
ThreadPoolConfig newConfig = (ThreadPoolConfig) config;
log.info("线程池配置更新:{}", newConfig);
// 动态调整线程池
ThreadPoolExecutor executor = applicationContext.getBean(ThreadPoolExecutor.class);
executor.setCorePoolSize(newConfig.getCorePoolSize());
executor.setMaximumPoolSize(newConfig.getMaxPoolSize());
this.threadPoolConfig = newConfig;
});
// 监听限流规则变化
configClient.addListener("ratelimit", (config) -> {
List<RateLimitRule> newRules = (List<RateLimitRule>) config;
log.info("限流规则更新:{}", newRules.size());
// 重新加载限流器
RateLimiterManager limiterManager = applicationContext.getBean(RateLimiterManager.class);
limiterManager.reloadRules(newRules);
this.rateLimitRules = newRules;
});
}
private void startConfigHealthCheck() {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() -> {
try {
// 定期检查配置中心连接状态
boolean healthy = configClient.healthCheck();
if (!healthy) {
log.warn("配置中心连接异常,使用本地缓存配置");
}
} catch (Exception e) {
log.error("配置健康检查异常", e);
}
}, 1, 5, TimeUnit.MINUTES);
}
// 对外提供配置获取接口
public ThreadPoolConfig getThreadPoolConfig() {
return threadPoolConfig;
}
public boolean isFeatureEnabled(String featureName) {
return featureSwitches != null && featureSwitches.isEnabled(featureName);
}
public RateLimitRule getRateLimitRule(String apiName) {
return rateLimitRules.stream()
.filter(r -> r.getApiName().equals(apiName))
.findFirst()
.orElse(null);
}
}
|
项目场景:在微服务网关中,通过@PostConstruct加载限流、熔断等动态配置,并注册监听器实现配置热更新。当运营需要调整某个API的限流阈值时,只需在配置中心修改,网关自动生效,无需重启服务。
5. 实战案例四:数据校验与完整性检查
一句话原理:利用InitializingBean在依赖注入完成后,对关键依赖和配置进行完整性校验,及早发现问题,避免运行时因配置缺失导致的诡异错误。
一句话源码:
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
| /**
* 数据校验实战
*/
@Component
public class SystemIntegrityChecker implements InitializingBean {
private static final Logger log = LoggerFactory.getLogger(SystemIntegrityChecker.class);
@Autowired(required = false)
private DataSource dataSource;
@Autowired(required = false)
private RedisTemplate redisTemplate;
@Autowired(required = false)
private MongoTemplate mongoTemplate;
@Value("${app.version:unknown}")
private String appVersion;
@Value("${app.env:unknown}")
private String environment;
@Override
public void afterPropertiesSet() {
log.info("系统完整性检查开始,环境:{},版本:{}", environment, appVersion);
// 1. 检查核心依赖
checkRequiredDependencies();
// 2. 检查数据库连接
checkDatabaseConnectivity();
// 3. 检查Redis连接
checkRedisConnectivity();
// 4. 检查必要表是否存在
checkRequiredTables();
// 5. 检查磁盘空间
checkDiskSpace();
log.info("系统完整性检查完成");
}
private void checkRequiredDependencies() {
List<String> missingDependencies = new ArrayList<>();
if (dataSource == null) {
missingDependencies.add("DataSource");
}
if (redisTemplate == null) {
missingDependencies.add("RedisTemplate");
}
if (!missingDependencies.isEmpty()) {
log.error("缺少必要依赖:{}", missingDependencies);
// 可以决定是否抛出异常阻止启动
if (environment.contains("prod")) {
throw new IllegalStateException("生产环境缺少必要依赖: " + missingDependencies);
}
}
}
private void checkDatabaseConnectivity() {
try {
Connection conn = dataSource.getConnection();
boolean valid = conn.isValid(3);
conn.close();
if (!valid) {
log.error("数据库连接测试失败");
if (environment.contains("prod")) {
throw new IllegalStateException("数据库无法连接");
}
}
log.info("数据库连接正常");
} catch (Exception e) {
log.error("数据库连接检查异常", e);
}
}
private void checkRedisConnectivity() {
try {
String pong = redisTemplate.getConnectionFactory().getConnection().ping();
if ("PONG".equals(pong)) {
log.info("Redis连接正常");
} else {
log.warn("Redis ping返回异常:{}", pong);
}
} catch (Exception e) {
log.warn("Redis连接检查异常", e);
// Redis可选,只记录警告
}
}
private void checkRequiredTables() {
// 检查关键业务表是否存在
// 如果表不存在,可以自动创建或报警
}
private void checkDiskSpace() {
File root = new File("/");
long freeSpace = root.getFreeSpace();
long totalSpace = root.getTotalSpace();
double freePercent = freeSpace * 100.0 / totalSpace;
if (freePercent < 10) {
log.warn("磁盘空间不足:剩余{}%({}GB/{}GB)",
String.format("%.2f", freePercent),
freeSpace / (1024 * 1024 * 1024),
totalSpace / (1024 * 1024 * 1024));
} else {
log.info("磁盘空间充足:剩余{}%", String.format("%.2f", freePercent));
}
}
}
|
项目场景:在应用启动时通过完整性检查,发现某次上线时配置文件漏写了Redis密码,及时报错阻止启动,避免了线上服务依赖Redis的功能不可用。同时磁盘空间检查预警,提前处理了日志文件过大的问题。
最佳实践总结
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
| /**
* 初始化操作最佳实践总结
*/
public class InitializationBestPractices {
/**
* 1. 选择原则
*/
public class SelectionPrinciples {
// @PostConstruct:业务初始化,与Spring解耦,95%场景适用
// InitializingBean:需要访问Spring容器元数据,需要Bean名称
// init-method:第三方组件集成,无法修改源码
}
/**
* 2. 注意事项
*/
public class Precautions {
// 1. 不要在初始化中做耗时操作(可异步处理)
// 2. 做好异常处理,避免初始化失败导致应用无法启动
// 3. 考虑幂等性,多次初始化不应有问题
// 4. 日志记录,便于排查问题
// 5. 可以配合@Lazy实现延迟初始化
}
/**
* 3. 执行顺序
*/
public class ExecutionOrder {
// Constructor > @Autowired > @PostConstruct > afterPropertiesSet > init-method
// 可以通过Ordered接口或@Order控制BeanPostProcessor的顺序
}
/**
* 4. 常见陷阱
*/
public class CommonPitfalls {
// 陷阱1:在@PostConstruct中调用远程服务(超时影响启动)
// 解决:异步执行
// 陷阱2:在初始化中依赖其他未初始化的Bean
// 解决:使用@DependsOn指定依赖顺序
// 陷阱3:忘记处理异常,导致应用启动失败
// 解决:捕获异常,决定是忽略还是终止
// 陷阱4:初始化操作重复执行(如多个继承层次)
// 解决:检查父类是否也有初始化方法
}
}
/**
* 项目场景总结
*
* 场景 使用方式 作用
* 缓存预热 @PostConstruct 提升首次访问性能
* 线程池启动 InitializingBean 后台任务管理
* 配置加载 @PostConstruct+监听器 热更新配置
* 完整性检查 InitializingBean 及早发现问题
* 第三方集成 init-method 适配不可修改代码
*/
// 面试金句
// "在项目中,我像'管家'一样管理Bean的初始化:
// @PostConstruct是'打扫房间'(缓存预热、加载配置),
// InitializingBean是'启动家电'(线程池、定时任务),
// init-method是'安装第三方家具'(集成第三方SDK)。
// 最经典的案例是订单系统的缓存预热:通过@PostConstruct异步加载热门商品,
// 上线后第一批用户请求不再穿透数据库,接口响应时间从500ms降到50ms。
// 同时用InitializingBean启动超时扫描线程,确保每一笔订单都被正确监控。
// 理解这些初始化方式,才能在合适的时机做正确的事。"
|
Aware 接口的作用是什么?常见的 Aware 接口有哪些?
Aware核心原理
一句话原理:Aware接口是Spring提供的标记性接口,用于让Bean感知到容器中的特定资源(如Bean名称、BeanFactory、ApplicationContext等),通过回调方式将容器资源注入到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
| /**
* Aware核心机制源码分析
*/
// 顶层标记接口
public interface Aware {
// 空接口,仅作为标记
}
// 常见的Aware接口示例
public interface BeanNameAware extends Aware {
void setBeanName(String name); // 注入Bean名称
}
public interface BeanFactoryAware extends Aware {
void setBeanFactory(BeanFactory beanFactory); // 注入BeanFactory
}
public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext applicationContext); // 注入ApplicationContext
}
// Spring容器处理Aware接口的源码
public class AbstractAutowireCapableBeanFactory {
// 在initializeBean中调用Aware接口
protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
// 1. 调用各种Aware接口
invokeAwareMethods(beanName, bean);
// 2. 执行BeanPostProcessor前置处理
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
// 3. 执行初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
// 4. 执行BeanPostProcessor后置处理
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}
// 专门处理Aware接口的方法
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
}
// ApplicationContextAware由ApplicationContextAwareProcessor处理
public class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ApplicationContext applicationContext;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
return bean;
}
}
|
项目场景:在开发通用组件时,需要获取ApplicationContext来动态获取其他Bean,通过实现ApplicationContextAware接口,组件可以持有容器引用,在不侵入业务代码的前提下实现灵活的资源获取。
常见Aware接口详解
一句话原理:Spring提供十余种Aware接口,按功能分为容器感知(BeanFactoryAware)、环境感知(EnvironmentAware)、资源感知(ResourceLoaderAware)、上下文感知(ApplicationContextAware)等类别,满足不同场景的资源获取需求。
一句话源码:
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
| /**
* 常见Aware接口大全及使用示例
*/
@Component
public class AllAwareDemo implements
BeanNameAware,
BeanClassLoaderAware,
BeanFactoryAware,
ApplicationContextAware,
EnvironmentAware,
ResourceLoaderAware,
ApplicationEventPublisherAware,
MessageSourceAware,
EmbeddedValueResolverAware {
private static final Logger log = LoggerFactory.getLogger(AllAwareDemo.class);
// 1. BeanNameAware - 获取Bean在容器中的名称
@Override
public void setBeanName(String name) {
log.info("1. BeanNameAware: 我的名字是 {}", name);
this.beanName = name;
}
// 2. BeanClassLoaderAware - 获取加载Bean的类加载器
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
log.info("2. BeanClassLoaderAware: 类加载器 = {}", classLoader);
this.classLoader = classLoader;
}
// 3. BeanFactoryAware - 获取BeanFactory(低级容器)
@Override
public void setBeanFactory(BeanFactory beanFactory) {
log.info("3. BeanFactoryAware: BeanFactory = {}", beanFactory);
this.beanFactory = beanFactory;
}
// 4. ApplicationContextAware - 获取ApplicationContext(高级容器)
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
log.info("4. ApplicationContextAware: ApplicationContext = {}", applicationContext);
this.applicationContext = applicationContext;
}
// 5. EnvironmentAware - 获取环境信息(配置文件、属性)
@Override
public void setEnvironment(Environment environment) {
log.info("5. EnvironmentAware: 当前环境 = {}", environment.getActiveProfiles());
this.environment = environment;
}
// 6. ResourceLoaderAware - 获取资源加载器(用于读取文件)
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
log.info("6. ResourceLoaderAware: ResourceLoader = {}", resourceLoader);
this.resourceLoader = resourceLoader;
}
// 7. ApplicationEventPublisherAware - 获取事件发布器
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
log.info("7. ApplicationEventPublisherAware: 事件发布器 = {}", publisher);
this.eventPublisher = publisher;
}
// 8. MessageSourceAware - 获取国际化消息源
@Override
public void setMessageSource(MessageSource messageSource) {
log.info("8. MessageSourceAware: 消息源 = {}", messageSource);
this.messageSource = messageSource;
}
// 9. EmbeddedValueResolverAware - 获取占位符解析器(解析${...})
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
log.info("9. EmbeddedValueResolverAware: 占位符解析器 = {}", resolver);
this.valueResolver = resolver;
}
// 使用示例:通过ApplicationContext动态获取Bean
public <T> T getBean(Class<T> requiredType) {
return applicationContext.getBean(requiredType);
}
// 使用示例:解析占位符
public String resolvePlaceholder(String expression) {
return valueResolver.resolveStringValue(expression);
}
// 使用示例:发布自定义事件
public void publishEvent(Object event) {
eventPublisher.publishEvent(event);
}
}
|
项目场景:在开发配置中心客户端时,需要同时获取Environment(读取本地配置)、ApplicationContext(动态刷新Bean)、ApplicationEventPublisher(发布配置变更事件),通过实现多个Aware接口一站式解决所有需求。
3. Aware接口的执行顺序
一句话原理:Aware接口的回调遵循固定顺序:先执行与BeanFactory相关的(BeanNameAware → BeanClassLoaderAware → BeanFactoryAware),后执行与ApplicationContext相关的(其余Aware),这个顺序由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
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
73
74
| /**
* Aware接口执行顺序源码分析
*/
@Component
public class AwareOrderDemo implements
BeanNameAware,
BeanFactoryAware,
ApplicationContextAware,
EnvironmentAware,
InitializingBean {
private static final Logger log = LoggerFactory.getLogger(AwareOrderDemo.class);
public AwareOrderDemo() {
log.info("0. 构造器执行");
}
@Override
public void setBeanName(String name) {
log.info("1. BeanNameAware.setBeanName()");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
log.info("2. BeanFactoryAware.setBeanFactory()");
}
@Override
public void setEnvironment(Environment environment) {
log.info("3. EnvironmentAware.setEnvironment()");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
log.info("4. ApplicationContextAware.setApplicationContext()");
}
@PostConstruct
public void postConstruct() {
log.info("5. @PostConstruct");
}
@Override
public void afterPropertiesSet() {
log.info("6. InitializingBean.afterPropertiesSet()");
}
@Bean(initMethod = "initMethod")
public void initMethod() {
log.info("7. init-method");
}
// 执行顺序输出:
// 0. 构造器执行
// 1. BeanNameAware.setBeanName()
// 2. BeanFactoryAware.setBeanFactory()
// 3. EnvironmentAware.setEnvironment()
// 4. ApplicationContextAware.setApplicationContext()
// 5. @PostConstruct
// 6. InitializingBean.afterPropertiesSet()
// 7. init-method
}
// Spring源码中的调用顺序
public class AwareOrderAnalysis {
// AbstractAutowireCapableBeanFactory.initializeBean()
// 1. invokeAwareMethods() // 处理BeanNameAware等
// 2. applyBeanPostProcessorsBeforeInitialization() // 处理ApplicationContextAware等
// 3. invokeInitMethods() // 处理InitializingBean等
// ApplicationContextAwareProcessor.postProcessBeforeInitialization()
// 在这里处理剩余的Aware接口
}
|
项目场景:在开发框架基础组件时,需要明确Aware接口的执行顺序,确保依赖资源在正确的时间点可用。例如在ApplicationContextAware中获取容器后,可以在@PostConstruct中使用容器资源,因为@PostConstruct在Aware之后执行。
完整实战指南
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
| /**
* Aware接口完整实战指南
*/
public class AwarePracticeGuide {
/**
* 1. 自定义Aware接口
*/
// 定义自定义Aware接口
public interface MyServiceAware extends Aware {
void setMyService(MyService myService);
}
// 实现BeanPostProcessor处理自定义Aware
@Component
public class MyServiceAwareProcessor implements BeanPostProcessor {
@Autowired
private MyService myService;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (bean instanceof MyServiceAware) {
((MyServiceAware) bean).setMyService(myService);
}
return bean;
}
}
// 使用自定义Aware
@Component
public class MyComponent implements MyServiceAware {
private MyService myService;
@Override
public void setMyService(MyService myService) {
this.myService = myService;
}
public void doWork() {
myService.process(); // 使用注入的服务
}
}
/**
* 2. 实战:ApplicationContextAware实现工具类
*/
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
context = applicationContext; // 静态持有
}
// 静态方法供非Spring管理的对象使用
public static <T> T getBean(Class<T> clazz) {
return context.getBean(clazz);
}
public static Object getBean(String name) {
return context.getBean(name);
}
public static String[] getActiveProfiles() {
return context.getEnvironment().getActiveProfiles();
}
public static void publishEvent(ApplicationEvent event) {
context.publishEvent(event);
}
}
// 在工具类中使用(不需要注入)
public class NonSpringClass {
public void doSomething() {
UserService userService = SpringContextUtil.getBean(UserService.class);
userService.process();
}
}
/**
* 3. 实战:EnvironmentAware实现多环境配置
*/
@Component
public class EnvironmentConfig implements EnvironmentAware {
private Environment environment;
private String currentEnv;
private boolean isProd;
private boolean isDev;
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
// 解析环境信息
String[] profiles = environment.getActiveProfiles();
currentEnv = profiles.length > 0 ? profiles[0] : "default";
isProd = "prod".equals(currentEnv);
isDev = "dev".equals(currentEnv);
// 读取特定配置
String appName = environment.getProperty("spring.application.name");
String serverPort = environment.getProperty("server.port");
System.out.println("当前环境: " + currentEnv);
System.out.println("应用名称: " + appName);
System.out.println("服务端口: " + serverPort);
}
public boolean isProd() { return isProd; }
public boolean isDev() { return isDev; }
public String getProperty(String key) {
return environment.getProperty(key);
}
}
/**
* 4. 实战:ResourceLoaderAware读取文件
*/
@Component
public class FileReaderComponent implements ResourceLoaderAware {
private ResourceLoader resourceLoader;
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public String readFile(String path) throws IOException {
Resource resource = resourceLoader.getResource("classpath:" + path);
try (InputStream is = resource.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
return reader.lines().collect(Collectors.joining("\n"));
}
}
}
/**
* 5. 常见Aware接口汇总表
*/
public class AwareSummary {
// 接口名称 作用
// BeanNameAware 获取Bean名称
// BeanClassLoaderAware 获取类加载器
// BeanFactoryAware 获取BeanFactory
// ApplicationContextAware 获取ApplicationContext
// EnvironmentAware 获取环境信息
// ResourceLoaderAware 获取资源加载器
// ApplicationEventPublisherAware 获取事件发布器
// MessageSourceAware 获取国际化消息源
// EmbeddedValueResolverAware 获取占位符解析器
// ImportAware 获取@Import注解信息
// LoadTimeWeaverAware 获取LTW织入器
}
}
/**
* Aware接口总结表
*
* 执行顺序 接口 触发时机
* 1 BeanNameAware initializeBean中
* 2 BeanClassLoaderAware initializeBean中
* 3 BeanFactoryAware initializeBean中
* 4 EnvironmentAware BeanPostProcessor前
* 5 ApplicationContextAware BeanPostProcessor前
* 6 @PostConstruct 初始化方法
* 7 InitializingBean 初始化方法
* 8 init-method 初始化方法
*
* 使用原则:
* 1. 优先使用注入(@Autowired),Aware接口作为补充
* 2. 工具类需要静态访问时,使用ApplicationContextAware
* 3. 组件需要感知环境时,使用EnvironmentAware
* 4. 需要动态获取资源时,使用ResourceLoaderAware
*/
// 面试金句
// "Aware接口就像Bean的'感官系统':
// BeanNameAware是'记住自己名字',
// BeanFactoryAware是'认识家庭住址'(低级容器),
// ApplicationContextAware是'认识社区服务中心'(高级容器),
// EnvironmentAware是'感知天气环境'(配置信息),
// ResourceLoaderAware是'会使用工具'(读取文件)。
// 在开发框架工具类时,我常用ApplicationContextAware实现一个静态的SpringContextHolder,
// 让非Spring管理的对象也能获取Bean;用EnvironmentAware实现配置的集中管理;
// 用ResourceLoaderAware实现资源的统一读取。
// 理解Aware接口,让Bean能够'睁眼看世界',但又不会过度依赖容器。"
|
BeanPostProcessor 和 BeanFactoryPostProcessor 的区别?
核心概念区别
一句话原理:BeanFactoryPostProcessor作用于Bean定义阶段,在Bean实例化前修改Bean的配置元数据;BeanPostProcessor作用于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
| /**
* 核心接口定义对比
*/
public interface BeanFactoryPostProcessor {
// 作用时间:所有Bean定义加载完成后,Bean实例化之前
// 作用对象:BeanDefinition(Bean的配置元数据)
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
public interface BeanPostProcessor {
// 作用时间:Bean实例化后,初始化前后
// 作用对象:Bean实例(已经创建出来的对象)
// 初始化前执行
default Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
// 初始化后执行
default Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
// 执行时机对比
// BeanFactoryPostProcessor:
// refresh() → invokeBeanFactoryPostProcessors() → 此时Bean还未创建
//
// BeanPostProcessor:
// refresh() → finishBeanFactoryInitialization() → 创建Bean → populateBean → initializeBean
// → applyBeanPostProcessorsBeforeInitialization → init-method → applyBeanPostProcessorsAfterInitialization
|
项目场景:在配置中心组件中,使用BeanFactoryPostProcessor在Bean实例化前替换配置文件中的占位符;在监控组件中,使用BeanPostProcessor对所有Service类自动添加性能统计功能,两者配合实现"配置修改+功能增强"的完整闭环。
BeanFactoryPostProcessor深度解析
一句话原理:BeanFactoryPostProcessor在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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
| /**
* BeanFactoryPostProcessor核心实现
*/
public class BeanFactoryPostProcessorDetail {
// 1. 经典实现:PropertySourcesPlaceholderConfigurer(处理@Value("${...}"))
public class PropertySourcesPlaceholderConfigurer implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 遍历所有Bean定义
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
// 解析Bean定义中的占位符
resolvePlaceholders(bd);
}
}
private void resolvePlaceholders(BeanDefinition bd) {
// 获取Bean定义中的属性值
MutablePropertyValues pvs = bd.getPropertyValues();
for (PropertyValue pv : pvs.getPropertyValues()) {
Object value = pv.getValue();
if (value instanceof String && ((String) value).contains("${")) {
// 将${...}替换为实际配置值
String resolved = environment.resolvePlaceholders((String) value);
pvs.add(pv.getName(), resolved);
}
}
}
}
// 2. 实战:动态修改Bean作用域
@Component
public class CustomScopePostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 将所有以"prototype"结尾的Bean改为原型作用域
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
if (beanName.endsWith("Prototype")) {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
bd.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE);
System.out.println("修改Bean作用域: " + beanName + " → prototype");
}
}
}
}
// 3. 实战:动态注册Bean
@Component
public class DynamicBeanRegisterPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 转换为BeanDefinitionRegistry(可注册Bean)
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// 动态创建Bean定义
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(DynamicService.class);
bd.setScope(ConfigurableBeanFactory.SCOPE_SINGLETON);
bd.setLazyInit(false);
// 添加属性值
bd.getPropertyValues().add("name", "dynamicBean");
// 注册到容器
registry.registerBeanDefinition("dynamicService", bd);
System.out.println("动态注册Bean: dynamicService");
}
}
}
}
// 执行顺序控制
@Order(1) // 数字越小优先级越高
@Component
public class FirstPostProcessor implements BeanFactoryPostProcessor {
// 优先执行
}
@Order(2)
@Component
public class SecondPostProcessor implements BeanFactoryPostProcessor {
// 后执行
}
|
项目场景:在微服务配置中心,通过自定义BeanFactoryPostProcessor实现配置的热加载:在Bean实例化前,将配置文件中的占位符替换为配置中心的最新值,同时支持动态修改数据源连接参数,无需重启应用。
3. BeanPostProcessor深度解析
一句话原理:BeanPostProcessor在Bean实例化后、初始化前后执行,可以包装、修改、代理Bean实例,常用于AOP代理、属性注入、自定义注解处理、监控增强等场景。
一句话源码:
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
| /**
* BeanPostProcessor核心实现
*/
public class BeanPostProcessorDetail {
// 1. 经典实现:AutowiredAnnotationBeanPostProcessor(处理@Autowired)
public class AutowiredAnnotationBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
// 在初始化前处理@Autowired注入
Class<?> clazz = bean.getClass();
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
// 从容器获取依赖并注入
Object dependency = getBeanFromFactory(field.getType());
field.setAccessible(true);
field.set(bean, dependency);
}
}
return bean;
}
}
// 2. 经典实现:AbstractAutoProxyCreator(AOP代理创建)
public abstract class AbstractAutoProxyCreator implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 在初始化后检查是否需要创建代理
if (shouldProxy(bean)) {
// 创建AOP代理对象
return createProxy(bean);
}
return bean;
}
protected abstract boolean shouldProxy(Object bean);
protected abstract Object createProxy(Object target);
}
// 3. 实战:方法耗时统计
@Component
public class PerformanceMonitorPostProcessor implements BeanPostProcessor {
private static final Logger log = LoggerFactory.getLogger(PerformanceMonitorPostProcessor.class);
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 只对Service类进行增强
if (beanName.endsWith("Service")) {
// 使用CGLIB创建代理
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(bean.getClass());
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
long start = System.currentTimeMillis();
try {
return proxy.invokeSuper(obj, args);
} finally {
long cost = System.currentTimeMillis() - start;
if (cost > 100) { // 超过100ms记录慢方法
log.warn("慢方法监控 - {}.{} 耗时: {}ms", beanName, method.getName(), cost);
}
}
}
});
return enhancer.create();
}
return bean;
}
}
// 4. 实战:自定义注解处理
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecution {
String value() default "";
}
@Component
public class LogExecutionPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 检查是否有方法标注@LogExecution
boolean hasLogMethod = Arrays.stream(bean.getClass().getMethods())
.anyMatch(m -> m.isAnnotationPresent(LogExecution.class));
if (hasLogMethod) {
return Enhancer.create(bean.getClass(), new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if (method.isAnnotationPresent(LogExecution.class)) {
LogExecution logExec = method.getAnnotation(LogExecution.class);
System.out.println("方法执行前: " + logExec.value());
Object result = proxy.invokeSuper(obj, args);
System.out.println("方法执行后");
return result;
}
return proxy.invokeSuper(obj, args);
}
});
}
return bean;
}
}
}
|
项目场景:在核心交易系统中,通过自定义BeanPostProcessor对所有Service方法添加性能监控,自动记录慢方法并报警;同时通过AOP代理实现事务管理,两者都是通过BeanPostProcessor在Bean初始化后创建代理对象实现的。
4. 核心区别对照表
一句话原理:两者本质区别在于作用对象(Bean定义 vs Bean实例)、执行时机(实例化前 vs 初始化前后)、典型应用(配置处理 vs 功能增强),共同构成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
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
| /**
* 完整对比分析
*/
public class ComprehensiveComparison {
// 1. 执行时机对比图
public class TimingComparison {
// BeanFactoryPostProcessor执行点:
// refresh() → obtainFreshBeanFactory() → invokeBeanFactoryPostProcessors()
// ↓
// Bean定义已加载
// ↓
// BeanFactoryPostProcessor
// ↓
// Bean实例化开始
// ↓
// BeanPostProcessor执行
// (before/after初始化)
}
// 2. 源码中的调用链
public class SourceCodeChain {
// AbstractApplicationContext.refresh()
public void refresh() {
// ... 准备BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 1. 调用BeanFactoryPostProcessor(此时Bean还未创建)
invokeBeanFactoryPostProcessors(beanFactory);
// 2. 注册BeanPostProcessor(为后续Bean创建做准备)
registerBeanPostProcessors(beanFactory);
// 3. 初始化所有单例Bean
finishBeanFactoryInitialization(beanFactory);
// 在这里创建Bean时,会应用已注册的BeanPostProcessor
}
}
// 3. 详细区别对照表
public class DifferenceTable {
// 维度 BeanFactoryPostProcessor BeanPostProcessor
// 作用对象 BeanDefinition(定义) Bean实例
// 执行时机 Bean实例化前 Bean初始化前后
// 能否修改Bean定义 ✅ 可以修改 ❌ 不能
// 能否替换Bean实例 ❌ 不能 ✅ 可以(返回代理对象)
// 典型应用 占位符替换、动态注册Bean AOP代理、属性注入、监控
// 调用次数 每个容器一次 每个Bean多次
// 执行顺序控制 @Order或Ordered接口 @Order或Ordered接口
// 内置实现 PropertySourcesPlaceholderConfigurer AutowiredAnnotationBeanPostProcessor
}
// 4. 组合应用实战
@Configuration
public class CombinedUsage {
// BeanFactoryPostProcessor:修改配置
@Bean
public static BeanFactoryPostProcessor configModifier() {
return beanFactory -> {
// 获取Bean定义并修改
BeanDefinition bd = beanFactory.getBeanDefinition("dataSource");
bd.getPropertyValues().add("maxActive", 50); // 修改连接池大小
};
}
// BeanPostProcessor:增强功能
@Bean
public BeanPostProcessor performanceMonitor() {
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof DataSource) {
// 为DataSource添加监控能力
return proxyDataSource((DataSource) bean);
}
return bean;
}
};
}
}
}
/**
* 总结表
*
* 特性 BeanFactoryPostProcessor BeanPostProcessor
* 作用对象 BeanDefinition Bean Instance
* 执行时机 实例化前 初始化前后
* 主要用途 配置修改、属性覆盖、动态注册 AOP、注入、监控、包装
* 执行次数 1次/容器 N次/Bean
* 典型代表 PropertySourcesPlaceholderConfigurer AutowiredAnnotationBeanPostProcessor
*
* 记忆口诀:
* BeanFactoryPostProcessor是"图纸修改师"(改设计方案)
* BeanPostProcessor是"生产线工人"(加工成品)
*/
|
完整实战指南
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
| /**
* 项目实战指南
*/
public class ProjectPracticeGuide {
/**
* 1. BeanFactoryPostProcessor实战:动态数据源切换
*/
@Component
public class DynamicDataSourcePostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
BeanDefinition bd = beanFactory.getBeanDefinition("dataSource");
// 根据环境动态修改数据库连接
String env = System.getProperty("spring.profiles.active");
if ("prod".equals(env)) {
bd.getPropertyValues().add("url", "jdbc:mysql://prod-db:3306/prod");
} else {
bd.getPropertyValues().add("url", "jdbc:mysql://test-db:3306/test");
}
}
}
/**
* 2. BeanPostProcessor实战:全局异常处理
*/
@Component
public class GlobalExceptionHandlerPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 为所有Controller添加统一异常处理
if (bean.getClass().isAnnotationPresent(RestController.class)) {
return Enhancer.create(bean.getClass(), new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
try {
return proxy.invokeSuper(obj, args);
} catch (Exception e) {
// 统一异常处理
return handleException(e);
}
}
});
}
return bean;
}
private ResponseEntity<ErrorResponse> handleException(Exception e) {
// 统一异常处理逻辑
return ResponseEntity.status(500).body(new ErrorResponse(e.getMessage()));
}
}
/**
* 3. 面试常见问题
*/
public class InterviewQA {
// Q: 两者执行顺序是怎样的?
// A: BeanFactoryPostProcessor先执行(refresh中invoke阶段)
// BeanPostProcessor后执行(创建Bean时)
// Q: 能否在BeanFactoryPostProcessor中获取Bean实例?
// A: 不能,因为此时Bean还未实例化,强行获取会导致提前初始化
// Q: 能否在BeanPostProcessor中修改Bean定义?
// A: 不能,因为此时Bean定义已经固化
// Q: 两者各有什么典型应用?
// A: BeanFactoryPostProcessor:占位符替换、配置中心集成
// BeanPostProcessor:AOP、自定义注解、监控增强
}
/**
* 4. 调试技巧
*/
public class DebugTips {
// 断点1: AbstractApplicationContext.invokeBeanFactoryPostProcessors()
// 观察BeanFactoryPostProcessor执行
// 断点2: AbstractAutowireCapableBeanFactory.initializeBean()
// 观察BeanPostProcessor的before/after执行
// 断点3: 自定义PostProcessor的方法内
// 观察具体处理逻辑
}
}
// 面试金句
// "BeanFactoryPostProcessor和BeanPostProcessor就像'建筑设计院'和'装修公司':
// BeanFactoryPostProcessor是'设计院',在房子建造前修改图纸(Bean定义),
// 决定哪里建墙、哪里开窗(修改作用域、属性);
// BeanPostProcessor是'装修公司',在房子建好后进行精装修(增强Bean实例),
// 铺地板、刷墙面(AOP代理、注入依赖)、装监控(性能统计)。
// 在配置中心项目中,我通过BeanFactoryPostProcessor动态替换数据库连接参数,
// 通过BeanPostProcessor为所有Service添加调用链追踪能力,
// 两者配合实现了配置动态化和全链路监控。理解它们的区别,
// 就能在正确的时机用正确的方式扩展Spring。"
|
扩展点
如何修改 Spring 容器中某个 Bean 的属性或行为?
整体解决方案概览
一句话原理:Spring提供多层次的Bean修改机制:配置层面(占位符/配置文件)、定义层面(BeanFactoryPostProcessor)、实例层面(BeanPostProcessor)、运行时层面(@RefreshScope),覆盖从启动到运行时的全生命周期修改需求。
一句话源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| /**
* 修改Bean的四种核心方式对比
*/
public class BeanModificationOverview {
// 1. 配置层面:通过properties/yml修改
// application.yml
// user:
// name: 张三
// age: 25
// 2. 定义层面:BeanFactoryPostProcessor修改BeanDefinition
// 时机:Bean实例化前
// 3. 实例层面:BeanPostProcessor修改Bean实例
// 时机:Bean初始化前后
// 4. 运行时层面:@RefreshScope动态刷新
// 时机:运行时通过配置中心触发
}
|
项目场景:在微服务架构中,需要多维度修改Bean:启动时通过配置中心动态替换数据源连接串(BeanFactoryPostProcessor);运行时调整限流阈值(@RefreshScope);对特定Service添加监控能力(BeanPostProcessor);不同环境加载不同配置文件(PropertySource)。
配置层面:属性占位符与配置文件
一句话原理:通过@Value("${...}")和@ConfigurationProperties将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
| /**
* 配置层面修改示例
*/
@Component
@ConfigurationProperties(prefix = "app.datasource")
@RefreshScope // 支持运行时刷新
public class DataSourceConfig {
private String url;
private String username;
private String password;
private int maxActive = 10;
private int maxIdle = 5;
// getters/setters
}
// application-dev.yml
app:
datasource:
url: jdbc:mysql://dev-db:3306/app
username: dev_user
password: dev_pass
maxActive: 20
// application-prod.yml
app:
datasource:
url: jdbc:mysql://prod-db:3306/app
username: prod_user
password: prod_pass
maxActive: 50
// 使用@Value注解
@Component
public class EmailService {
@Value("${email.host:smtp.default.com}") // 带默认值
private String host;
@Value("${email.port:25}")
private int port;
@Value("${email.timeout:3000}")
private int timeout;
public void sendEmail() {
// 使用配置的属性
}
}
// 动态刷新监听
@Component
public class ConfigChangeListener {
@EventListener
public void handleConfigChange(EnvironmentChangeEvent event) {
System.out.println("配置发生变化: " + event.getKeys());
// 执行重新加载等操作
}
}
|
项目场景:在多环境部署中,通过不同配置文件管理不同环境的数据库连接、Redis地址等,无需修改代码即可实现环境切换。同时结合配置中心,实现运行时动态调整线程池大小、限流阈值等。
3. 定义层面:BeanFactoryPostProcessor修改BeanDefinition
一句话原理:BeanFactoryPostProcessor在Bean实例化前修改BeanDefinition,可以修改属性值、作用域、依赖关系甚至替换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
73
74
75
76
77
78
| /**
* BeanFactoryPostProcessor修改Bean定义
*/
@Component
public class CustomBeanModifier implements BeanFactoryPostProcessor {
private static final Logger log = LoggerFactory.getLogger(CustomBeanModifier.class);
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 1. 修改特定Bean的属性值
modifyDataSourceProperties(beanFactory);
// 2. 根据条件替换Bean实现类
replaceServiceImplementation(beanFactory);
// 3. 动态修改Bean的作用域
modifyBeanScope(beanFactory);
// 4. 添加属性值(如环境标识)
addCommonProperties(beanFactory);
}
private void modifyDataSourceProperties(ConfigurableListableBeanFactory beanFactory) {
BeanDefinition dataSourceDef = beanFactory.getBeanDefinition("dataSource");
// 从配置中心获取实际值
String actualUrl = ConfigCenter.get("db.url");
String actualUser = ConfigCenter.get("db.username");
// 修改Bean定义中的属性值
dataSourceDef.getPropertyValues().add("url", actualUrl);
dataSourceDef.getPropertyValues().add("username", actualUser);
// 添加原来没有的属性
dataSourceDef.getPropertyValues().add("validationQuery", "SELECT 1");
log.info("已修改数据源配置: {}", actualUrl);
}
private void replaceServiceImplementation(ConfigurableListableBeanFactory beanFactory) {
String env = System.getProperty("spring.profiles.active", "dev");
// 根据环境替换Bean实现
if ("test".equals(env)) {
// 测试环境使用Mock实现
BeanDefinition bd = beanFactory.getBeanDefinition("paymentService");
bd.setBeanClassName("com.example.service.MockPaymentService");
} else if ("prod".equals(env)) {
// 生产环境使用真实实现
BeanDefinition bd = beanFactory.getBeanDefinition("paymentService");
bd.setBeanClassName("com.example.service.RealPaymentService");
}
}
private void modifyBeanScope(ConfigurableListableBeanFactory beanFactory) {
// 将某些Bean改为原型作用域
String[] prototypeBeans = {"shoppingCart", "requestContext"};
for (String beanName : prototypeBeans) {
if (beanFactory.containsBeanDefinition(beanName)) {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
bd.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE);
}
}
}
private void addCommonProperties(ConfigurableListableBeanFactory beanFactory) {
// 为所有Service添加环境标识
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
if (beanName.endsWith("Service")) {
bd.getPropertyValues().add("environment",
System.getProperty("spring.profiles.active", "dev"));
}
}
}
}
|
项目场景:在开发通用数据源组件时,通过BeanFactoryPostProcessor动态读取配置中心的数据库连接信息,在Bean实例化前修改数据源配置,实现数据库连接的动态切换,同时支持多租户场景下根据请求头动态选择数据源。
4. 实例层面:BeanPostProcessor修改Bean实例
一句话原理:BeanPostProcessor在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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
| /**
* BeanPostProcessor修改Bean实例
*/
@Component
public class CustomBeanEnhancer implements BeanPostProcessor {
private static final Logger log = LoggerFactory.getLogger(CustomBeanEnhancer.class);
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
// 1. 为特定Bean注入额外属性
if (bean instanceof UserService) {
injectExtraProperties((UserService) bean);
}
// 2. 验证Bean的必需属性
validateRequiredProperties(bean, beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 1. 为所有Service添加性能监控代理
if (beanName.endsWith("Service") || beanName.endsWith("Controller")) {
bean = createPerformanceProxy(bean, beanName);
}
// 2. 为带有@LogExecution的方法添加日志
if (hasLogAnnotation(bean)) {
bean = createLogProxy(bean);
}
// 3. 动态修改Bean属性值(如果支持)
modifyBeanFields(bean, beanName);
return bean;
}
private void injectExtraProperties(UserService userService) {
// 注入当前环境信息
String env = System.getProperty("spring.profiles.active", "dev");
userService.setEnvironment(env);
// 注入应用版本
userService.setAppVersion(getAppVersion());
}
private void validateRequiredProperties(Object bean, String beanName) {
// 检查某些Bean是否配置了必需属性
if (bean instanceof DataSource) {
// 验证数据源配置
}
}
private Object createPerformanceProxy(Object target, String beanName) {
Class<?> targetClass = target.getClass();
return Enhancer.create(targetClass, new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
long start = System.currentTimeMillis();
try {
return proxy.invokeSuper(obj, args);
} finally {
long cost = System.currentTimeMillis() - start;
if (cost > 100) {
log.warn("慢方法监控: {}.{} 耗时 {}ms", beanName, method.getName(), cost);
}
}
}
});
}
private boolean hasLogAnnotation(Object bean) {
return Arrays.stream(bean.getClass().getMethods())
.anyMatch(m -> m.isAnnotationPresent(LogExecution.class));
}
private Object createLogProxy(Object target) {
// 创建日志代理
return Enhancer.create(target.getClass(), new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if (method.isAnnotationPresent(LogExecution.class)) {
LogExecution logExec = method.getAnnotation(LogExecution.class);
log.info("方法开始: {}", logExec.value());
Object result = proxy.invokeSuper(obj, args);
log.info("方法结束: {}", logExec.value());
return result;
}
return proxy.invokeSuper(obj, args);
}
});
}
private void modifyBeanFields(Object bean, String beanName) {
// 反射修改某些字段值(用于测试环境)
if ("dev".equals(System.getProperty("spring.profiles.active"))) {
// 开发环境设置较短的超时时间
setFieldValue(bean, "timeout", 1000);
setFieldValue(bean, "retryCount", 1);
}
}
private void setFieldValue(Object bean, String fieldName, Object value) {
try {
Field field = bean.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(bean, value);
} catch (Exception e) {
// 忽略
}
}
}
|
项目场景:在统一监控平台中,通过BeanPostProcessor为所有Service和Controller添加方法耗时统计,自动上报到监控系统;同时为带有@TraceId注解的方法自动注入链路追踪ID,实现无侵入的监控增强。
5. 运行时层面:@RefreshScope动态刷新
一句话原理:通过@RefreshScope注解结合配置中心(如Spring Cloud Config),在运行时修改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
73
74
75
76
77
| /**
* @RefreshScope动态刷新示例
*/
@RefreshScope // 标记为可刷新
@Component
@ConfigurationProperties(prefix = "app.order")
public class OrderConfig {
private int timeoutSeconds = 30;
private int maxRetries = 3;
private List<String> supportedChannels;
private Map<String, Integer> channelPriorities;
// getters/setters
}
@RefreshScope
@Component
public class DynamicThreadPool {
@Value("${threadpool.core-size:10}")
private int corePoolSize;
@Value("${threadpool.max-size:20}")
private int maxPoolSize;
@Value("${threadpool.queue-size:100}")
private int queueSize;
private ThreadPoolExecutor executor;
@PostConstruct
public void init() {
// 每次刷新都会重新创建线程池
createThreadPool();
}
private void createThreadPool() {
if (executor != null) {
executor.shutdown();
}
executor = new ThreadPoolExecutor(
corePoolSize, maxPoolSize, 60, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(queueSize)
);
log.info("线程池已重新创建: core={}, max={}, queue={}",
corePoolSize, maxPoolSize, queueSize);
}
public void execute(Runnable task) {
executor.execute(task);
}
}
// 配置变更监听
@Component
public class RefreshEventListener {
@EventListener
public void handleRefresh(RefreshEvent event) {
log.info("配置刷新事件触发,相关Bean将被重新创建");
}
}
// 手动触发刷新(通过Spring Cloud Config)
@RestController
public class RefreshController {
@Autowired
private RefreshEndpoint refreshEndpoint;
@PostMapping("/refresh")
public Set<String> refresh() {
// 触发所有@RefreshScope Bean的刷新
return refreshEndpoint.refresh();
}
}
|
项目场景:在微服务网关中,限流阈值、超时时间、路由规则等配置需要随时调整。通过@RefreshScope标记配置类,当配置中心变更时,只需调用/refresh接口,所有相关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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
| /**
* 综合实战:多维度修改Bean
*/
public class ComprehensivePractice {
/**
* 案例:多环境多租户数据源配置
*/
@Configuration
public class DynamicDataSourceConfig {
// 1. 配置层面:基础配置
@Bean
@ConfigurationProperties(prefix = "app.datasource.common")
public DataSourceProperties commonDataSourceProps() {
return new DataSourceProperties();
}
// 2. 定义层面:动态修改BeanDefinition
@Bean
public static BeanFactoryPostProcessor dataSourcePostProcessor() {
return beanFactory -> {
BeanDefinition bd = beanFactory.getBeanDefinition("dataSource");
// 从配置中心获取动态配置
String tenantId = TenantContext.getCurrentTenant();
String dbUrl = ConfigCenter.get("db.url." + tenantId);
bd.getPropertyValues().add("url", dbUrl);
};
}
// 3. 实例层面:增强数据源监控
@Bean
public BeanPostProcessor dataSourceMonitor() {
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof DataSource) {
return proxyDataSource((DataSource) bean);
}
return bean;
}
};
}
// 4. 运行时层面:支持动态刷新
@Bean
@RefreshScope
public DynamicDataSource dynamicDataSource() {
return new DynamicDataSource();
}
}
/**
* 选择指南
*/
public class SelectionGuide {
// 静态配置修改 → @Value/@ConfigurationProperties
// 启动时动态决策 → BeanFactoryPostProcessor
// 功能增强/监控 → BeanPostProcessor
// 运行时热更新 → @RefreshScope
// 测试环境mock → @Primary/@Conditional
}
/**
* 注意事项
*/
public class Precautions {
// 1. BeanFactoryPostProcessor不能获取Bean实例(会提前初始化)
// 2. BeanPostProcessor不能修改BeanDefinition
// 3. @RefreshScope会重新创建Bean,注意状态丢失
// 4. 代理对象要正确处理equals/hashCode
// 5. 考虑多线程环境下的可见性
}
}
/**
* 修改方式总结表
*
* 方式 时机 作用对象 典型场景
* 配置文件 启动时 属性值 环境配置
* BeanFactoryPostProcessor 实例化前 BeanDefinition 动态注册、替换实现类
* BeanPostProcessor 初始化前后 Bean实例 AOP、监控、注入
* @RefreshScope 运行时 Bean实例 配置热更新
*
* 选择原则:
* 越早修改影响越大,越晚修改越灵活
*/
// 面试金句
// "修改Spring Bean就像'改造房子'有四种方式:
// 配置文件是'换家具'(修改属性值),
// BeanFactoryPostProcessor是'改图纸'(在盖房前调整设计方案),
// BeanPostProcessor是'精装修'(房子盖好后添置智能家居),
// @RefreshScope是'智能改造'(随时可以根据心情换墙纸)。
// 在网关项目中,我用BeanFactoryPostProcessor动态选择数据源实现类,
// 用BeanPostProcessor给所有Filter添加日志能力,
// 用@RefreshScope让限流规则实时生效,
// 用@ConfigurationProperties管理不同环境的配置。
// 理解这些层次,才能在正确的时机用正确的方式修改Bean。"
|
如何实现一个自定义的 BeanPostProcessor?在实际项目中用过吗?
自定义BeanPostProcessor核心原理
一句话原理:自定义BeanPostProcessor通过实现BeanPostProcessor接口,重写postProcessBeforeInitialization和postProcessAfterInitialization方法,在Spring容器管理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
| /**
* 自定义BeanPostProcessor基础模板
*/
@Component // 将其注册为Spring Bean
public class CustomBeanPostProcessor implements BeanPostProcessor {
private static final Logger log = LoggerFactory.getLogger(CustomBeanPostProcessor.class);
/**
* 在Bean初始化前执行(在@PostConstruct、InitializingBean之前)
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
// 可以在此处对特定Bean进行预处理
if (bean instanceof SpecialService) {
log.debug("处理特殊Service: {}", beanName);
// 例如:注入额外属性、验证配置等
}
// 可以返回原始bean,也可以返回包装后的代理对象
return bean;
}
/**
* 在Bean初始化后执行(在@PostConstruct、InitializingBean之后)
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 可以在此处对Bean进行增强
if (shouldProxy(bean, beanName)) {
// 返回代理对象替代原始Bean
return createProxy(bean, beanName);
}
return bean;
}
/**
* 判断是否需要为Bean创建代理
*/
private boolean shouldProxy(Object bean, String beanName) {
// 根据Bean类型、名称、注解等条件判断
return beanName.endsWith("Service") ||
bean.getClass().isAnnotationPresent(Monitor.class);
}
/**
* 创建代理对象(示例使用CGLIB)
*/
private Object createProxy(Object target, String beanName) {
return Enhancer.create(target.getClass(), new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
long start = System.currentTimeMillis();
try {
return proxy.invokeSuper(obj, args);
} finally {
long cost = System.currentTimeMillis() - start;
if (cost > 100) {
log.warn("慢方法监控: {}.{} 耗时 {}ms", beanName, method.getName(), cost);
}
}
}
});
}
}
|
项目场景:在统一监控平台项目中,通过自定义BeanPostProcessor为所有标注了@Monitor注解的Bean自动添加性能统计和日志记录功能,无需在每个业务方法中手动编写监控代码,实现了关注点分离。
实战案例一:全局性能监控处理器
一句话原理:实现PerformanceMonitorProcessor,在postProcessAfterInitialization中为所有Service层Bean创建CGLIB代理,自动统计方法执行耗时并上报监控系统,对业务代码零侵入。
一句话源码:
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
| /**
* 全局性能监控BeanPostProcessor
*/
@Component
public class PerformanceMonitorProcessor implements BeanPostProcessor {
private static final Logger log = LoggerFactory.getLogger(PerformanceMonitorProcessor.class);
@Autowired
private MetricsCollector metricsCollector;
@Autowired
private Environment environment;
// 需要排除的Bean名称
private static final Set<String> EXCLUDED_BEANS = Set.of(
"performanceMonitorProcessor", "metricsCollector", "environment"
);
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 1. 排除Spring内部Bean和自身
if (EXCLUDED_BEANS.contains(beanName) || beanName.startsWith("spring")) {
return bean;
}
// 2. 只为特定包下的Bean创建代理(如service、controller、repository)
if (shouldMonitor(bean, beanName)) {
return createMonitorProxy(bean, beanName);
}
return bean;
}
private boolean shouldMonitor(Object bean, String beanName) {
// 检查包名
Package pkg = bean.getClass().getPackage();
if (pkg != null) {
String packageName = pkg.getName();
if (packageName.startsWith("com.example.service") ||
packageName.startsWith("com.example.controller") ||
packageName.startsWith("com.example.repository")) {
return true;
}
}
// 检查注解
if (bean.getClass().isAnnotationPresent(Monitor.class)) {
return true;
}
// 通过配置控制
String[] monitorPackages = environment.getProperty("monitor.packages", String[].class);
if (monitorPackages != null) {
for (String pkgName : monitorPackages) {
if (bean.getClass().getPackage().getName().startsWith(pkgName)) {
return true;
}
}
}
return false;
}
private Object createMonitorProxy(Object target, String beanName) {
Class<?> targetClass = target.getClass();
// 使用CGLIB创建代理
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 跳过toString、hashCode等Object方法
if (method.getDeclaringClass() == Object.class) {
return proxy.invokeSuper(obj, args);
}
String methodName = beanName + "." + method.getName();
long start = System.nanoTime();
try {
// 执行原方法
Object result = proxy.invokeSuper(obj, args);
// 记录成功调用
long cost = (System.nanoTime() - start) / 1_000_000; // 毫秒
metricsCollector.record(methodName, cost, true);
// 慢方法告警
if (cost > 500) {
log.warn("慢方法告警: {} 耗时 {}ms", methodName, cost);
}
return result;
} catch (Throwable t) {
// 记录失败调用
long cost = (System.nanoTime() - start) / 1_000_000;
metricsCollector.record(methodName, cost, false);
// 异常告警
log.error("方法执行异常: {}", methodName, t);
throw t;
}
}
});
return enhancer.create();
}
// 自定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Monitor {
String value() default "";
}
}
|
项目场景:在金融核心系统中,通过该处理器为所有交易服务自动添加性能监控,实时上报到Prometheus+Grafana。上线后发现某个接口响应时间突增,通过监控面板快速定位到问题方法,避免了人工添加监控代码的繁琐工作。
3. 实战案例二:自定义注解处理器
一句话原理:实现LogExecutionProcessor,在postProcessAfterInitialization中扫描Bean的方法上是否有@LogExecution注解,为这些方法创建代理,实现声明式日志,简化日志记录代码。
一句话源码:
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
| /**
* 自定义注解处理器
*/
@Component
public class LogExecutionProcessor implements BeanPostProcessor {
private static final Logger log = LoggerFactory.getLogger(LogExecutionProcessor.class);
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 检查Bean中是否有方法标注@LogExecution
boolean hasLogMethod = Arrays.stream(bean.getClass().getDeclaredMethods())
.anyMatch(m -> m.isAnnotationPresent(LogExecution.class));
if (hasLogMethod) {
return createLogProxy(bean, beanName);
}
return bean;
}
private Object createLogProxy(Object target, String beanName) {
Class<?> targetClass = target.getClass();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 获取方法上的注解
LogExecution logExec = method.getAnnotation(LogExecution.class);
if (logExec != null) {
// 构建日志信息
String logMessage = logExec.value();
if (logMessage.isEmpty()) {
logMessage = beanName + "." + method.getName();
}
// 记录入参
if (logExec.logArgs()) {
log.info("[{}] 开始执行,参数: {}", logMessage, Arrays.toString(args));
} else {
log.info("[{}] 开始执行", logMessage);
}
long start = System.currentTimeMillis();
try {
Object result = proxy.invokeSuper(obj, args);
// 记录出参和耗时
long cost = System.currentTimeMillis() - start;
if (logExec.logResult()) {
log.info("[{}] 执行完成,结果: {},耗时: {}ms", logMessage, result, cost);
} else {
log.info("[{}] 执行完成,耗时: {}ms", logMessage, cost);
}
return result;
} catch (Exception e) {
long cost = System.currentTimeMillis() - start;
log.error("[{}] 执行异常,耗时: {}ms,错误: {}", logMessage, cost, e.getMessage(), e);
throw e;
}
}
// 没有注解,直接执行
return proxy.invokeSuper(obj, args);
}
});
return enhancer.create();
}
// 自定义日志注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecution {
String value() default ""; // 日志描述
boolean logArgs() default true; // 是否记录参数
boolean logResult() default true; // 是否记录结果
}
}
// 使用示例
@Service
public class OrderService {
@LogExecution(value = "创建订单", logArgs = true, logResult = false)
public Order createOrder(OrderRequest request) {
// 业务逻辑
return order;
}
@LogExecution("查询订单")
public Order getOrder(Long orderId) {
return orderRepository.findById(orderId);
}
}
|
项目场景:在业务系统中,通过该注解快速为关键方法添加执行日志,开发人员只需在方法上标注@LogExecution,即可自动记录方法入参、出参、耗时和异常,极大地提高了日志规范性和开发效率。
4. 实战案例三:统一异常处理
一句话原理:实现ExceptionHandlerProcessor,在postProcessAfterInitialization中为所有Controller创建代理,统一捕获异常并转换为标准响应格式,实现全局异常处理的另一种实现方式。
一句话源码:
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
| /**
* 统一异常处理器
*/
@Component
public class ExceptionHandlerProcessor implements BeanPostProcessor {
private static final Logger log = LoggerFactory.getLogger(ExceptionHandlerProcessor.class);
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 只为Controller创建异常处理代理
if (isController(bean)) {
return createExceptionProxy(bean);
}
return bean;
}
private boolean isController(Object bean) {
Class<?> clazz = bean.getClass();
return clazz.isAnnotationPresent(RestController.class) ||
clazz.isAnnotationPresent(Controller.class);
}
private Object createExceptionProxy(Object target) {
Class<?> targetClass = target.getClass();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
try {
return proxy.invokeSuper(obj, args);
} catch (Exception e) {
return handleException(e, method);
}
}
});
return enhancer.create();
}
private ResponseEntity<ErrorResponse> handleException(Exception e, Method method) {
log.error("Controller方法执行异常: {}", method.getName(), e);
// 根据不同异常类型返回不同状态码
if (e instanceof BusinessException) {
BusinessException be = (BusinessException) e;
return ResponseEntity
.status(be.getHttpStatus())
.body(new ErrorResponse(be.getCode(), be.getMessage()));
}
if (e instanceof ValidationException) {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse("400", "参数验证失败: " + e.getMessage()));
}
// 未知异常
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("500", "系统繁忙,请稍后重试"));
}
}
|
项目场景:在遗留系统改造中,原有代码没有统一异常处理,通过该处理器无侵入地添加全局异常处理,所有Controller方法自动获得异常捕获能力,避免了修改大量Controller代码。
5. 实战案例四:配置注入处理器
一句话原理:实现ConfigInjectProcessor,在postProcessBeforeInitialization中为带有@InjectConfig注解的字段自动注入配置值,实现自定义配置注入,补充Spring的@Value功能。
一句话源码:
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
| /**
* 配置注入处理器
*/
@Component
public class ConfigInjectProcessor implements BeanPostProcessor {
@Autowired
private Environment environment;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
// 在初始化前注入配置
injectConfigValues(bean);
return bean;
}
private void injectConfigValues(Object bean) {
Class<?> clazz = bean.getClass();
// 遍历所有字段
for (Field field : clazz.getDeclaredFields()) {
InjectConfig injectConfig = field.getAnnotation(InjectConfig.class);
if (injectConfig != null) {
String key = injectConfig.value();
String defaultValue = injectConfig.defaultValue();
// 从Environment获取配置
String value = environment.getProperty(key, defaultValue);
// 类型转换并注入
Object convertedValue = convertValue(value, field.getType());
try {
field.setAccessible(true);
field.set(bean, convertedValue);
} catch (IllegalAccessException e) {
log.error("注入配置失败: {}.{}", clazz.getSimpleName(), field.getName(), e);
}
}
}
}
private Object convertValue(String value, Class<?> targetType) {
if (targetType == String.class) {
return value;
}
if (targetType == Integer.class || targetType == int.class) {
return Integer.parseInt(value);
}
if (targetType == Long.class || targetType == long.class) {
return Long.parseLong(value);
}
if (targetType == Boolean.class || targetType == boolean.class) {
return Boolean.parseBoolean(value);
}
if (targetType == List.class) {
return Arrays.asList(value.split(","));
}
return value;
}
// 自定义注入注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectConfig {
String value(); // 配置key
String defaultValue() default ""; // 默认值
}
}
// 使用示例
@Component
public class EmailSender {
@InjectConfig(value = "email.host", defaultValue = "smtp.qq.com")
private String host;
@InjectConfig("email.port")
private int port;
@InjectConfig(value = "email.timeout", defaultValue = "3000")
private int timeout;
@InjectConfig(value = "email.admin.emails", defaultValue = "admin@example.com")
private List<String> adminEmails;
public void send() {
System.out.println("发送邮件到: " + host + ":" + port);
}
}
|
项目场景:在第三方SDK集成时,需要从配置文件读取大量参数,通过该处理器和自定义注解,实现简洁的配置注入,比在每个字段上加@Value更灵活,且支持List等复杂类型的自动转换。
完整实战指南
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
| /**
* 自定义BeanPostProcessor完整指南
*/
public class BeanPostProcessorGuide {
/**
* 1. 执行顺序控制
*/
@Component
@Order(1) // 数字越小优先级越高
public class FirstProcessor implements BeanPostProcessor {
// 优先执行
}
@Component
@Order(2)
public class SecondProcessor implements BeanPostProcessor {
// 后执行
}
// 或者实现Ordered接口
@Component
public class OrderedProcessor implements BeanPostProcessor, Ordered {
@Override
public int getOrder() {
return 0; // 返回优先级
}
}
/**
* 2. 注意事项
*/
public class Precautions {
// 1. BeanPostProcessor本身也会被其他BeanPostProcessor处理,注意循环
// 2. 不要在这里做耗时操作,会影响应用启动速度
// 3. 返回的可能是代理对象,注意类型转换
// 4. 考虑多线程安全问题
// 5. 避免在postProcessBeforeInitialization中创建新线程
}
/**
* 3. 调试技巧
*/
public class DebugTips {
// 断点位置1: AbstractAutowireCapableBeanFactory.initializeBean()
// 观察BeanPostProcessor调用栈
// 断点位置2: 自定义Processor的方法内
// 观察Bean处理过程
// 启动参数: -Ddebug=true 查看详细日志
}
/**
* 4. 性能考虑
*/
public class PerformanceConsideration {
// 每个Bean都会经过所有BeanPostProcessor
// 应快速判断是否需要处理,避免不必要的操作
// 优化示例
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 快速过滤
if (!beanName.startsWith("com.example.service")) {
return bean;
}
// 缓存需要代理的Bean类型
// 使用ConcurrentHashMap缓存判断结果
}
}
}
/**
* 自定义BeanPostProcessor总结表
*
* 类型 执行时机 典型应用
* Before初始化 postProcessBeforeInitialization 配置注入、属性验证
* After初始化 postProcessAfterInitialization AOP代理、监控增强
*
* 应用场景:
* 1. 性能监控:为方法添加耗时统计
* 2. 日志增强:注解驱动的方法日志
* 3. 异常处理:统一异常捕获
* 4. 配置注入:自定义配置注入
* 5. 权限校验:方法级权限检查
* 6. 缓存处理:自动添加缓存能力
*/
// 面试金句
// "自定义BeanPostProcessor就像给Spring装上了'智能加工中心':
// 每个Bean从流水线上下来时,都会经过这个加工中心。
// postProcessBeforeInitialization是'粗加工'(注入配置、验证属性),
// postProcessAfterInitialization是'精加工'(添加监控、生成代理)。
// 在监控平台项目中,我通过自定义BeanPostProcessor为所有Service自动添加性能统计,
// 业务代码零入侵,上线后快速发现慢方法,帮团队解决了性能瓶颈。
// 另一个项目用自定义注解+BeanPostProcessor实现声明式缓存,
// 开发效率提升了30%。理解BeanPostProcessor,就能在Spring框架之上构建自己的增强能力。"
|
Spring 中 Bean 的初始化顺序如何控制?@DependsOn 注解的作用?
Bean初始化顺序控制整体方案
一句话原理:Spring提供多层级的初始化顺序控制机制:通过@DependsOn声明显式依赖,通过@Order或Ordered接口控制同一类型Bean的加载顺序,通过@Lazy实现延迟加载,通过@Priority影响候选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
| /**
* 初始化顺序控制方式概览
*/
@Configuration
public class OrderControlOverview {
// 1. @DependsOn - 显式指定依赖关系
@Bean
@DependsOn({"dataSource", "cacheManager"})
public UserService userService() {
return new UserService();
}
// 2. @Order - 控制集合类中Bean的顺序
@Bean
@Order(1)
public Filter firstFilter() {
return new FirstFilter();
}
@Bean
@Order(2)
public Filter secondFilter() {
return new SecondFilter();
}
// 3. @Lazy - 延迟初始化
@Bean
@Lazy
public HeavyResource heavyResource() {
return new HeavyResource(); // 首次使用时才创建
}
// 4. Ordered接口 - 编程式指定顺序
@Bean
public PriorityBean priorityBean() {
return new PriorityBean();
}
}
// 5. SmartLifecycle - 控制容器启动/关闭顺序
@Component
public class CustomLifecycle implements SmartLifecycle {
@Override
public void start() {
// 在所有Bean初始化完成后执行
}
@Override
public int getPhase() {
return Integer.MAX_VALUE; // 数字越小启动越早
}
}
|
项目场景:在微服务启动时,需要严格控制初始化顺序:数据源最先初始化,其次是缓存管理器,然后是业务服务,最后是消息监听器。通过@DependsOn和SmartLifecycle的组合,确保了所有依赖都已就绪后才启动核心服务。
@DependsOn注解深度解析
一句话原理:@DependsOn用于强制指定当前Bean所依赖的其他Bean,确保被依赖的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
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
| /**
* @DependsOn源码及使用示例
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DependsOn {
String[] value() default {}; // 指定依赖的Bean名称
}
// 使用示例1:在配置类方法上
@Configuration
public class DatabaseConfig {
@Bean
public DataSource dataSource() {
return new HikariDataSource();
}
@Bean
@DependsOn("dataSource") // 确保dataSource先初始化
public DatabaseInitializer databaseInitializer() {
return new DatabaseInitializer(); // 需要数据库连接
}
}
// 使用示例2:在组件类上
@Component
@DependsOn({"cacheManager", "messageSource"})
public class OrderService {
private final CacheManager cacheManager;
private final MessageSource messageSource;
// 即使没有显式注入,Spring也会确保这两个Bean先初始化
public OrderService() {
// 构造函数
}
}
// 使用示例3:多个依赖
@Bean
@DependsOn({"dataSource", "redisTemplate", "rabbitTemplate"})
public DataInitializer dataInitializer() {
return new DataInitializer(); // 需要所有基础设施就绪
}
// 源码中的处理逻辑
public class DependsOnProcessor {
// AbstractBeanFactory.registerDependentBean()
public void registerDependentBean(String beanName, String dependentBeanName) {
// 记录依赖关系:dependentBeanName依赖于beanName
// 如果beanName还没初始化,先初始化它
if (!containsSingleton(beanName)) {
getBean(beanName); // 强制提前初始化
}
}
}
|
项目场景:在系统启动时需要执行数据库脚本初始化,但脚本执行必须依赖数据源和Flyway迁移工具。通过@DependsOn({"dataSource", "flyway"})确保这两个Bean先初始化,然后执行初始化脚本,避免了数据源未就绪就执行SQL的错误。
3. 复杂场景实战:多模块初始化顺序控制
一句话原理:在复杂系统中,通过组合使用@DependsOn、@Order、SmartLifecycle和ApplicationListener,实现分阶段、分模块的精细化初始化控制,满足各种业务场景需求。
一句话源码:
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
73
74
75
76
77
78
79
| /**
* 复杂场景实战:微服务启动顺序控制
*/
@Configuration
public class ComplexOrderControl {
// 第一阶段:基础设施初始化
@Bean
public DataSource dataSource() {
return new HikariDataSource(); // 最先初始化
}
@Bean
@DependsOn("dataSource")
public ConnectionPool connectionPool() {
return new ConnectionPool(); // 依赖数据源
}
// 第二阶段:缓存系统初始化
@Bean
@DependsOn("connectionPool")
public RedisCacheManager redisCacheManager() {
return new RedisCacheManager(); // 依赖连接池
}
// 第三阶段:业务服务初始化(依赖多个)
@Bean
@DependsOn({"redisCacheManager", "rabbitMQConnection"})
public UserService userService() {
return new UserService();
}
// 第四阶段:消息监听器(最后启动)
@Bean
@DependsOn("userService")
public MessageListener messageListener() {
return new MessageListener(); // 确保业务服务已就绪
}
// 使用SmartLifecycle控制启动后的执行顺序
@Component
public class StartupTasks implements SmartLifecycle {
private volatile boolean running = false;
@Override
public void start() {
// 所有Bean初始化完成后执行
performStartupTasks();
running = true;
}
private void performStartupTasks() {
// 1. 数据预热
cacheWarmer.warmup();
// 2. 注册服务到注册中心
serviceRegistry.register();
// 3. 发送启动事件
applicationContext.publishEvent(new AppStartedEvent(this));
}
@Override
public void stop() {
running = false;
}
@Override
public boolean isRunning() {
return running;
}
@Override
public int getPhase() {
return Integer.MAX_VALUE; // 最后执行
}
}
}
|
项目场景:在微服务架构中,服务启动需要按阶段进行:基础设施(数据源、连接池)→ 中间件(Redis、RabbitMQ)→ 业务服务(UserService、OrderService)→ 消息监听器。通过@DependsOn构建清晰的依赖链,确保每个组件都在其依赖就绪后才初始化。
4. @Order注解与Ordered接口
一句话原理:@Order和Ordered接口用于控制同一类型多个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
73
74
75
76
77
78
79
80
| /**
* @Order和Ordered使用示例
*/
// 1. 使用@Order注解
@Component
@Order(1)
public class FirstFilter implements Filter {
@Override
public void doFilter() {
System.out.println("第一个过滤器");
}
}
@Component
@Order(2)
public class SecondFilter implements Filter {
@Override
public void doFilter() {
System.out.println("第二个过滤器");
}
}
// 2. 实现Ordered接口
@Component
public class FirstInterceptor implements OrderedInterceptor {
@Override
public int getOrder() {
return 1; // 数字越小越靠前
}
}
@Component
public class SecondInterceptor implements OrderedInterceptor {
@Override
public int getOrder() {
return 2;
}
}
// 3. 在集合注入时保持顺序
@Configuration
public class OrderedCollection {
@Autowired
private List<Filter> filters; // 会按照@Order排序
@PostConstruct
public void init() {
// filters已经是排好序的
filters.forEach(Filter::doFilter);
}
// 4. 使用@Order控制配置类加载顺序
@Configuration
@Order(1)
public static class DatabaseConfig {
// 优先加载
}
@Configuration
@Order(2)
public static class ServiceConfig {
// 后加载
}
}
// 源码中的排序逻辑
public class AnnotationAwareOrderComparator {
public static void sort(List<?> list) {
list.sort(INSTANCE);
}
public int compare(Object o1, Object o2) {
// 获取@Order或Ordered的值进行比较
int order1 = getOrder(o1);
int order2 = getOrder(o2);
return Integer.compare(order1, order2);
}
}
|
项目场景:在Spring Security中,通过@Order控制多个过滤器的执行顺序,确保认证过滤器在授权过滤器之前执行;在事件监听器中,通过@Order保证核心监听器优先处理事件,辅助监听器后处理。
5. 实战案例:多数据源初始化顺序控制
一句话原理:在多数据源场景中,通过@DependsOn控制主数据源先初始化,从数据源后初始化,同时通过事件监听确保数据源就绪后执行表结构检查和数据预热。
一句话源码:
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
| /**
* 多数据源初始化实战
*/
@Configuration
public class MultiDataSourceConfig {
// 主库 - 最先初始化
@Bean
@Primary
@ConfigurationProperties("spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
// 从库 - 依赖主库
@Bean
@DependsOn("masterDataSource")
@ConfigurationProperties("spring.datasource.slave")
public DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}
// 数据库初始化脚本执行器 - 依赖所有数据源
@Bean
@DependsOn({"masterDataSource", "slaveDataSource"})
public DatabaseInitializer databaseInitializer() {
return new DatabaseInitializer();
}
}
@Component
public class DatabaseInitializer {
private static final Logger log = LoggerFactory.getLogger(DatabaseInitializer.class);
private final DataSource masterDataSource;
private final DataSource slaveDataSource;
public DatabaseInitializer(DataSource masterDataSource, DataSource slaveDataSource) {
this.masterDataSource = masterDataSource;
this.slaveDataSource = slaveDataSource;
}
@PostConstruct
public void init() {
log.info("开始执行数据库初始化...");
// 1. 检查表是否存在
checkTables(masterDataSource);
// 2. 执行初始化脚本
executeInitScripts(masterDataSource);
// 3. 同步数据到从库
syncToSlave();
log.info("数据库初始化完成");
}
private void checkTables(DataSource dataSource) {
// 表结构检查
}
private void executeInitScripts(DataSource dataSource) {
// 执行SQL脚本
}
private void syncToSlave() {
// 主从同步
}
}
// 监听数据库初始化完成事件
@Component
public class DatabaseReadyListener {
@EventListener
@Order(1) // 优先处理
public void handleDbReady(DatabaseInitializedEvent event) {
log.info("数据库已就绪,开始加载业务数据");
// 加载业务数据
}
@EventListener
@Order(2) // 后处理
public void sendNotification(DatabaseInitializedEvent event) {
log.info("数据库初始化完成,发送通知");
// 发送通知给其他服务
}
}
|
项目场景:在分库分表系统中,需要先初始化主库,再初始化从库,然后执行表结构检查,最后进行数据预热。通过@DependsOn构建清晰的依赖链,配合@EventListener和@Order控制事件处理顺序,确保了多数据源的正确初始化。
完整实战指南
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
73
74
75
76
77
78
79
80
81
82
83
| /**
* 初始化顺序控制完整指南
*/
public class OrderControlGuide {
/**
* 1. 控制方式总结表
*/
public class ControlMethods {
// 方式 作用范围 执行时机 典型场景
// @DependsOn Bean级别 初始化前 显式依赖声明
// @Order 同类型Bean 初始化后 过滤器、拦截器顺序
// Ordered接口 同类型Bean 初始化后 同@Order
// @Lazy Bean级别 首次使用时 大对象延迟加载
// SmartLifecycle 全局 初始化完成后 启动任务
// @Priority Bean候选 依赖注入时 同一类型多个候选
}
/**
* 2. 常见问题与解决方案
*/
public class CommonProblems {
// 问题1:循环依赖导致的顺序问题
// 解决:使用@Lazy打破循环
// 问题2:隐式依赖无法被Spring识别
// 解决:使用@DependsOn显式声明
// 问题3:多个同类型Bean顺序混乱
// 解决:使用@Order或Ordered接口
// 问题4:需要在所有Bean初始化后执行任务
// 解决:实现SmartLifecycle或监听ContextRefreshedEvent
}
/**
* 3. 调试技巧
*/
public class DebugTips {
// 1. 开启DEBUG日志
// logging.level.org.springframework.beans.factory.support=DEBUG
// 2. 断点位置
// - AbstractBeanFactory.doGetBean() 观察Bean创建顺序
// - DefaultListableBeanFactory.preInstantiateSingletons() 观察初始化顺序
// 3. 查看依赖关系图
// 使用Spring Boot Actuator的/beans端点
}
/**
* 4. 最佳实践
*/
public class BestPractices {
// 1. 优先依赖Spring自动装配,而不是强制指定顺序
// 2. 必须控制顺序时,首选@DependsOn
// 3. 同类型Bean顺序用@Order
// 4. 启动后任务用SmartLifecycle或事件监听
// 5. 避免使用@DependsOn创建循环依赖
}
}
/**
* 控制方式对比表
*
* 注解/接口 作用 示例 注意事项
* @DependsOn 显式声明Bean依赖 @DependsOn("dataSource") 可能导致循环依赖
* @Order 同类型Bean优先级 @Order(1) 不控制初始化顺序
* Ordered 同Order 实现getOrder() 同@Order
* @Lazy 延迟初始化 @Lazy 代理对象
* SmartLifecycle 容器生命周期回调 getPhase() 启动/关闭顺序
*/
// 面试金句
// "Spring Bean初始化顺序控制就像'交响乐团'的出场顺序:
// @DependsOn是'首席先出场'(大提琴必须在指挥之前就位),
// @Order是'演奏顺序'(第一乐章、第二乐章),
// SmartLifecycle是'谢幕顺序'(首席最后退场)。
// 在微服务启动中,我用@DependsOn确保数据源先于缓存初始化,
// 用@Order控制多个过滤器的执行顺序,
// 用SmartLifecycle在所有Bean就绪后注册服务到注册中心。
// 理解这些机制,才能精确控制系统的启动流程,避免因初始化顺序导致的诡异问题。"
|