基于Nacos自动刷新ThreadPoolExecutor线程池参数

业务上为了支撑动态刷新线程池核心参数,所以集成Nacos配置中心实现自动刷新。

前提是系统已经集成Nacos相关依赖,比如

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>     
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>       

做了个注解启动动态线程池开关@EnableDiversityThreadPool,使用时加在启动类即可

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import({DtpFactory.class})
public @interface EnableDiversityThreadPool {

    /**
     * 初始化IO密集型线程池
     */
    boolean initIOPool() default true;

    /**
     * 初始化CPU密集型线程池
     */
    boolean initCPUPool() default true;

    /**
     * 初始化优先级调度线程池
     */
    boolean initPriorityPool() default true;

    /**
     * 初始化future任务线程池,若关闭,则默认使用ForkJoinPool
     */
    boolean initFuturePool() default true;

    /**
     * 自动扩容核心线程
     */
    boolean autoExpansion() default true;

    /**
     * 是否回收核心线程
     */
    boolean allowCoreThreadTimeOut() default false;

    /**
     * 线程空闲存活时间,超过则回收 单位:TimeUnit.SECONDS
     */
    long keepAliveTime() default 5;
}

注册Nacos配置监听回调方法即可,基于注解@ConditionalOnClass(value = NacosConfigManager.class)实现自动装配。
基于Spring容器启动事件ApplicationStartedEvent @EventListener实现监听注册

import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.AbstractListener;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ByteArrayResource;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.Map;

import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;

/**
 * @author rui.wang
 * @ Version: 1.0
 * @ Time: 2023/5/16 17:28
 * @ Description:
 */
@Slf4j
@Configuration
@ConditionalOnClass(value = NacosConfigManager.class)
public class NacosEventListenerConfiguration {

    @Autowired
    private NacosConfigManager nacosConfigManager;

    @Autowired
    private Environment environment;

    @Resource
    private DtpProperties dtpProperties;

    @EventListener
    public void listener(ApplicationStartedEvent event) throws NacosException {
        EnableDiversityThreadPool annotation = AnnotationUtils.getAnnotation(event.getSpringApplication().getMainApplicationClass(),
                EnableDiversityThreadPool.class);
        if (annotation != null) {
            init();
        }
    }

    public void init() throws NacosException {
        Listener listener = new AbstractListener() {
            @Override
            public void receiveConfigInfo(String configInfo) {
                val properties = doParse(configInfo);
                bindDtpProperties(properties, dtpProperties);
                log.info("Nacos config refresh dtpProperties:{}", dtpProperties.toString());
                doRefresh(dtpProperties);
            }
        };
        String[] profiles = environment.getActiveProfiles();
        if (profiles.length < 1) {
            profiles = environment.getDefaultProfiles();
        }

        String appName = environment.getProperty("spring.application.name");
        appName = StringUtils.isNoneBlank(appName) ? appName : "application";

        String fileType = environment.getProperty("spring.cloud.nacos.config.file-extension");
        fileType = StringUtils.isNoneBlank(fileType) ? fileType : "yml";

        String group = environment.getProperty("spring.cloud.nacos.config.group");
        group = StringUtils.isNoneBlank(group) ? group : DEFAULT_GROUP;

        String dataId = appName + "-" + profiles[0] + "." + fileType;
        nacosConfigManager.getConfigService().addListener(dataId, group, listener);
        log.info("Nacos dtp config eventListener resistry success");
    }

    private void doRefresh(DtpProperties dtpProperties) {
        DtpContext.IO_POOL.fixPoolSize(dtpProperties.getCorePoolSizeIO(), dtpProperties.getMaximumPoolSizeIO());
        DtpContext.CPU_POOL.fixPoolSize(dtpProperties.getCorePoolSizeCPU(), dtpProperties.getMaximumPoolSizeCPU());
        DtpContext.PRIORITY_POOL.fixPoolSize(dtpProperties.getCorePoolSizePriority(), dtpProperties.getMaximumPoolSizePriority());
        DtpContext.FUTURE_POOL.fixPoolSize(dtpProperties.getCorePoolSizeFuture(), dtpProperties.getMaximumPoolSizePriority());
        DtpContext.IO_POOL.autoExpansion.set(dtpProperties.isAutoExpansion());
        DtpContext.CPU_POOL.autoExpansion.set(dtpProperties.isAutoExpansion());
        DtpContext.PRIORITY_POOL.autoExpansion.set(dtpProperties.isAutoExpansion());
    }

    private Map<Object, Object> doParse(String configInfo) {
        if (StringUtils.isEmpty(configInfo)) {
            return Collections.emptyMap();
        }
        YamlPropertiesFactoryBean bean = new YamlPropertiesFactoryBean();
        bean.setResources(new ByteArrayResource(configInfo.getBytes()));
        return bean.getObject();
    }

    public static void bindDtpProperties(Map<?, Object> properties, DtpProperties dtpProperties) {
        ConfigurationPropertySource sources = new MapConfigurationPropertySource(properties);
        Binder binder = new Binder(sources);
        ResolvableType type = ResolvableType.forClass(DtpProperties.class);
        Bindable<?> target = Bindable.of(type).withExistingValue(dtpProperties);
        binder.bind("spring.dynamic.tp", target);
    }
}

Properties

@Slf4j
@Data
@Component
@ConfigurationProperties(prefix = "spring.dynamic.tp")
public class DtpProperties {

    /**
     * IO密集型线程池核心线程数
     */
    private int corePoolSizeIO = 1;

    /**
     * IO密集型线程池最大线程数
     */
    private int maximumPoolSizeIO = 1;

    /**
     * CPU密集型线程池核心线程数
     */
    private int corePoolSizeCPU = 1;

    /**
     * CPU密集型线程池最大线程数
     */
    private int maximumPoolSizeCPU = 1;

    /**
     * 优先级线程池核心线程数
     */
    private int corePoolSizePriority = 1;

    /**
     * 优先级线程池最大线程数
     */
    private int maximumPoolSizePriority = 1;

    /**
     * future线程池核心线程数
     */
    private int corePoolSizeFuture = 1;

    /**
     * future线程池最大线程数
     */
    private int maximumPoolSizeFuture = 1;

    /**
     * 阻塞队列默认容量
     */
    private int poolQueueSize = 1000;

    /**
     * 是否开启自动扩容核心线程
     */
    private boolean autoExpansion = true;

}

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值