开源动态线程池组件 Dynamic-TP 学习记录(三) -- core模块的 spring 生命周期分析

文章介绍了Dynamic-TP,一个基于配置中心的轻量级动态线程池,它利用Spring的扩展点如ImportBeanDefinitionRegistrar和SmartLifecycle进行自定义扩展,管理Spring容器中的线程池。详细解释了核心模块的依赖分析和Spring容器与bean的生命周期管理过程。
摘要由CSDN通过智能技术生成

   一、简要介绍

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实例化之前。

具体的执行顺序如下:

  1. Spring启动,加载配置文件(如XML配置文件或者@Configuration注解的Java配置类)。

  2. 解析配置文件,将Bean的定义信息(如类名、作用域、懒加载、依赖等)加载到Spring容器中。

  3. 如果配置类中使用了@Import注解导入了实现了ImportBeanDefinitionRegistrar接口的类,那么Spring会调用这个类的registerBeanDefinitions方法,允许我们在这个时机向容器中注册新的Bean。

  4. Spring开始实例化Bean。首先实例化非懒加载的单例Bean,然后根据需要实例化其他Bean。

  5. 如果Bean实现了InitializingBean接口,那么在Bean被实例化后Spring会调用它的afterPropertiesSet方法。如果Bean的定义信息中配置了初始化方法,那么Spring会调用这个初始化方法。

  6. 最后,如果配置类中使用了@Import注解导入了实现了ImportSelector接口的类,那么Spring会在所有Bean都被初始化后,调用这个类的selectImports方法,允许我们在这个时机向容器中注册新的Bean。

所以,ImportBeanDefinitionRegistrar接口的执行时机是在Bean定义被加载到容器后,但是在Bean实例化之前。

(1)DtpBeanDefinitionRegistrar

  1. 主要用于注册 DtpExecutor 类型的 bean
  2. 从配置文件中读取线程池的配置属性
  3. 根据配置的执行器类型(ExecutorType)创建不同类型的线程池执行器 bean,如 EagerDtpExecutorPriorityDtpExecutor
  4. 设置线程池执行器的各种属性,如核心线程数、最大线程数、队列类型、拒绝策略等
  5. 将创建好的线程池执行器 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

  1. 注册一些基础的 bean,包括 ApplicationContextHolderHashedWheelTimerDtpPostProcessor
  2. ApplicationContextHolder 用于持有应用上下文
  3. HashedWheelTimer 用于执行定时任务
  4. DtpPostProcessor 是一个 Bean 后置处理器,可以进一步增强或修改 bean

 2. DtpLifecycle

SmartLifecycle是Spring框架中的一个接口,它扩展了Lifecycle接口,添加了对Spring容器的生命周期的管理。SmartLifecycle接口定义了以下方法:

  1. start(): 启动组件。在Spring应用上下文的刷新阶段结束后,将调用实现SmartLifecycle接口的bean的start()方法。

  2. stop(): 停止组件。在Spring应用上下文关闭时,将调用实现SmartLifecycle接口的bean的stop()方法。

  3. isRunning(): 返回组件是否正在运行。如果组件正在运行,则返回true;否则,返回false

  4. stop(Runnable callback): 停止组件,并在停止后运行一个回调。这是一个可选的操作。

  5. isAutoStartup(): 返回组件是否在Spring应用上下文的刷新阶段结束后自动启动。如果组件在Spring应用上下文的刷新阶段结束后自动启动,则返回true;否则,返回false

  6. 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接口,下面简要说明这些接口:  

  1. DeferredImportSelector接口允许我们在运行时动态地添加需要被Spring容器管理的bean。selectImports方法返回一个包含全类名的字符串数组,这些类将被Spring容器管理。  
  2. Ordered接口定义了一个getOrder方法,该方法返回一个整数值,表示在Spring容器中的加载顺序。值越小,优先级越高。  
  3. EnvironmentAware接口允许我们获取到Spring容器的环境变量。setEnvironment方法用于设置环境变量。

主要说明一下selectImports方法:

selectImports(AnnotationMetadata metadata) 位于 ImportSelector 接口中,它用于在配置类中动态添加需要导入的类,根据传入的 AnnotationMetadata 对象(该对象包含当前配置类的注解信息),返回一个字符串数组,数组中的每个字符串表示需要被导入到容器中的完全限定类名。

DeferredImportSelector 继承了 ImportSelector 接口, 它的 selectImports 方法用于延迟导入配置类,通过使用 DeferredImportSelector,可以有选择性地在运行时动态导入配置类,而避免在启动时就加载所有的配置类。这种延迟导入的机制可以提高应用启动时的性能,因为只有在真正需要时才会加载相关的配置类。

  • 24
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值