一、简要介绍
Dynamic-TP 是基于配置中心的轻量级动态线程池,内置监控告警功能,集成常用中间件线程池管理,可通过SPI自定义扩展实现
项目github仓库:GitHub - dromara/dynamic-tp
项目官网: https://dynamictp.cn
参考资料:
Spring容器生命周期和bean生命周期的基础知识:
Spring之Bean的生命周期_spring bean的生命周期-CSDN博客
Aware原理_environmentaware-CSDN博客
Spring的Lifecycle和SmartLifecycle,可以没用过,但不能不知道!-CSDN博客
Spring之BeanPostProcessor-CSDN博客
Spring-ImportBeanDefinitionRegistrar接口介绍-CSDN博客
Spring扩展点在SpringCloud微服务组件中的应用(一)_@role(beandefinition.role_infrastructure)-CSDN博客
简要总结整个spring容器和bean的生命周期:
二、core模块的spring依赖分析
1. DtpBeanDefinitionRegistrar和DtpBaseBeanDefinitionRegistrar
ImportBeanDefinitionRegistrar
接口是Spring提供的一种扩展点,允许我们在运行时动态地向Spring容器中注册Bean。它的执行时机是在Spring的配置类被解析并且Bean定义被加载到容器后,但是在Bean实例化之前。
具体的执行顺序如下:
-
Spring启动,加载配置文件(如XML配置文件或者@Configuration注解的Java配置类)。
-
解析配置文件,将Bean的定义信息(如类名、作用域、懒加载、依赖等)加载到Spring容器中。
-
如果配置类中使用了
@Import
注解导入了实现了ImportBeanDefinitionRegistrar
接口的类,那么Spring会调用这个类的registerBeanDefinitions
方法,允许我们在这个时机向容器中注册新的Bean。 -
Spring开始实例化Bean。首先实例化非懒加载的单例Bean,然后根据需要实例化其他Bean。
-
如果Bean实现了
InitializingBean
接口,那么在Bean被实例化后,Spring会调用它的afterPropertiesSet
方法。如果Bean的定义信息中配置了初始化方法,那么Spring会调用这个初始化方法。 -
最后,如果配置类中使用了
@Import
注解导入了实现了ImportSelector
接口的类,那么Spring会在所有Bean都被初始化后,调用这个类的selectImports
方法,允许我们在这个时机向容器中注册新的Bean。
所以,ImportBeanDefinitionRegistrar
接口的执行时机是在Bean定义被加载到容器后,但是在Bean实例化之前。
(1)DtpBeanDefinitionRegistrar
- 主要用于注册
DtpExecutor
类型的 bean - 从配置文件中读取线程池的配置属性
- 根据配置的执行器类型(
ExecutorType
)创建不同类型的线程池执行器 bean,如EagerDtpExecutor
、PriorityDtpExecutor
等 - 设置线程池执行器的各种属性,如核心线程数、最大线程数、队列类型、拒绝策略等
- 将创建好的线程池执行器 bean 注册到 Spring 容器中
(a)registerBeanDefinitions
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 获取DtpProperties的单例实例
DtpProperties dtpProperties = DtpProperties.getInstance();
// 使用环境变量绑定DtpProperties实例的属性
BinderHelper.bindDtpProperties(environment, dtpProperties);
// 从DtpProperties实例中获取执行器列表
val executors = dtpProperties.getExecutors();
// 如果执行器列表为空,则记录警告日志并返回
if (CollectionUtils.isEmpty(executors)) {
log.warn("DynamicTp registrar, no executors are configured.");
return;
}
// 遍历执行器列表
executors.forEach(e -> {
// 根据执行器类型获取对应的类
Class<?> executorTypeClass = ExecutorType.getClass(e.getExecutorType());
// 构建bean定义的属性值
Map<String, Object> propertyValues = buildPropertyValues(e);
// 构建bean定义的构造函数参数
Object[] args = buildConstructorArgs(executorTypeClass, e);
// 将bean定义注册到Spring容器
SpringBeanHelper.register(registry, e.getThreadPoolName(), executorTypeClass, propertyValues, args);
});
}
注册过程中主要用到buildPropertyValues来映射配置,buildConstructorArgs来构建参数集合。
(b)buildPropertyValues
buildPropertyValues把所有参数映射成<prop_name,prop_value>
(c)buildConstructorArgs
buildConstructorArgs
方法的主要作用是构建用于创建dtpProperties配置的executors中的每一个executorTypeClass(common 、eager 、ordered 、priority 、scheduled )的bean定义的构造函数参数。它创建了一个对象数组,这些对象将用作bean的构造函数的参数,主要用于创建线程池执行器的构造函数参数,包括核心线程池大小、最大线程池大小、线程保持活动的时间、时间单位、任务队列、线程工厂和拒绝处理器。
private Object[] buildConstructorArgs(Class<?> clazz, DtpExecutorProps props) {
// 根据执行器的类型和属性,创建一个阻塞队列
BlockingQueue<Runnable> taskQueue;
if (clazz.equals(EagerDtpExecutor.class)) {
// 如果执行器类型是EagerDtpExecutor,创建一个TaskQueue
taskQueue = new TaskQueue(props.getQueueCapacity());
} else if (clazz.equals(PriorityDtpExecutor.class)) {
// 如果执行器类型是PriorityDtpExecutor,创建一个优先级阻塞队列
taskQueue = new PriorityBlockingQueue<>(props.getQueueCapacity(), PriorityDtpExecutor.getRunnableComparator());
} else {
// 否则,根据队列类型、容量、能否被抢占和最大空闲内存创建一个阻塞队列
taskQueue = buildLbq(props.getQueueType(),
props.getQueueCapacity(),
props.isFair(),
props.getMaxFreeMemory());
}
// 返回一个对象数组,这些对象将用作bean的构造函数的参数
return new Object[]{
props.getCorePoolSize(), // 核心线程池大小
props.getMaximumPoolSize(), // 最大线程池大小
props.getKeepAliveTime(), // 线程保持活动的时间
props.getUnit(), // 时间单位
taskQueue, // 任务队列
new NamedThreadFactory(props.getThreadNamePrefix()), // 线程工厂
RejectHandlerGetter.buildRejectedHandler(props.getRejectedHandlerType()) // 拒绝策略
};
}
(2)DtpBaseBeanDefinitionRegistrar
- 注册一些基础的 bean,包括
ApplicationContextHolder
、HashedWheelTimer
和DtpPostProcessor
ApplicationContextHolder
用于持有应用上下文HashedWheelTimer
用于执行定时任务DtpPostProcessor
是一个 Bean 后置处理器,可以进一步增强或修改 bean
2. DtpLifecycle
SmartLifecycle
是Spring框架中的一个接口,它扩展了Lifecycle
接口,添加了对Spring容器的生命周期的管理。SmartLifecycle
接口定义了以下方法:
-
start()
: 启动组件。在Spring应用上下文的刷新阶段结束后,将调用实现SmartLifecycle
接口的bean的start()
方法。 -
stop()
: 停止组件。在Spring应用上下文关闭时,将调用实现SmartLifecycle
接口的bean的stop()
方法。 -
isRunning()
: 返回组件是否正在运行。如果组件正在运行,则返回true
;否则,返回false
。 -
stop(Runnable callback)
: 停止组件,并在停止后运行一个回调。这是一个可选的操作。 -
isAutoStartup()
: 返回组件是否在Spring应用上下文的刷新阶段结束后自动启动。如果组件在Spring应用上下文的刷新阶段结束后自动启动,则返回true
;否则,返回false
。 -
getPhase()
: 返回组件的阶段。Spring应用上下文在启动或关闭时,将按照阶段的顺序启动或关闭组件。阶段的值越小,组件越早启动,并且越晚关闭。
3. DtpPostProcessor
BeanPostProcessor接口定义了修改新bean实例的回调。Spring IoC容器在创建bean实例、设置bean属性和连接bean的自动装配之后,以及在初始化方法(如afterPropertiesSet或自定义的初始化方法)之前和之后,将调用BeanPostProcessor。
postProcessBeforeInitialization(Object bean, String beanName): 此方法在bean初始化之前被调用,在这里它直接返回了bean实例,没有做任何处理。
postProcessAfterInitialization(Object bean, String beanName): 此方法在bean初始化之后被调用。
可以看到它区分bean是否是ThreadPoolExecutor或ThreadPoolTaskExecutor的实例,如果是,它会将这些bean注册到DtpRegistry中,并返回一个代理对象。如果bean是DtpExecutor的实例,它会创建一个增强的bean,并将其注册到DtpRegistry中。
4. DtpConfigurationSelector
DtpConfigurationSelector实现了Spring的DeferredImportSelector,Ordered和EnvironmentAware接口,下面简要说明这些接口:
- DeferredImportSelector接口允许我们在运行时动态地添加需要被Spring容器管理的bean。selectImports方法返回一个包含全类名的字符串数组,这些类将被Spring容器管理。
Ordered接口定义了一个getOrder方法,该方法返回一个整数值,表示在Spring容器中的加载顺序。值越小,优先级越高。
EnvironmentAware接口允许我们获取到Spring容器的环境变量。setEnvironment方法用于设置环境变量。
主要说明一下selectImports方法:
selectImports(AnnotationMetadata metadata)
位于 ImportSelector
接口中,它用于在配置类中动态添加需要导入的类,根据传入的 AnnotationMetadata
对象(该对象包含当前配置类的注解信息),返回一个字符串数组,数组中的每个字符串表示需要被导入到容器中的完全限定类名。
DeferredImportSelector
继承了 ImportSelector
接口, 它的 selectImports
方法用于延迟导入配置类,通过使用 DeferredImportSelector
,可以有选择性地在运行时动态导入配置类,而避免在启动时就加载所有的配置类。这种延迟导入的机制可以提高应用启动时的性能,因为只有在真正需要时才会加载相关的配置类。