一、Spring扩展点概述
Spring框架之所以强大,很大程度上归功于其丰富的扩展点设计。这些扩展点允许开发者在Spring容器的不同生命周期阶段介入,实现自定义逻辑,大大增强了框架的灵活性。
二、BeanDefinition注册阶段的扩展点
2.1 动态注册BeanDefinition的三种方式
在Spring启动过程中,我们可以通过以下三种方式动态注册BeanDefinition:
2.1.1 BeanDefinitionRegistryPostProcessor
@Component
public class MyBeanDefinitionRegistryPostProcessor
implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// 动态注册BeanDefinition
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(XushuService.class);
BeanDefinition beanDefinition = builder.getBeanDefinition();
// 设置属性
beanDefinition.getPropertyValues().add("age", 18);
beanDefinition.setLazyInit(true);
// 注册到容器
registry.registerBeanDefinition("xushuService3", beanDefinition);
}
@Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) {
// 可以修改已有的BeanDefinition
}
}
特点:
-
可以注册新的BeanDefinition
-
可以修改已有的BeanDefinition
-
执行时机早,适合需要早期干预的场景
2.1.2 BeanFactoryPostProcessor
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) {
// 只能修改已有的BeanDefinition,不能注册新的
BeanDefinition beanDefinition = beanFactory
.getBeanDefinition("existingBean");
beanDefinition.setLazyInit(true);
}
}
特点:
-
只能修改已有BeanDefinition
-
不能注册新的BeanDefinition
2.1.3 ImportBeanDefinitionRegistrar
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
// 注册新的BeanDefinition
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClassName("com.example.MyBean");
registry.registerBeanDefinition("myBean", beanDefinition);
}
}
// 使用@Import注解引入
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class AppConfig {
}
特点:
-
需要结合@Import注解使用
-
可以获取@Import注解所在类的元数据信息
-
没有Bean的生命周期,但支持部分Aware接口
2.2 三种方式的对比
| 扩展点 | 注册新BeanDefinition | 修改已有BeanDefinition | 获取注解元数据 | 生命周期支持 |
|---|---|---|---|---|
| BeanDefinitionRegistryPostProcessor | ✅ | ✅ | ❌ | ✅ |
| BeanFactoryPostProcessor | ❌ | ✅ | ❌ | ✅ |
| ImportBeanDefinitionRegistrar | ✅ | ❌ | ✅ | 部分Aware |
三、Bean创建过程的扩展点
3.1 BeanPostProcessor:Bean的后置处理器
BeanPostProcessor是Spring中最重要的扩展点之一,它在Bean的创建过程中提供了多个介入点:
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
// 初始化前调用
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("初始化前: " + beanName);
return bean;
}
// 初始化后调用
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("初始化后: " + beanName);
return bean;
}
}
3.1.1 特殊的BeanPostProcessor
Spring还提供了一些更细粒度的BeanPostProcessor:
-
InstantiationAwareBeanPostProcessor:实例化前后介入
-
SmartInstantiationAwareBeanPostProcessor:可以指定构造函数
-
MergedBeanDefinitionPostProcessor:修改合并后的BeanDefinition
-
DestructionAwareBeanPostProcessor:销毁前介入
3.2 Aware接口:感知Spring容器组件
Aware接口允许Bean感知到Spring容器中的特定组件,相比@Autowired,Aware接口的执行时机更早:
@Component
public class MyAwareComponent implements
EnvironmentAware, ApplicationContextAware {
private Environment environment;
private ApplicationContext applicationContext;
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
// 可以获取配置信息
String property = environment.getProperty("my.property");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
// 可以获取容器中的其他Bean
}
}
Spring内置的Aware接口调用顺序:
-
BeanNameAware、BeanClassLoaderAware、BeanFactoryAware(通过invokeAwareMethods调用)
-
EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware(通过ApplicationContextAwareProcessor调用)
3.3 生命周期回调
Spring提供了多种生命周期回调方式,执行顺序如下:
@Component
public class LifecycleBean implements InitializingBean, DisposableBean {
// 1. 构造方法
public LifecycleBean() {
System.out.println("1. 构造方法");
}
// 2. @PostConstruct(JSR-250)
@PostConstruct
public void postConstruct() {
System.out.println("2. @PostConstruct");
}
// 3. InitializingBean接口
@Override
public void afterPropertiesSet() {
System.out.println("3. InitializingBean.afterPropertiesSet()");
}
// 4. 自定义init-method
public void customInit() {
System.out.println("4. 自定义init-method");
}
// 销毁顺序(与初始化相反)
@PreDestroy
public void preDestroy() {
System.out.println("5. @PreDestroy");
}
@Override
public void destroy() {
System.out.println("6. DisposableBean.destroy()");
}
public void customDestroy() {
System.out.println("7. 自定义destroy-method");
}
}
四、容器加载完毕的扩展点
4.1 SmartInitializingSingleton:所有单例Bean创建完成后调用
@Component
public class MySmartInitializingSingleton implements SmartInitializingSingleton {
@Override
public void afterSingletonsInstantiated() {
System.out.println("所有单例Bean创建完成后调用");
// 适合需要依赖所有Bean都创建完成的初始化工作
}
}
特点:
-
在所有单例Bean创建完成后调用
-
相比@PostConstruct,执行时机更晚
-
可以确保依赖的所有Bean都已就绪
4.2 SmartLifecycle:与容器同生命周期的组件
@Component
public class MyLifecycle implements SmartLifecycle {
private boolean isRunning = false;
private ScheduledFuture<?> scheduledFuture;
@Override
public void start() {
System.out.println("容器启动,组件开始运行");
isRunning = true;
// 启动定时任务
scheduledFuture = Executors.newSingleThreadScheduledExecutor()
.scheduleAtFixedRate(this::doTask, 0, 1, TimeUnit.SECONDS);
}
@Override
public void stop() {
System.out.println("容器关闭,组件停止运行");
isRunning = false;
// 停止定时任务
if (scheduledFuture != null) {
scheduledFuture.cancel(false);
}
}
@Override
public boolean isRunning() {
return isRunning;
}
private void doTask() {
System.out.println("执行定时任务");
}
}
适用场景:
-
定时任务组件
-
资源预热
-
缓存预热/清理
-
需要随容器启动/关闭的组件
4.3 ContextRefreshedEvent:容器刷新完成事件
@Component
public class ContextRefreshedEventListener {
// 方式1:实现ApplicationListener接口
// @Component
// public class ContextRefreshedEventListener
// implements ApplicationListener<ContextRefreshedEvent> {
// @Override
// public void onApplicationEvent(ContextRefreshedEvent event) {
// System.out.println("容器加载完毕");
// }
// }
// 方式2:使用@EventListener注解(推荐)
@EventListener(ContextRefreshedEvent.class)
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("容器加载完毕,所有Bean已就绪");
}
// 异步事件处理
@Async
@EventListener(ContextRefreshedEvent.class)
public void onApplicationEventAsync(ContextRefreshedEvent event) {
System.out.println("异步处理容器加载完成事件");
}
}
五、综合案例:动态线程池实现
5.1 需求分析
传统线程池的问题:
-
参数难以确定,需要根据实际情况调整
-
修改参数需要重启服务
-
运行情况难以监控
目标:实现一个可动态调整、可监控的线程池
5.2 实现步骤
步骤1:定义配置类
# application.yml
spring:
dtp:
executors:
- poolName: dtpExecutor1
corePoolSize: 5
maximumPoolSize: 10
keepAliveTime: 60
queueSize: 100
- poolName: dtpExecutor2
corePoolSize: 2
maximumPoolSize: 8
keepAliveTime: 30
queueSize: 50
@Data
public class DtpProperties {
private List<ThreadPoolProperties> executors;
}
@Data
public class ThreadPoolProperties {
private String poolName;
private int corePoolSize = 1;
private int maximumPoolSize = 1;
private long keepAliveTime;
private TimeUnit timeUnit = TimeUnit.SECONDS;
private String queueType = "arrayBlockingQueue";
private int queueSize = 5;
}
步骤2:动态注册BeanDefinition
@Slf4j
public class DtpBeanDefinitionRegistrar implements
ImportBeanDefinitionRegistrar, EnvironmentAware {
private Environment environment;
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
// 绑定配置
BindResult<DtpProperties> bindResult = Binder.get(environment)
.bind("spring.dtp", DtpProperties.class);
DtpProperties dtpProperties = bindResult.get();
List<ThreadPoolProperties> executors = dtpProperties.getExecutors();
if (executors == null || executors.isEmpty()) {
log.info("未检测到配置文件线程池");
return;
}
// 动态注册线程池Bean
for (ThreadPoolProperties properties : executors) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(DtpThreadPoolExecutor.class);
builder.addConstructorArgValue(properties);
registry.registerBeanDefinition(
properties.getPoolName(),
builder.getBeanDefinition()
);
}
}
}
// 自定义线程池类
public class DtpThreadPoolExecutor extends ThreadPoolExecutor {
public DtpThreadPoolExecutor(ThreadPoolProperties executorProp) {
super(
executorProp.getCorePoolSize(),
executorProp.getMaximumPoolSize(),
executorProp.getKeepAliveTime(),
executorProp.getTimeUnit(),
new ArrayBlockingQueue<>(executorProp.getQueueSize())
);
}
}
步骤3:线程池注册与管理
public class DtpRegistry {
private static final Map<String, ThreadPoolExecutor>
EXECUTOR_MAP = new ConcurrentHashMap<>();
// 注册线程池
public static void registry(String executorName, ThreadPoolExecutor executor) {
EXECUTOR_MAP.put(executorName, executor);
}
// 获取线程池
public static ThreadPoolExecutor getExecutor(String executorName) {
return EXECUTOR_MAP.get(executorName);
}
// 刷新线程池参数
public static void refresh(String executorName, ThreadPoolProperties properties) {
ThreadPoolExecutor executor = EXECUTOR_MAP.get(executorName);
if (executor != null) {
executor.setCorePoolSize(properties.getCorePoolSize());
executor.setMaximumPoolSize(properties.getMaximumPoolSize());
// 其他参数刷新...
}
}
}
// 使用BeanPostProcessor注册线程池
@Component
public class DtpBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof DtpThreadPoolExecutor) {
DtpRegistry.registry(beanName, (ThreadPoolExecutor) bean);
}
return bean;
}
}
步骤4:动态修改参数(事件机制)
// 自定义事件
public class DtpEvent extends ApplicationEvent {
private ThreadPoolProperties properties;
public DtpEvent(ThreadPoolProperties properties) {
super(properties);
this.properties = properties;
}
public ThreadPoolProperties getProperties() {
return properties;
}
}
// 事件监听器
@Component
public class DtpEventListener {
@EventListener(DtpEvent.class)
public void onApplicationEvent(DtpEvent event) {
ThreadPoolProperties properties = event.getProperties();
DtpRegistry.refresh(properties.getPoolName(), properties);
}
}
// 控制器
@RestController
@RequestMapping("/dtp")
public class DtpController implements ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;
@PostMapping("/refresh")
public String refresh(@RequestBody ThreadPoolProperties properties) {
applicationEventPublisher.publishEvent(new DtpEvent(properties));
return "success!";
}
@Override
public void setApplicationEventPublisher(
ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
}
步骤5:线程池监控与告警
@Component
public class DtpMonitor implements SmartLifecycle {
private ScheduledFuture<?> scheduledFuture;
private boolean isRunning = false;
@Override
public void start() {
// 启动定时监控任务
scheduledFuture = Executors.newSingleThreadScheduledExecutor()
.scheduleAtFixedRate(() -> {
monitor();
alarm();
}, 5, 5, TimeUnit.SECONDS);
isRunning = true;
}
@Override
public void stop() {
if (scheduledFuture != null) {
scheduledFuture.cancel(false);
}
isRunning = false;
}
@Override
public boolean isRunning() {
return isRunning;
}
private void monitor() {
for (String name : DtpRegistry.getAllExecutorNames()) {
ThreadPoolExecutor executor = DtpRegistry.getExecutor(name);
log.info("线程池[{}]状态: 核心线程数={}, 最大线程数={}, 活跃线程数={}, 队列大小={}",
name, executor.getCorePoolSize(), executor.getMaximumPoolSize(),
executor.getActiveCount(), executor.getQueue().size());
}
}
private void alarm() {
// 读取告警阈值配置
int alarmThreshold = 10;
for (ThreadPoolExecutor executor : DtpRegistry.getAllDtpExecutor()) {
int activeCount = executor.getActiveCount();
if (activeCount >= alarmThreshold) {
// 发送告警(邮件、短信、钉钉等)
log.warn("线程池告警: 活跃线程数{}超过阈值{}",
activeCount, alarmThreshold);
}
}
}
}
步骤6:封装成插件
// 启用注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(DtpImportSelector.class)
public @interface EnableDynamicThreadPool {
}
// ImportSelector实现
public class DtpImportSelector implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {
DtpBeanDefinitionRegistrar.class.getName(),
DtpBeanPostProcessor.class.getName(),
DtpMonitor.class.getName()
};
}
}
// 使用方式
@SpringBootApplication
@EnableDynamicThreadPool
public class DynamicThreadpoolApplication {
public static void main(String[] args) {
SpringApplication.run(DynamicThreadpoolApplication.class, args);
}
}
六、扩展点最佳实践总结
6.1 选择合适扩展点的原则
-
按执行时机选择:
-
BeanDefinition注册阶段:
BeanDefinitionRegistryPostProcessor、ImportBeanDefinitionRegistrar -
Bean创建阶段:
BeanPostProcessor、Aware接口 -
容器启动完成:
SmartInitializingSingleton、SmartLifecycle、事件监听
-
-
按功能需求选择:
-
动态注册Bean:
BeanDefinitionRegistryPostProcessor或ImportBeanDefinitionRegistrar -
修改已有Bean:
BeanFactoryPostProcessor -
Bean创建过程干预:
BeanPostProcessor -
获取容器组件:Aware接口
-
启动完成后的初始化:
SmartInitializingSingleton -
生命周期管理:
SmartLifecycle
-
6.2 注意事项
-
执行顺序问题:
-
扩展点的执行顺序很重要,特别是多个扩展点之间
-
可以使用
Ordered或@Order注解控制顺序
-
-
性能考虑:
-
BeanPostProcessor会对每个Bean都执行,避免在其中做耗时操作 -
合理使用缓存,避免重复计算
-
-
异常处理:
-
扩展点中的异常可能导致Spring启动失败
-
做好异常捕获和处理
-
七、结语
Spring IOC容器的扩展点设计体现了框架的开放封闭原则 和依赖倒置原则。通过合理使用这些扩展点,我们可以:
-
增强框架能力:在不修改Spring源码的情况下扩展功能
-
提高灵活性:实现动态配置、热更新等高级特性
-
统一生命周期管理:确保组件与容器同生命周期
-
提升可维护性:将扩展逻辑集中管理,代码更清晰