diff --git a/.github/checkstyle/checkstyle.xml b/.github/checkstyle/checkstyle.xml index 643c0d45e..988f52ebe 100644 --- a/.github/checkstyle/checkstyle.xml +++ b/.github/checkstyle/checkstyle.xml @@ -1,7 +1,7 @@ + "-//Puppy Crawl//DTD Check Configuration 1.3//EN" + "http://www.puppycrawl.com/dtds/configuration_1_3.dtd"> @@ -182,4 +182,4 @@ - + \ No newline at end of file diff --git a/.github/workflows/build-jvmti.yml b/.github/workflows/build-jvmti.yml index 1f19e0fc3..0806969cb 100644 --- a/.github/workflows/build-jvmti.yml +++ b/.github/workflows/build-jvmti.yml @@ -7,10 +7,10 @@ jobs: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 - - name: Set up JDK 8 + - name: Set up JDK 17 uses: actions/setup-java@v3 with: - java-version: '8' + java-version: '17' distribution: 'adopt' - name: Build with Maven run: | @@ -26,10 +26,10 @@ jobs: runs-on: macos-latest steps: - uses: actions/checkout@v3 - - name: Set up JDK 8 + - name: Set up JDK 17 uses: actions/setup-java@v3 with: - java-version: '8' + java-version: '17' distribution: 'adopt' - name: Build with Maven run: | @@ -45,10 +45,10 @@ jobs: runs-on: windows-2019 steps: - uses: actions/checkout@v3 - - name: Set up JDK 8 + - name: Set up JDK 17 uses: actions/setup-java@v3 with: - java-version: '8' + java-version: '17' distribution: 'adopt' - name: Build with Maven run: | diff --git a/.github/workflows/maven-build.yml b/.github/workflows/maven-build.yml index 3a4a4a09f..15bdffe4e 100644 --- a/.github/workflows/maven-build.yml +++ b/.github/workflows/maven-build.yml @@ -10,9 +10,9 @@ name: Java CI with Maven on: push: - branches: [ "master" ] + branches: [ "springboot3" ] pull_request: - branches: [ "master" ] + branches: [ "springboot3" ] jobs: build: @@ -21,10 +21,10 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up JDK 8 + - name: Set up JDK 17 uses: actions/setup-java@v3 with: - java-version: '8' + java-version: '17' distribution: 'temurin' cache: maven - name: Build with Maven diff --git a/adapter/adapter-common/src/main/java/org/dromara/dynamictp/adapter/common/AbstractDtpAdapter.java b/adapter/adapter-common/src/main/java/org/dromara/dynamictp/adapter/common/AbstractDtpAdapter.java index 53b68371d..6af80d9e3 100644 --- a/adapter/adapter-common/src/main/java/org/dromara/dynamictp/adapter/common/AbstractDtpAdapter.java +++ b/adapter/adapter-common/src/main/java/org/dromara/dynamictp/adapter/common/AbstractDtpAdapter.java @@ -29,7 +29,7 @@ import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; import org.dromara.dynamictp.common.entity.NotifyPlatform; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; import org.dromara.dynamictp.common.entity.TpExecutorProps; import org.dromara.dynamictp.common.entity.TpMainFields; import org.dromara.dynamictp.common.event.CustomContextRefreshedEvent; @@ -104,20 +104,20 @@ public Map getExecutorWrappers() { } /** - * Get multi thread pool stats. + * Get multi executor stats. * - * @return thead pools stats + * @return Executors stats */ @Override - public List getMultiPoolStats() { + public List getMultiExecutorStats() { val executorWrappers = getExecutorWrappers(); if (MapUtils.isEmpty(executorWrappers)) { return Collections.emptyList(); } - List threadPoolStats = Lists.newArrayList(); - executorWrappers.forEach((k, v) -> threadPoolStats.add(ExecutorConverter.toMetrics(v))); - return threadPoolStats; + List executorStats = Lists.newArrayList(); + executorWrappers.forEach((k, v) -> executorStats.add(ExecutorConverter.toMetrics(v))); + return executorStats; } public void refresh(List propsList, List platforms) { diff --git a/adapter/adapter-common/src/main/java/org/dromara/dynamictp/adapter/common/DtpAdapterListener.java b/adapter/adapter-common/src/main/java/org/dromara/dynamictp/adapter/common/DtpAdapterListener.java index c061c714e..759cbeda2 100644 --- a/adapter/adapter-common/src/main/java/org/dromara/dynamictp/adapter/common/DtpAdapterListener.java +++ b/adapter/adapter-common/src/main/java/org/dromara/dynamictp/adapter/common/DtpAdapterListener.java @@ -29,7 +29,6 @@ import org.dromara.dynamictp.common.properties.DtpProperties; import org.dromara.dynamictp.core.handler.CollectorHandler; import org.dromara.dynamictp.core.notifier.manager.AlarmManager; - import java.util.EventObject; import static org.dromara.dynamictp.common.constant.DynamicTpConst.SCHEDULE_NOTIFY_ITEMS; @@ -74,7 +73,7 @@ protected void doCollect(DtpProperties dtpProperties) { if (MapUtils.isEmpty(handlerMap)) { return; } - handlerMap.forEach((k, v) -> v.getMultiPoolStats().forEach(ps -> + handlerMap.forEach((k, v) -> v.getMultiExecutorStats().forEach(ps -> CollectorHandler.getInstance().collect(ps, dtpProperties.getCollectorTypes()))); } diff --git a/adapter/adapter-grpc/pom.xml b/adapter/adapter-grpc/pom.xml index 24fa4a61d..8d9c307e3 100644 --- a/adapter/adapter-grpc/pom.xml +++ b/adapter/adapter-grpc/pom.xml @@ -31,7 +31,6 @@ ${grpc.version} true - diff --git a/common/src/main/java/org/dromara/dynamictp/common/constant/DynamicTpConst.java b/common/src/main/java/org/dromara/dynamictp/common/constant/DynamicTpConst.java index 847c529f7..579d9af4b 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/constant/DynamicTpConst.java +++ b/common/src/main/java/org/dromara/dynamictp/common/constant/DynamicTpConst.java @@ -127,4 +127,9 @@ private DynamicTpConst() { } public static final String TRUE_STR = "true"; public static final String FALSE_STR = "false"; + + /** + * jre + */ + public static final String THREAD_PER_TASK_EXECUTOR = "java.util.concurrent.ThreadPerTaskExecutor"; } diff --git a/common/src/main/java/org/dromara/dynamictp/common/em/JreEnum.java b/common/src/main/java/org/dromara/dynamictp/common/em/JreEnum.java index ca4e60552..b0e95d258 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/em/JreEnum.java +++ b/common/src/main/java/org/dromara/dynamictp/common/em/JreEnum.java @@ -54,12 +54,18 @@ public enum JreEnum { JAVA_18, - JAVA_19; + JAVA_19, + + JAVA_20, + + JAVA_21; private static final JreEnum VERSION = getJre(); public static final String DEFAULT_JAVA_VERSION = "1.8"; + private static final int JRE_VERSION_OFFSET = 8; + /** * get current JRE version * @@ -69,6 +75,14 @@ public static JreEnum currentVersion() { return VERSION; } + /** + * get current JRE integer version + * @return JRE integer version + */ + public static int currentIntVersion() { + return JreEnum.currentVersion().ordinal() + JRE_VERSION_OFFSET; + } + /** * is current version * diff --git a/common/src/main/java/org/dromara/dynamictp/common/entity/ThreadPoolStats.java b/common/src/main/java/org/dromara/dynamictp/common/entity/ExecutorStats.java similarity index 91% rename from common/src/main/java/org/dromara/dynamictp/common/entity/ThreadPoolStats.java rename to common/src/main/java/org/dromara/dynamictp/common/entity/ExecutorStats.java index 06b4928b1..ac86972e6 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/entity/ThreadPoolStats.java +++ b/common/src/main/java/org/dromara/dynamictp/common/entity/ExecutorStats.java @@ -22,24 +22,24 @@ /** - * ThreadPoolStats related + * ExecutorStats related * * @author yanhom * @since 1.0.0 **/ @Data @EqualsAndHashCode(callSuper = true) -public class ThreadPoolStats extends Metrics { +public class ExecutorStats extends Metrics { /** - * 线程池名字 + * 执行器名字 */ - private String poolName; + private String executorName; /** - * 线程池别名 + * 执行器别名 */ - private String poolAliasName; + private String executorAliasName; /** * 核心线程数 @@ -51,6 +51,31 @@ public class ThreadPoolStats extends Metrics { */ private int maximumPoolSize; + /** + * 正在执行任务的活跃线程大致总数 + */ + private int activeCount; + + /** + * 大致任务总数 + */ + private long taskCount; + + /** + * 执行超时任务数量 + */ + private long runTimeoutCount; + + /** + * 是否为DtpExecutor + */ + private boolean dynamic; + + /** + * 是否为虚拟线程执行器 + */ + private boolean isVirtualExecutor; + /** * 空闲时间 (ms) */ @@ -81,16 +106,6 @@ public class ThreadPoolStats extends Metrics { */ private int queueRemainingCapacity; - /** - * 正在执行任务的活跃线程大致总数 - */ - private int activeCount; - - /** - * 大致任务总数 - */ - private long taskCount; - /** * 已执行完成的大致任务总数 */ @@ -121,16 +136,6 @@ public class ThreadPoolStats extends Metrics { */ private String rejectHandlerName; - /** - * 是否DtpExecutor线程池 - */ - private boolean dynamic; - - /** - * 执行超时任务数量 - */ - private long runTimeoutCount; - /** * 在队列等待超时任务数量 */ @@ -185,4 +190,5 @@ public class ThreadPoolStats extends Metrics { * 满足99.9%的任务执行所需的最低耗时 */ private double tp999; + } diff --git a/common/src/main/java/org/dromara/dynamictp/common/entity/Metrics.java b/common/src/main/java/org/dromara/dynamictp/common/entity/Metrics.java index e7f464f43..c7209eae0 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/entity/Metrics.java +++ b/common/src/main/java/org/dromara/dynamictp/common/entity/Metrics.java @@ -27,4 +27,5 @@ **/ @Data public class Metrics { + } diff --git a/core/pom.xml b/core/pom.xml index 33f0b83bc..df9940d4e 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -24,7 +24,6 @@ io.micrometer micrometer-core - true @@ -37,16 +36,6 @@ transmittable-thread-local - - com.fasterxml.jackson.core - jackson-core - - - - com.fasterxml.jackson.core - jackson-databind - - cn.hutool hutool-core diff --git a/core/src/main/java/org/dromara/dynamictp/core/DtpRegistry.java b/core/src/main/java/org/dromara/dynamictp/core/DtpRegistry.java index ac1518bdf..392e515ec 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/DtpRegistry.java +++ b/core/src/main/java/org/dromara/dynamictp/core/DtpRegistry.java @@ -242,7 +242,6 @@ private static void doRefreshCommon(ExecutorWrapper executorWrapper, DtpExecutor if (StringUtils.isNotBlank(props.getThreadPoolAliasName())) { executorWrapper.setThreadPoolAliasName(props.getThreadPoolAliasName()); } - ExecutorAdapter executor = executorWrapper.getExecutor(); // update reject handler String currentRejectHandlerType = executor.getRejectHandlerType(); diff --git a/core/src/main/java/org/dromara/dynamictp/core/aware/MetricsAware.java b/core/src/main/java/org/dromara/dynamictp/core/aware/MetricsAware.java index 335b0ad08..a8e8dee62 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/aware/MetricsAware.java +++ b/core/src/main/java/org/dromara/dynamictp/core/aware/MetricsAware.java @@ -17,7 +17,7 @@ package org.dromara.dynamictp.core.aware; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; import java.util.Collections; import java.util.List; @@ -31,20 +31,20 @@ public interface MetricsAware extends DtpAware { /** - * Get thread pool stats. + * Get executors stats. * - * @return the thread pool stats + * @return the executors stats */ - default ThreadPoolStats getPoolStats() { + default ExecutorStats getExecutorStats() { return null; } /** - * Get multi thread pool stats. + * Get multi executors stats. * - * @return thead pools stats + * @return executors stats */ - default List getMultiPoolStats() { + default List getMultiExecutorStats() { return Collections.emptyList(); } } diff --git a/core/src/main/java/org/dromara/dynamictp/core/converter/ExecutorConverter.java b/core/src/main/java/org/dromara/dynamictp/core/converter/ExecutorConverter.java index 3688755f1..b5da89dab 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/converter/ExecutorConverter.java +++ b/core/src/main/java/org/dromara/dynamictp/core/converter/ExecutorConverter.java @@ -18,7 +18,7 @@ package org.dromara.dynamictp.core.converter; import lombok.val; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; import org.dromara.dynamictp.common.entity.TpMainFields; import org.dromara.dynamictp.core.executor.DtpExecutor; import org.dromara.dynamictp.core.monitor.PerformanceProvider; @@ -53,7 +53,7 @@ public static TpMainFields toMainFields(ExecutorWrapper executorWrapper) { return mainFields; } - public static ThreadPoolStats toMetrics(ExecutorWrapper wrapper) { + public static ExecutorStats toMetrics(ExecutorWrapper wrapper) { ExecutorAdapter executor = wrapper.getExecutor(); if (executor == null) { return null; @@ -61,43 +61,45 @@ public static ThreadPoolStats toMetrics(ExecutorWrapper wrapper) { ThreadPoolStatProvider provider = wrapper.getThreadPoolStatProvider(); PerformanceProvider performanceProvider = provider.getPerformanceProvider(); val performanceSnapshot = performanceProvider.getSnapshotAndReset(); - ThreadPoolStats poolStats = convertCommon(executor); - poolStats.setPoolName(wrapper.getThreadPoolName()); - poolStats.setPoolAliasName(wrapper.getThreadPoolAliasName()); - poolStats.setRunTimeoutCount(provider.getRunTimeoutCount()); - poolStats.setQueueTimeoutCount(provider.getQueueTimeoutCount()); - poolStats.setRejectCount(provider.getRejectedTaskCount()); - poolStats.setDynamic(executor instanceof DtpExecutor); + ExecutorStats executorStats = convertCommon(executor); + executorStats.setExecutorName(wrapper.getThreadPoolName()); + executorStats.setExecutorAliasName(wrapper.getThreadPoolAliasName()); + executorStats.setRunTimeoutCount(provider.getRunTimeoutCount()); + executorStats.setQueueTimeoutCount(provider.getQueueTimeoutCount()); + executorStats.setRejectCount(provider.getRejectedTaskCount()); - poolStats.setTps(performanceSnapshot.getTps()); - poolStats.setAvg(performanceSnapshot.getAvg()); - poolStats.setMaxRt(performanceSnapshot.getMaxRt()); - poolStats.setMinRt(performanceSnapshot.getMinRt()); - poolStats.setTp50(performanceSnapshot.getTp50()); - poolStats.setTp75(performanceSnapshot.getTp75()); - poolStats.setTp90(performanceSnapshot.getTp90()); - poolStats.setTp95(performanceSnapshot.getTp95()); - poolStats.setTp99(performanceSnapshot.getTp99()); - poolStats.setTp999(performanceSnapshot.getTp999()); - return poolStats; + executorStats.setVirtualExecutor(wrapper.isVirtualThreadExecutor()); + + executorStats.setDynamic(executor instanceof DtpExecutor); + executorStats.setTps(performanceSnapshot.getTps()); + executorStats.setAvg(performanceSnapshot.getAvg()); + executorStats.setMaxRt(performanceSnapshot.getMaxRt()); + executorStats.setMinRt(performanceSnapshot.getMinRt()); + executorStats.setTp50(performanceSnapshot.getTp50()); + executorStats.setTp75(performanceSnapshot.getTp75()); + executorStats.setTp90(performanceSnapshot.getTp90()); + executorStats.setTp95(performanceSnapshot.getTp95()); + executorStats.setTp99(performanceSnapshot.getTp99()); + executorStats.setTp999(performanceSnapshot.getTp999()); + return executorStats; } - private static ThreadPoolStats convertCommon(ExecutorAdapter executor) { - ThreadPoolStats poolStats = new ThreadPoolStats(); - poolStats.setCorePoolSize(executor.getCorePoolSize()); - poolStats.setMaximumPoolSize(executor.getMaximumPoolSize()); - poolStats.setPoolSize(executor.getPoolSize()); - poolStats.setActiveCount(executor.getActiveCount()); - poolStats.setLargestPoolSize(executor.getLargestPoolSize()); - poolStats.setQueueType(executor.getQueueType()); - poolStats.setQueueCapacity(executor.getQueueCapacity()); - poolStats.setQueueSize(executor.getQueueSize()); - poolStats.setQueueRemainingCapacity(executor.getQueueRemainingCapacity()); - poolStats.setTaskCount(executor.getTaskCount()); - poolStats.setCompletedTaskCount(executor.getCompletedTaskCount()); - poolStats.setWaitTaskCount(executor.getQueueSize()); - poolStats.setRejectHandlerName(executor.getRejectHandlerType()); - poolStats.setKeepAliveTime(executor.getKeepAliveTime(TimeUnit.MILLISECONDS)); - return poolStats; + private static ExecutorStats convertCommon(ExecutorAdapter executor) { + ExecutorStats executorStats = new ExecutorStats(); + executorStats.setCorePoolSize(executor.getCorePoolSize()); + executorStats.setMaximumPoolSize(executor.getMaximumPoolSize()); + executorStats.setPoolSize(executor.getPoolSize()); + executorStats.setActiveCount(executor.getActiveCount()); + executorStats.setLargestPoolSize(executor.getLargestPoolSize()); + executorStats.setQueueType(executor.getQueueType()); + executorStats.setQueueCapacity(executor.getQueueCapacity()); + executorStats.setQueueSize(executor.getQueueSize()); + executorStats.setQueueRemainingCapacity(executor.getQueueRemainingCapacity()); + executorStats.setTaskCount(executor.getTaskCount()); + executorStats.setCompletedTaskCount(executor.getCompletedTaskCount()); + executorStats.setWaitTaskCount(executor.getQueueSize()); + executorStats.setRejectHandlerName(executor.getRejectHandlerType()); + executorStats.setKeepAliveTime(executor.getKeepAliveTime(TimeUnit.MILLISECONDS)); + return executorStats; } } diff --git a/core/src/main/java/org/dromara/dynamictp/core/executor/ExecutorType.java b/core/src/main/java/org/dromara/dynamictp/core/executor/ExecutorType.java index 309866bda..9e97dfc77 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/executor/ExecutorType.java +++ b/core/src/main/java/org/dromara/dynamictp/core/executor/ExecutorType.java @@ -21,6 +21,7 @@ import org.dromara.dynamictp.core.executor.eager.EagerDtpExecutor; import lombok.Getter; import org.dromara.dynamictp.core.executor.priority.PriorityDtpExecutor; +import org.dromara.dynamictp.core.support.proxy.VirtualThreadExecutorProxy; /** * ExecutorType related @@ -55,7 +56,12 @@ public enum ExecutorType { /** * Priority executor type. */ - PRIORITY("priority", PriorityDtpExecutor.class); + PRIORITY("priority", PriorityDtpExecutor.class), + + /** + * Virtual thread executor adapter type. + */ + VIRTUAL("virtual", VirtualThreadExecutorProxy.class); private final String name; diff --git a/core/src/main/java/org/dromara/dynamictp/core/handler/CollectorHandler.java b/core/src/main/java/org/dromara/dynamictp/core/handler/CollectorHandler.java index 3add7edc5..6a0313975 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/handler/CollectorHandler.java +++ b/core/src/main/java/org/dromara/dynamictp/core/handler/CollectorHandler.java @@ -19,7 +19,7 @@ import com.google.common.collect.Maps; import lombok.extern.slf4j.Slf4j; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; import org.dromara.dynamictp.common.util.ExtensionServiceLoader; import org.dromara.dynamictp.core.monitor.collector.InternalLogCollector; import org.dromara.dynamictp.core.monitor.collector.LogCollector; @@ -56,14 +56,14 @@ private CollectorHandler() { COLLECTORS.put(jmxCollector.type(), jmxCollector); } - public void collect(ThreadPoolStats poolStats, List types) { - if (poolStats == null || CollectionUtils.isEmpty(types)) { + public void collect(ExecutorStats executorStats, List types) { + if (executorStats == null || CollectionUtils.isEmpty(types)) { return; } for (String collectorType : types) { MetricsCollector collector = COLLECTORS.get(collectorType.toLowerCase()); if (collector != null) { - collector.collect(poolStats); + collector.collect(executorStats); } } } diff --git a/core/src/main/java/org/dromara/dynamictp/core/monitor/DtpMonitor.java b/core/src/main/java/org/dromara/dynamictp/core/monitor/DtpMonitor.java index 6fa267c60..b4ea4f55d 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/monitor/DtpMonitor.java +++ b/core/src/main/java/org/dromara/dynamictp/core/monitor/DtpMonitor.java @@ -19,14 +19,12 @@ import com.google.common.eventbus.Subscribe; import lombok.extern.slf4j.Slf4j; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; import org.dromara.dynamictp.common.event.AlarmCheckEvent; import org.dromara.dynamictp.common.event.CollectEvent; import org.dromara.dynamictp.common.event.CustomContextRefreshedEvent; import org.dromara.dynamictp.common.manager.EventBusManager; - import org.dromara.dynamictp.common.properties.DtpProperties; - import org.dromara.dynamictp.core.DtpRegistry; import org.dromara.dynamictp.core.converter.ExecutorConverter; import org.dromara.dynamictp.core.handler.CollectorHandler; @@ -103,7 +101,8 @@ private void collectMetrics(Set executorNames) { publishCollectEvent(); } - private void doCollect(ThreadPoolStats threadPoolStats) { + + private void doCollect(ExecutorStats threadPoolStats) { try { CollectorHandler.getInstance().collect(threadPoolStats, dtpProperties.getCollectorTypes()); } catch (Exception e) { diff --git a/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/InternalLogCollector.java b/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/InternalLogCollector.java index aa8d8a242..8e9b7877a 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/InternalLogCollector.java +++ b/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/InternalLogCollector.java @@ -17,7 +17,7 @@ package org.dromara.dynamictp.core.monitor.collector; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; import org.dromara.dynamictp.common.em.CollectorTypeEnum; import org.dromara.dynamictp.common.util.JsonUtil; import lombok.extern.slf4j.Slf4j; @@ -29,10 +29,11 @@ public class InternalLogCollector extends AbstractCollector { @Override - public void collect(ThreadPoolStats poolStats) { + public void collect(ExecutorStats poolStats) { log.info("dynamic.tp metrics: {}", JsonUtil.toJson(poolStats)); } + @Override public String type() { return CollectorTypeEnum.INTERNAL_LOGGING.name().toLowerCase(); diff --git a/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/LogCollector.java b/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/LogCollector.java index d5c212f34..c9524f1e7 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/LogCollector.java +++ b/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/LogCollector.java @@ -18,7 +18,7 @@ package org.dromara.dynamictp.core.monitor.collector; import org.dromara.dynamictp.common.em.CollectorTypeEnum; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; import org.dromara.dynamictp.common.util.JsonUtil; import org.dromara.dynamictp.logging.LogHelper; import lombok.extern.slf4j.Slf4j; @@ -33,8 +33,8 @@ public class LogCollector extends AbstractCollector { @Override - public void collect(ThreadPoolStats threadPoolStats) { - String metrics = JsonUtil.toJson(threadPoolStats); + public void collect(ExecutorStats executorStats) { + String metrics = JsonUtil.toJson(executorStats); if (LogHelper.getMonitorLogger() == null) { log.error("Cannot find monitor logger..."); return; diff --git a/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/MetricsCollector.java b/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/MetricsCollector.java index b4728db4f..c06e1540a 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/MetricsCollector.java +++ b/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/MetricsCollector.java @@ -17,7 +17,7 @@ package org.dromara.dynamictp.core.monitor.collector; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; /** * MetricsCollector related @@ -31,7 +31,7 @@ public interface MetricsCollector { * Collect key metrics. * @param poolStats ThreadPoolStats instance */ - void collect(ThreadPoolStats poolStats); + void collect(ExecutorStats poolStats); /** * Collector type. diff --git a/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/MicroMeterCollector.java b/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/MicroMeterCollector.java index 071faf7a7..bd40efe99 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/MicroMeterCollector.java +++ b/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/MicroMeterCollector.java @@ -21,7 +21,7 @@ import io.micrometer.core.instrument.Tag; import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.common.em.CollectorTypeEnum; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; import org.dromara.dynamictp.common.util.BeanCopierUtil; import org.dromara.dynamictp.common.util.CommonUtil; @@ -52,18 +52,18 @@ public class MicroMeterCollector extends AbstractCollector { public static final String APP_NAME_TAG = "app.name"; - private static final Map GAUGE_CACHE = new ConcurrentHashMap<>(); + private static final Map GAUGE_CACHE = new ConcurrentHashMap<>(); @Override - public void collect(ThreadPoolStats threadPoolStats) { + public void collect(ExecutorStats executorStats) { // metrics must be held with a strong reference, even though it is never referenced within this class - ThreadPoolStats oldStats = GAUGE_CACHE.get(threadPoolStats.getPoolName()); + ExecutorStats oldStats = GAUGE_CACHE.get(executorStats.getExecutorName()); if (Objects.isNull(oldStats)) { - GAUGE_CACHE.put(threadPoolStats.getPoolName(), threadPoolStats); + GAUGE_CACHE.put(executorStats.getExecutorName(), executorStats); } else { - BeanCopierUtil.copyProperties(threadPoolStats, oldStats); + BeanCopierUtil.copyProperties(executorStats, oldStats); } - gauge(GAUGE_CACHE.get(threadPoolStats.getPoolName())); + gauge(GAUGE_CACHE.get(executorStats.getExecutorName())); } @Override @@ -71,50 +71,50 @@ public String type() { return CollectorTypeEnum.MICROMETER.name().toLowerCase(); } - public void gauge(ThreadPoolStats poolStats) { - - Iterable tags = getTags(poolStats); - - Metrics.gauge(metricName("core.size"), tags, poolStats, ThreadPoolStats::getCorePoolSize); - Metrics.gauge(metricName("maximum.size"), tags, poolStats, ThreadPoolStats::getMaximumPoolSize); - Metrics.gauge(metricName("current.size"), tags, poolStats, ThreadPoolStats::getPoolSize); - Metrics.gauge(metricName("largest.size"), tags, poolStats, ThreadPoolStats::getLargestPoolSize); - Metrics.gauge(metricName("active.count"), tags, poolStats, ThreadPoolStats::getActiveCount); - - Metrics.gauge(metricName("task.count"), tags, poolStats, ThreadPoolStats::getTaskCount); - Metrics.gauge(metricName("completed.task.count"), tags, poolStats, ThreadPoolStats::getCompletedTaskCount); - Metrics.gauge(metricName("wait.task.count"), tags, poolStats, ThreadPoolStats::getWaitTaskCount); - - Metrics.gauge(metricName("queue.size"), tags, poolStats, ThreadPoolStats::getQueueSize); - Metrics.gauge(metricName("queue.capacity"), tags, poolStats, ThreadPoolStats::getQueueCapacity); - Metrics.gauge(metricName("queue.remaining.capacity"), tags, poolStats, ThreadPoolStats::getQueueRemainingCapacity); - - Metrics.gauge(metricName("reject.count"), tags, poolStats, ThreadPoolStats::getRejectCount); - Metrics.gauge(metricName("run.timeout.count"), tags, poolStats, ThreadPoolStats::getRunTimeoutCount); - Metrics.gauge(metricName("queue.timeout.count"), tags, poolStats, ThreadPoolStats::getQueueTimeoutCount); - - Metrics.gauge(metricName("tps"), tags, poolStats, ThreadPoolStats::getTps); - Metrics.gauge(metricName("completed.task.time.avg"), tags, poolStats, ThreadPoolStats::getAvg); - Metrics.gauge(metricName("completed.task.time.max"), tags, poolStats, ThreadPoolStats::getMaxRt); - Metrics.gauge(metricName("completed.task.time.min"), tags, poolStats, ThreadPoolStats::getMinRt); - Metrics.gauge(metricName("completed.task.time.tp50"), tags, poolStats, ThreadPoolStats::getTp50); - Metrics.gauge(metricName("completed.task.time.tp75"), tags, poolStats, ThreadPoolStats::getTp75); - Metrics.gauge(metricName("completed.task.time.tp90"), tags, poolStats, ThreadPoolStats::getTp90); - Metrics.gauge(metricName("completed.task.time.tp95"), tags, poolStats, ThreadPoolStats::getTp95); - Metrics.gauge(metricName("completed.task.time.tp99"), tags, poolStats, ThreadPoolStats::getTp99); - Metrics.gauge(metricName("completed.task.time.tp999"), tags, poolStats, ThreadPoolStats::getTp999); + public void gauge(ExecutorStats executorStats) { + + Iterable tags = getTags(executorStats); + + Metrics.gauge(metricName("core.size"), tags, executorStats, ExecutorStats::getCorePoolSize); + Metrics.gauge(metricName("maximum.size"), tags, executorStats, ExecutorStats::getMaximumPoolSize); + Metrics.gauge(metricName("current.size"), tags, executorStats, ExecutorStats::getPoolSize); + Metrics.gauge(metricName("largest.size"), tags, executorStats, ExecutorStats::getLargestPoolSize); + + Metrics.gauge(metricName("completed.task.count"), tags, executorStats, ExecutorStats::getCompletedTaskCount); + Metrics.gauge(metricName("wait.task.count"), tags, executorStats, ExecutorStats::getWaitTaskCount); + + Metrics.gauge(metricName("queue.size"), tags, executorStats, ExecutorStats::getQueueSize); + Metrics.gauge(metricName("queue.capacity"), tags, executorStats, ExecutorStats::getQueueCapacity); + Metrics.gauge(metricName("queue.remaining.capacity"), tags, executorStats, ExecutorStats::getQueueRemainingCapacity); + + Metrics.gauge(metricName("reject.count"), tags, executorStats, ExecutorStats::getRejectCount); + Metrics.gauge(metricName("queue.timeout.count"), tags, executorStats, ExecutorStats::getQueueTimeoutCount); + + Metrics.gauge(metricName("active.count"), tags, executorStats, ExecutorStats::getActiveCount); + Metrics.gauge(metricName("task.count"), tags, executorStats, ExecutorStats::getTaskCount); + Metrics.gauge(metricName("run.timeout.count"), tags, executorStats, ExecutorStats::getRunTimeoutCount); + + Metrics.gauge(metricName("tps"), tags, executorStats, ExecutorStats::getTps); + Metrics.gauge(metricName("completed.task.time.avg"), tags, executorStats, ExecutorStats::getAvg); + Metrics.gauge(metricName("completed.task.time.max"), tags, executorStats, ExecutorStats::getMaxRt); + Metrics.gauge(metricName("completed.task.time.min"), tags, executorStats, ExecutorStats::getMinRt); + Metrics.gauge(metricName("completed.task.time.tp50"), tags, executorStats, ExecutorStats::getTp50); + Metrics.gauge(metricName("completed.task.time.tp75"), tags, executorStats, ExecutorStats::getTp75); + Metrics.gauge(metricName("completed.task.time.tp90"), tags, executorStats, ExecutorStats::getTp90); + Metrics.gauge(metricName("completed.task.time.tp95"), tags, executorStats, ExecutorStats::getTp95); + Metrics.gauge(metricName("completed.task.time.tp99"), tags, executorStats, ExecutorStats::getTp99); + Metrics.gauge(metricName("completed.task.time.tp999"), tags, executorStats, ExecutorStats::getTp999); } private static String metricName(String name) { return String.join(".", DTP_METRIC_NAME_PREFIX, name); } - private Iterable getTags(ThreadPoolStats poolStats) { + private Iterable getTags(ExecutorStats executorStats) { List tags = new ArrayList<>(3); - tags.add(Tag.of(POOL_NAME_TAG, poolStats.getPoolName())); + tags.add(Tag.of(POOL_NAME_TAG, executorStats.getExecutorName())); tags.add(Tag.of(APP_NAME_TAG, CommonUtil.getInstance().getServiceName())); - // https://github.com/dromara/dynamic-tp/issues/359 - tags.add(Tag.of(POOL_ALIAS_TAG, Optional.ofNullable(poolStats.getPoolAliasName()).orElse(poolStats.getPoolName()))); + tags.add(Tag.of(POOL_ALIAS_TAG, Optional.ofNullable(executorStats.getExecutorAliasName()).orElse(executorStats.getExecutorName()))); return tags; } } diff --git a/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/jmx/ThreadPoolStatsJMX.java b/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/jmx/ExecutorStatsJMX.java similarity index 66% rename from core/src/main/java/org/dromara/dynamictp/core/monitor/collector/jmx/ThreadPoolStatsJMX.java rename to core/src/main/java/org/dromara/dynamictp/core/monitor/collector/jmx/ExecutorStatsJMX.java index 1f43c312f..aae7df866 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/jmx/ThreadPoolStatsJMX.java +++ b/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/jmx/ExecutorStatsJMX.java @@ -17,26 +17,26 @@ package org.dromara.dynamictp.core.monitor.collector.jmx; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; /** * @author KamTo Hung */ -public class ThreadPoolStatsJMX implements ThreadPoolStatsMXBean { +public class ExecutorStatsJMX implements ExecutorStatsMXBean { - private ThreadPoolStats threadPoolStats; + private ExecutorStats executorStats; - public ThreadPoolStatsJMX(ThreadPoolStats threadPoolStats) { - this.threadPoolStats = threadPoolStats; + public ExecutorStatsJMX(ExecutorStats executorStats) { + this.executorStats = executorStats; } @Override - public ThreadPoolStats getThreadPoolStats() { - return this.threadPoolStats; + public ExecutorStats getExecutorStats() { + return this.executorStats; } @Override - public void setThreadPoolStats(ThreadPoolStats threadPoolStats) { - this.threadPoolStats = threadPoolStats; + public void setExecutorStats(ExecutorStats executorStats) { + this.executorStats = executorStats; } } diff --git a/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/jmx/ThreadPoolStatsMXBean.java b/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/jmx/ExecutorStatsMXBean.java similarity index 75% rename from core/src/main/java/org/dromara/dynamictp/core/monitor/collector/jmx/ThreadPoolStatsMXBean.java rename to core/src/main/java/org/dromara/dynamictp/core/monitor/collector/jmx/ExecutorStatsMXBean.java index 3959cca36..a28d150f4 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/jmx/ThreadPoolStatsMXBean.java +++ b/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/jmx/ExecutorStatsMXBean.java @@ -17,30 +17,30 @@ package org.dromara.dynamictp.core.monitor.collector.jmx; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; import javax.management.MXBean; /** - * ThreadPoolStatsMXBean related + * ExecutorStatsMXBean related * * @author KamTo Hung */ @MXBean -public interface ThreadPoolStatsMXBean { +public interface ExecutorStatsMXBean { /** - * get thread pool stats + * get executor stats * * @return thread pool stats */ - ThreadPoolStats getThreadPoolStats(); + ExecutorStats getExecutorStats(); /** - * set thread pool stats + * set executor stats * - * @param threadPoolStats thread pool stats + * @param executorStats thread pool stats */ - void setThreadPoolStats(ThreadPoolStats threadPoolStats); + void setExecutorStats(ExecutorStats executorStats); } diff --git a/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/jmx/JMXCollector.java b/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/jmx/JMXCollector.java index a288bb928..79d03b6b5 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/jmx/JMXCollector.java +++ b/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/jmx/JMXCollector.java @@ -19,7 +19,8 @@ import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.common.em.CollectorTypeEnum; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.Metrics; +import org.dromara.dynamictp.common.entity.ExecutorStats; import org.dromara.dynamictp.common.util.BeanCopierUtil; import org.dromara.dynamictp.core.monitor.collector.AbstractCollector; @@ -43,23 +44,23 @@ public class JMXCollector extends AbstractCollector { /** * 缓存的作用是将注册到JMX的数据,每次都是同一个对象 */ - private static final Map GAUGE_CACHE = new ConcurrentHashMap<>(); + private static final Map GAUGE_CACHE = new ConcurrentHashMap<>(); @Override - public void collect(ThreadPoolStats threadPoolStats) { - if (GAUGE_CACHE.containsKey(threadPoolStats.getPoolName())) { - ThreadPoolStats poolStats = GAUGE_CACHE.get(threadPoolStats.getPoolName()); - BeanCopierUtil.copyProperties(threadPoolStats, poolStats); + public void collect(ExecutorStats executorStats) { + if (GAUGE_CACHE.containsKey(executorStats.getExecutorName())) { + ExecutorStats poolStats = (ExecutorStats) GAUGE_CACHE.get(executorStats.getExecutorName()); + BeanCopierUtil.copyProperties(executorStats, poolStats); } else { try { MBeanServer server = ManagementFactory.getPlatformMBeanServer(); - ObjectName name = new ObjectName(DTP_METRIC_NAME_PREFIX + ":name=" + threadPoolStats.getPoolName()); - ThreadPoolStatsJMX stats = new ThreadPoolStatsJMX(threadPoolStats); + ObjectName name = new ObjectName(DTP_METRIC_NAME_PREFIX + ":name=" + executorStats.getExecutorName()); + ExecutorStatsJMX stats = new ExecutorStatsJMX(executorStats); server.registerMBean(stats, name); } catch (JMException e) { log.error("collect thread pool stats error", e); } - GAUGE_CACHE.put(threadPoolStats.getPoolName(), threadPoolStats); + GAUGE_CACHE.put(executorStats.getExecutorName(), executorStats); } } diff --git a/core/src/main/java/org/dromara/dynamictp/core/notifier/alarm/AlarmCounter.java b/core/src/main/java/org/dromara/dynamictp/core/notifier/alarm/AlarmCounter.java index 5e1271d2b..b236431f2 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/notifier/alarm/AlarmCounter.java +++ b/core/src/main/java/org/dromara/dynamictp/core/notifier/alarm/AlarmCounter.java @@ -19,7 +19,6 @@ import cn.hutool.core.util.NumberUtil; import lombok.val; -import lombok.var; import org.dromara.dynamictp.common.em.NotifyItemEnum; import org.dromara.dynamictp.common.entity.AlarmInfo; import org.dromara.dynamictp.core.support.ExecutorWrapper; @@ -64,13 +63,13 @@ public static String getCount(String threadPoolName, String notifyItemType) { public static void reset(String threadPoolName, String notifyItemType) { String key = buildKey(threadPoolName, notifyItemType); - var alarmInfo = ALARM_INFO_CACHE.get(key); + val alarmInfo = ALARM_INFO_CACHE.get(key); alarmInfo.reset(); } public static void incAlarmCounter(String threadPoolName, String notifyItemType) { String key = buildKey(threadPoolName, notifyItemType); - var alarmInfo = ALARM_INFO_CACHE.get(key); + val alarmInfo = ALARM_INFO_CACHE.get(key); if (Objects.nonNull(alarmInfo)) { alarmInfo.incCounter(); } diff --git a/core/src/main/java/org/dromara/dynamictp/core/support/ExecutorWrapper.java b/core/src/main/java/org/dromara/dynamictp/core/support/ExecutorWrapper.java index 7101a44ed..8e6cc5fc0 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/support/ExecutorWrapper.java +++ b/core/src/main/java/org/dromara/dynamictp/core/support/ExecutorWrapper.java @@ -28,6 +28,7 @@ import org.dromara.dynamictp.core.notifier.capture.CapturedExecutor; import org.dromara.dynamictp.core.notifier.manager.AlarmManager; import org.dromara.dynamictp.core.reject.RejectHandlerGetter; +import org.dromara.dynamictp.core.support.proxy.VirtualThreadExecutorProxy; import org.dromara.dynamictp.core.support.adapter.ExecutorAdapter; import org.dromara.dynamictp.core.support.adapter.ThreadPoolExecutorAdapter; import org.dromara.dynamictp.core.support.task.wrapper.TaskWrapper; @@ -141,6 +142,8 @@ public ExecutorWrapper(String threadPoolName, Executor executor) { this.executor = new ThreadPoolExecutorAdapter((ThreadPoolExecutor) executor); } else if (executor instanceof ExecutorAdapter) { this.executor = (ExecutorAdapter) executor; + } else if (executor instanceof VirtualThreadExecutorProxy) { + this.executor = new VirtualThreadExecutorAdapter(((VirtualThreadExecutorProxy) executor).getThreadPerTaskExecutor()); } else { throw new IllegalArgumentException("unsupported Executor type !"); } @@ -177,7 +180,7 @@ public void initialize() { if (isDtpExecutor()) { ((DtpExecutor) getExecutor()).initialize(); AwareManager.register(this); - } else if (isThreadPoolExecutor()) { + } else if (isThreadPoolExecutor() || isVirtualThreadExecutor()) { AwareManager.register(this); } } @@ -204,6 +207,15 @@ public boolean isThreadPoolExecutor() { return this.executor instanceof ThreadPoolExecutorAdapter; } + /** + * whether is VirtualThreadExecutor + * + * @return boolean + */ + public boolean isVirtualThreadExecutor() { + return this.executor instanceof VirtualThreadExecutorAdapter; + } + /** * set taskWrappers * diff --git a/core/src/main/java/org/dromara/dynamictp/core/support/VirtualThreadExecutorAdapter.java b/core/src/main/java/org/dromara/dynamictp/core/support/VirtualThreadExecutorAdapter.java new file mode 100644 index 000000000..6d3a2dff6 --- /dev/null +++ b/core/src/main/java/org/dromara/dynamictp/core/support/VirtualThreadExecutorAdapter.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.dromara.dynamictp.core.support; + +import org.dromara.dynamictp.core.support.adapter.ExecutorAdapter; + +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; + +/** + * ClassName: VirtualThreadExecutorAdapter + * Package: org.dromara.dynamictp.core.support + * Description: + * Adapter for virtual thread executor + * + * @author CYC + */ +public class VirtualThreadExecutorAdapter implements ExecutorAdapter { + + private final ExecutorService executor; + + public VirtualThreadExecutorAdapter(Executor executor) { + this.executor = (ExecutorService) executor; + } + + @Override + public ExecutorService getOriginal() { + return this.executor; + } + + @Override + public void execute(Runnable command) { + this.executor.execute(command); + } + + @Override + public int getCorePoolSize() { + return 0; + } + + @Override + public void setCorePoolSize(int corePoolSize) { + + } + + @Override + public int getMaximumPoolSize() { + return 0; + } + + @Override + public void setMaximumPoolSize(int maximumPoolSize) { + + } + + @Override + public int getPoolSize() { + return 0; + } + + @Override + public int getActiveCount() { + return 0; + } + + @Override + public boolean isShutdown() { + return this.executor.isShutdown(); + } + + @Override + public boolean isTerminated() { + return this.executor.isTerminated(); + } + + +} diff --git a/core/src/main/java/org/dromara/dynamictp/core/support/proxy/VirtualThreadExecutorProxy.java b/core/src/main/java/org/dromara/dynamictp/core/support/proxy/VirtualThreadExecutorProxy.java new file mode 100644 index 000000000..906d3b4c0 --- /dev/null +++ b/core/src/main/java/org/dromara/dynamictp/core/support/proxy/VirtualThreadExecutorProxy.java @@ -0,0 +1,248 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dromara.dynamictp.core.support.proxy; + +import com.google.common.collect.Sets; +import org.dromara.dynamictp.common.em.NotifyItemEnum; +import org.dromara.dynamictp.common.entity.NotifyItem; +import org.dromara.dynamictp.core.aware.AwareManager; +import org.dromara.dynamictp.core.aware.TaskEnhanceAware; +import org.dromara.dynamictp.core.support.task.runnable.EnhancedRunnable; +import org.dromara.dynamictp.core.support.task.wrapper.TaskWrapper; + +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * ClassName: VirtualThreadExecutorProxy + * Package: org.dromara.dynamictp.core.support + * Description: + * VirtualThreadExecutor Proxy + * + * @Author CYC + * @Create 2024/10/14 15:59 + * @Version 1.0 + */ +public class VirtualThreadExecutorProxy implements TaskEnhanceAware, ExecutorService { + + private final ExecutorService threadPerTaskExecutor; + + /** + * Notify platform ids. + */ + private List platformIds; + + /** + * Task wrappers, do sth enhanced. + */ + private List taskWrappers; + + /** + * The name of the thread pool. + */ + protected String threadPoolName; + + /** + * Simple Business alias Name of Dynamic ThreadPool. Use for notify. + */ + private String threadPoolAliasName; + + /** + * If enable notify. + */ + private boolean notifyEnabled = true; + + /** + * Notify items, see {@link NotifyItemEnum}. + */ + private List notifyItems; + + /** + * Plugin names. + */ + private Set pluginNames = Sets.newHashSet(); + + /** + * Aware names. + */ + private Set awareNames = Sets.newHashSet(); + + + public VirtualThreadExecutorProxy(ExecutorService executor) { + super(); + threadPerTaskExecutor = executor; + } + + @Override + public void execute(Runnable command) { + command = getEnhancedTask(command); + EnhancedRunnable enhanceTask = EnhancedRunnable.of(command, this); + AwareManager.execute(this, enhanceTask); + threadPerTaskExecutor.execute(enhanceTask); + } + + public ExecutorService getThreadPerTaskExecutor() { + return threadPerTaskExecutor; + } + + @Override + public List getTaskWrappers() { + return taskWrappers; + } + + @Override + public void setTaskWrappers(List taskWrappers) { + this.taskWrappers = taskWrappers; + } + + + @Override + public void shutdown() { + threadPerTaskExecutor.shutdown(); + } + + @Override + public List shutdownNow() { + return threadPerTaskExecutor.shutdownNow(); + } + + @Override + public boolean isShutdown() { + return threadPerTaskExecutor.isShutdown(); + } + + @Override + public boolean isTerminated() { + return threadPerTaskExecutor.isTerminated(); + } + + @Override + public boolean awaitTermination(long l, TimeUnit timeUnit) throws InterruptedException { + return threadPerTaskExecutor.awaitTermination(l, timeUnit); + } + + @Override + public Future submit(Callable callable) { + FutureTask futureTask = new FutureTask(callable); + futureTask = (FutureTask) getEnhancedTask(futureTask); + EnhancedRunnable enhancedRunnable = EnhancedRunnable.of(futureTask, this); + AwareManager.execute(this, enhancedRunnable); + return threadPerTaskExecutor.submit(callable); + } + + + @Override + public Future submit(Runnable runnable, T t) { + runnable = getEnhancedTask(runnable); + EnhancedRunnable enhancedRunnable = EnhancedRunnable.of(runnable, this); + AwareManager.execute(this, enhancedRunnable); + return threadPerTaskExecutor.submit(runnable, t); + } + + @Override + public Future submit(Runnable runnable) { + runnable = getEnhancedTask(runnable); + EnhancedRunnable enhancedRunnable = EnhancedRunnable.of(runnable, this); + AwareManager.execute(this, enhancedRunnable); + return threadPerTaskExecutor.submit(enhancedRunnable); + } + + @Override + public List> invokeAll(Collection> collection) throws InterruptedException { + return threadPerTaskExecutor.invokeAll(collection); + } + + @Override + public List> invokeAll(Collection> collection, long l, TimeUnit timeUnit) throws InterruptedException { + return threadPerTaskExecutor.invokeAll(collection, l, timeUnit); + } + + @Override + public T invokeAny(Collection> collection) throws InterruptedException, ExecutionException { + return threadPerTaskExecutor.invokeAny(collection); + } + + @Override + public T invokeAny(Collection> collection, long l, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException { + return threadPerTaskExecutor.invokeAny(collection, l, timeUnit); + } + + public String getThreadPoolName() { + return threadPoolName; + } + + public void setThreadPoolName(String threadPoolName) { + this.threadPoolName = threadPoolName; + } + + public String getThreadPoolAliasName() { + return threadPoolAliasName; + } + + public void setThreadPoolAliasName(String threadPoolAliasName) { + this.threadPoolAliasName = threadPoolAliasName; + } + + public boolean isNotifyEnabled() { + return notifyEnabled; + } + + public void setNotifyEnabled(boolean notifyEnabled) { + this.notifyEnabled = notifyEnabled; + } + + public Set getPluginNames() { + return pluginNames; + } + + public void setPluginNames(Set pluginNames) { + this.pluginNames = pluginNames; + } + + public Set getAwareNames() { + return awareNames; + } + + public void setAwareNames(Set awareNames) { + this.awareNames = awareNames; + } + + public List getPlatformIds() { + return platformIds; + } + + public void setPlatformIds(List platformIds) { + this.platformIds = platformIds; + } + + public List getNotifyItems() { + return notifyItems; + } + + public void setNotifyItems(List notifyItems) { + this.notifyItems = notifyItems; + } +} diff --git a/dependencies/pom.xml b/dependencies/pom.xml index 16293b527..af9e426e4 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -12,9 +12,12 @@ https://github.com/yanhom1314/dynamic-tp - 1.1.9.1 + 1.1.9.1-3.x UTF-8 + 17 + 17 + 1.18.24 1.7.36 1.2.10 @@ -22,8 +25,7 @@ 5.8.25 31.1-jre - 2.13.4 - 2.13.4 + 2.13.4 2.8.9 1.2.83 2.14.3 @@ -49,18 +51,23 @@ 1.5.0 2.0.4 + + 2022.0.0.0 + 1.12.4-2022.0.4 0.2.12 - 2021.0.5.0 - 1.12.4-2021.0.8 + 1.10.11-2021.0.x 5.2.1 1.3.0 - 2.4 - 3.2.0 + 3.8.1 + 3.2.0 + 3.6.2 1.6 + 1.6.13 4.2.20 + 2.1.0 1.35 2.0.2 @@ -160,13 +167,13 @@ com.fasterxml.jackson.core jackson-core - ${jackson-core.version} + ${jackson.version} com.fasterxml.jackson.core jackson-databind - ${jackson-databind.version} + ${jackson.version} @@ -652,9 +659,6 @@ org.apache.maven.plugins maven-source-plugin ${maven-source-plugin.version} - - true - package @@ -664,26 +668,27 @@ - org.apache.maven.plugins maven-javadoc-plugin ${maven-javadoc-plugin.version} - package + package jar + + false + - org.apache.maven.plugins maven-gpg-plugin - 1.6 + ${maven-gpg-plugin.version} verify @@ -697,7 +702,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.7 + ${nexus-staging-maven-plugin.version} true ossrh @@ -706,7 +711,6 @@ - org.codehaus.mojo flatten-maven-plugin diff --git a/example/example-adapter/example-adapter-brpc/src/main/java/org/dromara/dynamictp/example/controller/TestController.java b/example/example-adapter/example-adapter-brpc/src/main/java/org/dromara/dynamictp/example/controller/TestController.java index 5d15abc2b..b0b21205a 100644 --- a/example/example-adapter/example-adapter-brpc/src/main/java/org/dromara/dynamictp/example/controller/TestController.java +++ b/example/example-adapter/example-adapter-brpc/src/main/java/org/dromara/dynamictp/example/controller/TestController.java @@ -22,7 +22,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; +import org.springframework.beans.factory.annotation.Autowired; /** * @author fabian4 @@ -32,7 +32,7 @@ @SuppressWarnings("all") public class TestController { - @Resource + @Autowired private BrpcClientService brpcClientService; @GetMapping("/dtp-example-adapter/testBrpc") diff --git a/example/example-adapter/example-adapter-brpc/src/main/resources/application.yml b/example/example-adapter/example-adapter-brpc/src/main/resources/application.yml index b5137e7cf..3d6386387 100644 --- a/example/example-adapter/example-adapter-brpc/src/main/resources/application.yml +++ b/example/example-adapter/example-adapter-brpc/src/main/resources/application.yml @@ -37,11 +37,11 @@ starlight: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true diff --git a/example/example-adapter/example-adapter-dubbo/example-adapter-alibaba-dubbo/src/main/java/org/dromara/dynamictp/example/controller/TestController.java b/example/example-adapter/example-adapter-dubbo/example-adapter-alibaba-dubbo/src/main/java/org/dromara/dynamictp/example/controller/TestController.java index e121bff97..72acdb6c8 100644 --- a/example/example-adapter/example-adapter-dubbo/example-adapter-alibaba-dubbo/src/main/java/org/dromara/dynamictp/example/controller/TestController.java +++ b/example/example-adapter/example-adapter-dubbo/example-adapter-alibaba-dubbo/src/main/java/org/dromara/dynamictp/example/controller/TestController.java @@ -17,13 +17,11 @@ package org.dromara.dynamictp.example.controller; -import org.dromara.dynamictp.example.dubbo.DubboUserService; import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.example.dubbo.DubboUserService; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; - /** * @author dragon-zhang */ @@ -32,8 +30,11 @@ @SuppressWarnings("all") public class TestController { - @Resource - private DubboUserService dubboUserService; + private final DubboUserService dubboUserService; + + public TestController(DubboUserService dubboUserService) { + this.dubboUserService = dubboUserService; + } @GetMapping("/dtp-example-adapter/testDubbo") public String testDubbo() throws InterruptedException { diff --git a/example/example-adapter/example-adapter-dubbo/example-adapter-alibaba-dubbo/src/main/resources/application.yml b/example/example-adapter/example-adapter-dubbo/example-adapter-alibaba-dubbo/src/main/resources/application.yml index 60070116a..6295a31a8 100644 --- a/example/example-adapter/example-adapter-dubbo/example-adapter-alibaba-dubbo/src/main/resources/application.yml +++ b/example/example-adapter/example-adapter-dubbo/example-adapter-alibaba-dubbo/src/main/resources/application.yml @@ -44,11 +44,11 @@ dubbo: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 \ No newline at end of file + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true \ No newline at end of file diff --git a/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-2.7.3/src/main/java/org/dromara/dynamictp/example/controller/TestController.java b/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-2.7.3/src/main/java/org/dromara/dynamictp/example/controller/TestController.java index e121bff97..745e1f16d 100644 --- a/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-2.7.3/src/main/java/org/dromara/dynamictp/example/controller/TestController.java +++ b/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-2.7.3/src/main/java/org/dromara/dynamictp/example/controller/TestController.java @@ -17,23 +17,22 @@ package org.dromara.dynamictp.example.controller; -import org.dromara.dynamictp.example.dubbo.DubboUserService; +import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.example.dubbo.DubboUserService; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; - /** * @author dragon-zhang */ @Slf4j @RestController +@AllArgsConstructor @SuppressWarnings("all") public class TestController { - @Resource - private DubboUserService dubboUserService; + private final DubboUserService dubboUserService; @GetMapping("/dtp-example-adapter/testDubbo") public String testDubbo() throws InterruptedException { diff --git a/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-2.7.3/src/main/resources/application.yml b/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-2.7.3/src/main/resources/application.yml index ad48d6b2f..9ce598d3f 100644 --- a/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-2.7.3/src/main/resources/application.yml +++ b/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-2.7.3/src/main/resources/application.yml @@ -50,11 +50,11 @@ dubbo: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 \ No newline at end of file + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true \ No newline at end of file diff --git a/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-2.7.9/src/main/java/org/dromara/dynamictp/example/controller/TestController.java b/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-2.7.9/src/main/java/org/dromara/dynamictp/example/controller/TestController.java index e121bff97..745e1f16d 100644 --- a/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-2.7.9/src/main/java/org/dromara/dynamictp/example/controller/TestController.java +++ b/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-2.7.9/src/main/java/org/dromara/dynamictp/example/controller/TestController.java @@ -17,23 +17,22 @@ package org.dromara.dynamictp.example.controller; -import org.dromara.dynamictp.example.dubbo.DubboUserService; +import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.example.dubbo.DubboUserService; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; - /** * @author dragon-zhang */ @Slf4j @RestController +@AllArgsConstructor @SuppressWarnings("all") public class TestController { - @Resource - private DubboUserService dubboUserService; + private final DubboUserService dubboUserService; @GetMapping("/dtp-example-adapter/testDubbo") public String testDubbo() throws InterruptedException { diff --git a/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-2.7.9/src/main/resources/application.yml b/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-2.7.9/src/main/resources/application.yml index ad48d6b2f..9ce598d3f 100644 --- a/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-2.7.9/src/main/resources/application.yml +++ b/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-2.7.9/src/main/resources/application.yml @@ -50,11 +50,11 @@ dubbo: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 \ No newline at end of file + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true \ No newline at end of file diff --git a/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-3.0.7/src/main/java/org/dromara/dynamictp/example/controller/TestController.java b/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-3.0.7/src/main/java/org/dromara/dynamictp/example/controller/TestController.java index 806bb7481..b2d6a79a2 100644 --- a/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-3.0.7/src/main/java/org/dromara/dynamictp/example/controller/TestController.java +++ b/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-3.0.7/src/main/java/org/dromara/dynamictp/example/controller/TestController.java @@ -17,23 +17,22 @@ package org.dromara.dynamictp.example.controller; -import org.dromara.dynamictp.example.dubbo.DubboUserService; +import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.example.dubbo.DubboUserService; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; - /** * @author fabian4 */ @Slf4j @RestController +@AllArgsConstructor @SuppressWarnings("all") public class TestController { - @Resource - private DubboUserService dubboUserService; + private final DubboUserService dubboUserService; @GetMapping("/dtp-example-adapter/testDubbo") public String testDubbo() throws InterruptedException { diff --git a/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-3.0.7/src/main/resources/application.yml b/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-3.0.7/src/main/resources/application.yml index ad48d6b2f..9ce598d3f 100644 --- a/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-3.0.7/src/main/resources/application.yml +++ b/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-3.0.7/src/main/resources/application.yml @@ -50,11 +50,11 @@ dubbo: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 \ No newline at end of file + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true \ No newline at end of file diff --git a/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-3.2.10/src/main/java/org/dromara/dynamictp/example/controller/TestController.java b/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-3.2.10/src/main/java/org/dromara/dynamictp/example/controller/TestController.java index 806bb7481..b2d6a79a2 100644 --- a/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-3.2.10/src/main/java/org/dromara/dynamictp/example/controller/TestController.java +++ b/example/example-adapter/example-adapter-dubbo/example-adapter-apache-dubbo/example-adapter-apache-dubbo-3.2.10/src/main/java/org/dromara/dynamictp/example/controller/TestController.java @@ -17,23 +17,22 @@ package org.dromara.dynamictp.example.controller; -import org.dromara.dynamictp.example.dubbo.DubboUserService; +import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.dromara.dynamictp.example.dubbo.DubboUserService; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; - /** * @author fabian4 */ @Slf4j @RestController +@AllArgsConstructor @SuppressWarnings("all") public class TestController { - @Resource - private DubboUserService dubboUserService; + private final DubboUserService dubboUserService; @GetMapping("/dtp-example-adapter/testDubbo") public String testDubbo() throws InterruptedException { diff --git a/example/example-adapter/example-adapter-grpc/pom.xml b/example/example-adapter/example-adapter-grpc/pom.xml index f89c97335..1224c3b23 100644 --- a/example/example-adapter/example-adapter-grpc/pom.xml +++ b/example/example-adapter/example-adapter-grpc/pom.xml @@ -46,7 +46,7 @@ net.devh grpc-spring-boot-starter - 2.13.1.RELEASE + 2.14.0.RELEASE diff --git a/example/example-adapter/example-adapter-grpc/src/main/java/org/dromara/dynamictp/example/controller/TestController.java b/example/example-adapter/example-adapter-grpc/src/main/java/org/dromara/dynamictp/example/controller/TestController.java index 64949e523..3d25bf990 100644 --- a/example/example-adapter/example-adapter-grpc/src/main/java/org/dromara/dynamictp/example/controller/TestController.java +++ b/example/example-adapter/example-adapter-grpc/src/main/java/org/dromara/dynamictp/example/controller/TestController.java @@ -22,7 +22,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; +import org.springframework.beans.factory.annotation.Autowired; /** * @author fabian4 @@ -32,7 +32,7 @@ @SuppressWarnings("all") public class TestController { - @Resource + @Autowired private GrpcClientService grpcClientService; @GetMapping("/dtp-example-adapter/testGrpc") diff --git a/example/example-adapter/example-adapter-grpc/src/main/resources/application.yml b/example/example-adapter/example-adapter-grpc/src/main/resources/application.yml index 109216733..534437fcd 100644 --- a/example/example-adapter/example-adapter-grpc/src/main/resources/application.yml +++ b/example/example-adapter/example-adapter-grpc/src/main/resources/application.yml @@ -56,11 +56,11 @@ grpc: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 \ No newline at end of file + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true diff --git a/example/example-adapter/example-adapter-hystrix/src/main/java/org/dromara/dynamictp/example/controller/TestController.java b/example/example-adapter/example-adapter-hystrix/src/main/java/org/dromara/dynamictp/example/controller/TestController.java index 0c4a663d6..8a84d85fc 100644 --- a/example/example-adapter/example-adapter-hystrix/src/main/java/org/dromara/dynamictp/example/controller/TestController.java +++ b/example/example-adapter/example-adapter-hystrix/src/main/java/org/dromara/dynamictp/example/controller/TestController.java @@ -22,7 +22,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; +import org.springframework.beans.factory.annotation.Autowired; /** * @author fabian4 @@ -32,7 +32,7 @@ @SuppressWarnings("all") public class TestController { - @Resource + @Autowired private HystrixTester hystrixTester; @GetMapping("/dtp-example-adapter/testHystrix") diff --git a/example/example-adapter/example-adapter-hystrix/src/main/resources/application.yml b/example/example-adapter/example-adapter-hystrix/src/main/resources/application.yml index 91937e3b3..241e241b7 100644 --- a/example/example-adapter/example-adapter-hystrix/src/main/resources/application.yml +++ b/example/example-adapter/example-adapter-hystrix/src/main/resources/application.yml @@ -32,11 +32,11 @@ dynamictp: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 \ No newline at end of file + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true diff --git a/example/example-adapter/example-adapter-motan/src/main/java/org/dromara/dynamictp/example/controller/TestController.java b/example/example-adapter/example-adapter-motan/src/main/java/org/dromara/dynamictp/example/controller/TestController.java index 4a7490449..b76ed9fca 100644 --- a/example/example-adapter/example-adapter-motan/src/main/java/org/dromara/dynamictp/example/controller/TestController.java +++ b/example/example-adapter/example-adapter-motan/src/main/java/org/dromara/dynamictp/example/controller/TestController.java @@ -22,7 +22,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; +import org.springframework.beans.factory.annotation.Autowired; /** * @author fabian4 @@ -32,7 +32,7 @@ @SuppressWarnings("all") public class TestController { - @Resource + @Autowired private FooService fooService; @GetMapping("/dtp-example-adapter/testMotan") diff --git a/example/example-adapter/example-adapter-motan/src/main/resources/application.yml b/example/example-adapter/example-adapter-motan/src/main/resources/application.yml index c19c4f548..bbb41d47b 100644 --- a/example/example-adapter/example-adapter-motan/src/main/resources/application.yml +++ b/example/example-adapter/example-adapter-motan/src/main/resources/application.yml @@ -32,11 +32,11 @@ dynamictp: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 \ No newline at end of file + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true diff --git a/example/example-adapter/example-adapter-okhttp3/src/main/java/org/dromara/dynamictp/example/controller/TestController.java b/example/example-adapter/example-adapter-okhttp3/src/main/java/org/dromara/dynamictp/example/controller/TestController.java index 6ba7fe66e..e67e2208a 100644 --- a/example/example-adapter/example-adapter-okhttp3/src/main/java/org/dromara/dynamictp/example/controller/TestController.java +++ b/example/example-adapter/example-adapter-okhttp3/src/main/java/org/dromara/dynamictp/example/controller/TestController.java @@ -22,7 +22,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; +import org.springframework.beans.factory.annotation.Autowired; /** * @author fabian4 @@ -32,7 +32,7 @@ @SuppressWarnings("all") public class TestController { - @Resource + @Autowired private Okhttp3Service okhttp3Service; @GetMapping("/dtp-example-adapter/testOkhttp3") diff --git a/example/example-adapter/example-adapter-okhttp3/src/main/java/org/dromara/dynamictp/example/okhttp3/Okhttp3Service.java b/example/example-adapter/example-adapter-okhttp3/src/main/java/org/dromara/dynamictp/example/okhttp3/Okhttp3Service.java index 38d2d095a..fb92172b3 100644 --- a/example/example-adapter/example-adapter-okhttp3/src/main/java/org/dromara/dynamictp/example/okhttp3/Okhttp3Service.java +++ b/example/example-adapter/example-adapter-okhttp3/src/main/java/org/dromara/dynamictp/example/okhttp3/Okhttp3Service.java @@ -23,9 +23,9 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import javax.annotation.Resource; import java.io.IOException; /** @@ -38,7 +38,7 @@ @Service public class Okhttp3Service { - @Resource + @Autowired private OkHttpClient okHttpClient; public void call(String url) { diff --git a/example/example-adapter/example-adapter-okhttp3/src/main/resources/application.yml b/example/example-adapter/example-adapter-okhttp3/src/main/resources/application.yml index 0c0cc60f0..27fae8d5d 100644 --- a/example/example-adapter/example-adapter-okhttp3/src/main/resources/application.yml +++ b/example/example-adapter/example-adapter-okhttp3/src/main/resources/application.yml @@ -40,11 +40,11 @@ dynamictp: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 \ No newline at end of file + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true diff --git a/example/example-adapter/example-adapter-rabbitmq/src/main/java/org/dromara/dynamictp/example/controller/TestController.java b/example/example-adapter/example-adapter-rabbitmq/src/main/java/org/dromara/dynamictp/example/controller/TestController.java index 9022213be..fe3ee41e7 100644 --- a/example/example-adapter/example-adapter-rabbitmq/src/main/java/org/dromara/dynamictp/example/controller/TestController.java +++ b/example/example-adapter/example-adapter-rabbitmq/src/main/java/org/dromara/dynamictp/example/controller/TestController.java @@ -19,11 +19,10 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; - /** * @author fabian4 */ @@ -32,8 +31,8 @@ @SuppressWarnings("all") public class TestController { - @Resource - RabbitTemplate rabbitTemplate; + @Autowired + private RabbitTemplate rabbitTemplate; //使用RabbitTemplate,这提供了接收/发送等等方法 @GetMapping("/dtp-example-adapter/testRabbitMq") public String sendDirectMessage() { diff --git a/example/example-adapter/example-adapter-rabbitmq/src/main/resources/application.yml b/example/example-adapter/example-adapter-rabbitmq/src/main/resources/application.yml index a48b8276c..ece2c3274 100644 --- a/example/example-adapter/example-adapter-rabbitmq/src/main/resources/application.yml +++ b/example/example-adapter/example-adapter-rabbitmq/src/main/resources/application.yml @@ -32,11 +32,11 @@ dynamictp: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 \ No newline at end of file + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true diff --git a/example/example-adapter/example-adapter-rocketmq/src/main/java/org/dromara/dynamictp/example/controller/TestController.java b/example/example-adapter/example-adapter-rocketmq/src/main/java/org/dromara/dynamictp/example/controller/TestController.java index cc9c6d693..c4c3534cd 100644 --- a/example/example-adapter/example-adapter-rocketmq/src/main/java/org/dromara/dynamictp/example/controller/TestController.java +++ b/example/example-adapter/example-adapter-rocketmq/src/main/java/org/dromara/dynamictp/example/controller/TestController.java @@ -22,7 +22,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; +import org.springframework.beans.factory.annotation.Autowired; /** * @author fabian4 @@ -32,7 +32,7 @@ @SuppressWarnings("all") public class TestController { - @Resource + @Autowired private RocketMqProducer rocketMqProducer; @GetMapping("/dtp-example-adapter/testRocketMq") diff --git a/example/example-adapter/example-adapter-rocketmq/src/main/java/org/dromara/dynamictp/example/mq/RocketMqProducer.java b/example/example-adapter/example-adapter-rocketmq/src/main/java/org/dromara/dynamictp/example/mq/RocketMqProducer.java index bc383ab0c..d5abaecc6 100644 --- a/example/example-adapter/example-adapter-rocketmq/src/main/java/org/dromara/dynamictp/example/mq/RocketMqProducer.java +++ b/example/example-adapter/example-adapter-rocketmq/src/main/java/org/dromara/dynamictp/example/mq/RocketMqProducer.java @@ -18,17 +18,16 @@ package org.dromara.dynamictp.example.mq; import org.apache.rocketmq.spring.core.RocketMQTemplate; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import javax.annotation.Resource; - /** * @author fabian */ @Component public class RocketMqProducer { - @Resource + @Autowired private RocketMQTemplate rocketMQTemplate; // 发送消息的实例 diff --git a/example/example-adapter/example-adapter-rocketmq/src/main/resources/application.yml b/example/example-adapter/example-adapter-rocketmq/src/main/resources/application.yml index f951349b9..935f88bd1 100644 --- a/example/example-adapter/example-adapter-rocketmq/src/main/resources/application.yml +++ b/example/example-adapter/example-adapter-rocketmq/src/main/resources/application.yml @@ -39,11 +39,11 @@ rocketmq: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 \ No newline at end of file + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true diff --git a/example/example-adapter/example-adapter-webserver/src/main/java/org/dromara/dynamictp/example/controller/TestController.java b/example/example-adapter/example-adapter-webserver/src/main/java/org/dromara/dynamictp/example/controller/TestController.java index 8f8c08335..9b81a4a2e 100644 --- a/example/example-adapter/example-adapter-webserver/src/main/java/org/dromara/dynamictp/example/controller/TestController.java +++ b/example/example-adapter/example-adapter-webserver/src/main/java/org/dromara/dynamictp/example/controller/TestController.java @@ -17,13 +17,13 @@ package org.dromara.dynamictp.example.controller; +import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.dromara.dynamictp.core.executor.ScheduledDtpExecutor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** @@ -31,25 +31,21 @@ */ @Slf4j @RestController +@AllArgsConstructor @SuppressWarnings("all") public class TestController { - @Resource - private ScheduledDtpExecutor testExecutor; + private final ThreadPoolExecutor testExecutor; - @Resource private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor; @GetMapping("/dtp-example-adapter/testWebserver") public String testWebserver() throws InterruptedException { - testExecutor.schedule(() -> { - try { - Thread.sleep((int) (Math.random() * 1000)); - } catch (InterruptedException e) { - e.printStackTrace(); - } - log.info("success"); - }, 1, TimeUnit.SECONDS); + try { + Thread.sleep((int) (Math.random() * 1000)); + } catch (InterruptedException e) { + e.printStackTrace(); + } return "success"; } diff --git a/example/example-adapter/example-adapter-webserver/src/main/resources/application.yml b/example/example-adapter/example-adapter-webserver/src/main/resources/application.yml index 91e1bae18..aa1b9b109 100644 --- a/example/example-adapter/example-adapter-webserver/src/main/resources/application.yml +++ b/example/example-adapter/example-adapter-webserver/src/main/resources/application.yml @@ -69,11 +69,11 @@ dynamictp: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 \ No newline at end of file + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true diff --git a/example/example-apollo/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java b/example/example-apollo/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java index 0dd2c4334..07c722ee3 100644 --- a/example/example-apollo/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java +++ b/example/example-apollo/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java @@ -17,7 +17,7 @@ package org.dromara.dynamictp.example.collector; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; import org.dromara.dynamictp.common.util.JsonUtil; import org.dromara.dynamictp.core.monitor.collector.AbstractCollector; @@ -36,7 +36,7 @@ public EsCollector() { } @Override - public void collect(ThreadPoolStats poolStats) { + public void collect(ExecutorStats poolStats) { esClient.save(JsonUtil.toJson(poolStats)); } diff --git a/example/example-apollo/src/main/resources/application.yml b/example/example-apollo/src/main/resources/application.yml index 22e97c4d1..11c8cae52 100644 --- a/example/example-apollo/src/main/resources/application.yml +++ b/example/example-apollo/src/main/resources/application.yml @@ -20,11 +20,11 @@ app: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true diff --git a/example/example-consul-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java b/example/example-consul-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java index 0dd2c4334..07c722ee3 100644 --- a/example/example-consul-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java +++ b/example/example-consul-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java @@ -17,7 +17,7 @@ package org.dromara.dynamictp.example.collector; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; import org.dromara.dynamictp.common.util.JsonUtil; import org.dromara.dynamictp.core.monitor.collector.AbstractCollector; @@ -36,7 +36,7 @@ public EsCollector() { } @Override - public void collect(ThreadPoolStats poolStats) { + public void collect(ExecutorStats poolStats) { esClient.save(JsonUtil.toJson(poolStats)); } diff --git a/example/example-consul-cloud/src/main/resources/bootstrap.yml b/example/example-consul-cloud/src/main/resources/bootstrap.yml index ed232938a..1e0a995dc 100644 --- a/example/example-consul-cloud/src/main/resources/bootstrap.yml +++ b/example/example-consul-cloud/src/main/resources/bootstrap.yml @@ -23,14 +23,14 @@ spring: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true mybatis: mapper-locations: classpath:mapper/*.xml diff --git a/example/example-etcd/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java b/example/example-etcd/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java index 0dd2c4334..07c722ee3 100644 --- a/example/example-etcd/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java +++ b/example/example-etcd/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java @@ -17,7 +17,7 @@ package org.dromara.dynamictp.example.collector; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; import org.dromara.dynamictp.common.util.JsonUtil; import org.dromara.dynamictp.core.monitor.collector.AbstractCollector; @@ -36,7 +36,7 @@ public EsCollector() { } @Override - public void collect(ThreadPoolStats poolStats) { + public void collect(ExecutorStats poolStats) { esClient.save(JsonUtil.toJson(poolStats)); } diff --git a/example/example-etcd/src/main/resources/application.yml b/example/example-etcd/src/main/resources/application.yml index 3c1c7a7de..0175559fb 100644 --- a/example/example-etcd/src/main/resources/application.yml +++ b/example/example-etcd/src/main/resources/application.yml @@ -15,11 +15,11 @@ dynamictp: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 \ No newline at end of file + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true diff --git a/example/example-huawei-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java b/example/example-huawei-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java index 0dd2c4334..07c722ee3 100644 --- a/example/example-huawei-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java +++ b/example/example-huawei-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java @@ -17,7 +17,7 @@ package org.dromara.dynamictp.example.collector; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; import org.dromara.dynamictp.common.util.JsonUtil; import org.dromara.dynamictp.core.monitor.collector.AbstractCollector; @@ -36,7 +36,7 @@ public EsCollector() { } @Override - public void collect(ThreadPoolStats poolStats) { + public void collect(ExecutorStats poolStats) { esClient.save(JsonUtil.toJson(poolStats)); } diff --git a/example/example-huawei-cloud/src/main/resources/bootstrap.yml b/example/example-huawei-cloud/src/main/resources/bootstrap.yml index 41590bcbe..04d437ce6 100644 --- a/example/example-huawei-cloud/src/main/resources/bootstrap.yml +++ b/example/example-huawei-cloud/src/main/resources/bootstrap.yml @@ -22,11 +22,11 @@ spring: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 \ No newline at end of file + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true diff --git a/example/example-nacos-cloud/pom.xml b/example/example-nacos-cloud/pom.xml index d5505a9b3..22490e3b1 100644 --- a/example/example-nacos-cloud/pom.xml +++ b/example/example-nacos-cloud/pom.xml @@ -31,27 +31,6 @@ org.springframework.boot spring-boot-starter - - - org.springframework.boot - spring-boot-starter-logging - - - - - - org.apache.logging.log4j - log4j-core - - - - org.apache.logging.log4j - log4j-api - - - - org.apache.logging.log4j - log4j-slf4j-impl @@ -62,19 +41,16 @@ org.dromara.dynamictp dynamic-tp-spring-cloud-starter-nacos - ${revision} org.dromara.dynamictp dynamic-tp-spring-boot-starter-adapter-webserver - ${revision} org.dromara.dynamictp dynamic-tp-spring-boot-starter-extension-limiter-redis - ${revision} diff --git a/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java b/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java index 0dd2c4334..07c722ee3 100644 --- a/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java +++ b/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java @@ -17,7 +17,7 @@ package org.dromara.dynamictp.example.collector; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; import org.dromara.dynamictp.common.util.JsonUtil; import org.dromara.dynamictp.core.monitor.collector.AbstractCollector; @@ -36,7 +36,7 @@ public EsCollector() { } @Override - public void collect(ThreadPoolStats poolStats) { + public void collect(ExecutorStats poolStats) { esClient.save(JsonUtil.toJson(poolStats)); } diff --git a/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/config/ThreadPoolConfiguration.java b/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/config/ThreadPoolConfiguration.java index ff51f8d24..17a9c5220 100644 --- a/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/config/ThreadPoolConfiguration.java +++ b/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/config/ThreadPoolConfiguration.java @@ -26,6 +26,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadPoolExecutor; @@ -62,6 +63,17 @@ public ThreadPoolTaskExecutor threadPoolTaskExecutor() { return new ThreadPoolTaskExecutor(); } + /** + * 通过{@link DynamicTp} 注解定义虚拟线程执行器 + * + * @return 虚拟线程执行器实例 + */ + @DynamicTp("virtualThreadExecutor") + @Bean + public ExecutorService virtualThreadExecutor() { + return Executors.newVirtualThreadPerTaskExecutor(); + } + /** * 通过{@link ThreadPoolCreator} 快速创建一些简单配置的线程池,使用默认参数 * tips: 建议直接在配置中心配置就行,不用@Bean声明 diff --git a/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/controller/TestController.java b/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/controller/TestController.java index 3b69416df..339052b01 100644 --- a/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/controller/TestController.java +++ b/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/controller/TestController.java @@ -68,4 +68,9 @@ public String testOrdered() { testService.testOrderedDtp(); return "testOrderedDtp success"; } + @GetMapping("/dtp-nacos-example/testVTExecutor") + public String testVirtual() { + testService.testVTExecutor(); + return "testVTExecutor success"; + } } diff --git a/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/service/TestService.java b/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/service/TestService.java index dc96fec65..af3c22bff 100644 --- a/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/service/TestService.java +++ b/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/service/TestService.java @@ -54,4 +54,9 @@ public interface TestService { * Test ordered dtp. */ void testOrderedDtp(); + + /** + * Test VTExecutor. + */ + void testVTExecutor(); } diff --git a/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java b/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java index 047661457..1c7b49f2a 100644 --- a/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java +++ b/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java @@ -26,10 +26,12 @@ import org.dromara.dynamictp.core.support.task.runnable.NamedRunnable; import org.dromara.dynamictp.core.support.task.runnable.OrderedRunnable; import org.dromara.dynamictp.example.service.TestService; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Service; import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -54,16 +56,20 @@ public class TestServiceImpl implements TestService { private final OrderedDtpExecutor orderedDtpExecutor; + private final ExecutorService virtualThreadExecutor; + public TestServiceImpl(ThreadPoolExecutor jucThreadPoolExecutor, ThreadPoolTaskExecutor threadPoolTaskExecutor, DtpExecutor eagerDtpExecutor, ScheduledExecutorService scheduledDtpExecutor, - OrderedDtpExecutor orderedDtpExecutor) { + OrderedDtpExecutor orderedDtpExecutor, + @Qualifier("virtualThreadExecutor") ExecutorService virtualThreadExecutor) { this.jucThreadPoolExecutor = jucThreadPoolExecutor; this.threadPoolTaskExecutor = threadPoolTaskExecutor; this.eagerDtpExecutor = eagerDtpExecutor; this.scheduledDtpExecutor = scheduledDtpExecutor; this.orderedDtpExecutor = orderedDtpExecutor; + this.virtualThreadExecutor = virtualThreadExecutor; } @Override @@ -142,10 +148,24 @@ public void testOrderedDtp() { } } + @Override + public void testVTExecutor() { + for (int i = 0; i < 10; i++) { + int finalI = i; + virtualThreadExecutor.execute(() -> { + log.info("i am a VTExecutor's {} task", finalI); + try { + Thread.sleep(30000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }); + } + } + public static class TestOrderedRunnable implements OrderedRunnable { private final UserInfo userInfo; - public TestOrderedRunnable(UserInfo userInfo) { this.userInfo = userInfo; } diff --git a/example/example-nacos-cloud/src/main/resources/bootstrap.yml b/example/example-nacos-cloud/src/main/resources/bootstrap.yml index 71af6a26d..f25c3ae2d 100644 --- a/example/example-nacos-cloud/src/main/resources/bootstrap.yml +++ b/example/example-nacos-cloud/src/main/resources/bootstrap.yml @@ -18,18 +18,19 @@ spring: group: DEFAULT_GROUP refresh: true # 必须配置,负责自动刷新不生效 refresh-enabled: true - redis: - host: ${redis:localhost} - port: 6379 + data: + redis: + host: ${redis:localhost} + port: 6379 # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 \ No newline at end of file + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true \ No newline at end of file diff --git a/example/example-nacos/pom.xml b/example/example-nacos/pom.xml index 0ae1becea..c68ee9067 100644 --- a/example/example-nacos/pom.xml +++ b/example/example-nacos/pom.xml @@ -36,11 +36,7 @@ nacos-config-spring-boot-starter 0.2.12 - - com.alibaba.nacos - nacos-client - 1.4.6 - + org.dromara.dynamictp dynamic-tp-spring-boot-starter-nacos diff --git a/example/example-nacos/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java b/example/example-nacos/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java index 0dd2c4334..07c722ee3 100644 --- a/example/example-nacos/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java +++ b/example/example-nacos/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java @@ -17,7 +17,7 @@ package org.dromara.dynamictp.example.collector; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; import org.dromara.dynamictp.common.util.JsonUtil; import org.dromara.dynamictp.core.monitor.collector.AbstractCollector; @@ -36,7 +36,7 @@ public EsCollector() { } @Override - public void collect(ThreadPoolStats poolStats) { + public void collect(ExecutorStats poolStats) { esClient.save(JsonUtil.toJson(poolStats)); } diff --git a/example/example-nacos/src/main/resources/application.yml b/example/example-nacos/src/main/resources/application.yml index 5647a939f..12d4a312b 100644 --- a/example/example-nacos/src/main/resources/application.yml +++ b/example/example-nacos/src/main/resources/application.yml @@ -21,11 +21,11 @@ nacos: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 \ No newline at end of file + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true \ No newline at end of file diff --git a/example/example-polaris-cloud/pom.xml b/example/example-polaris-cloud/pom.xml index f3cbe9313..276c74c45 100644 --- a/example/example-polaris-cloud/pom.xml +++ b/example/example-polaris-cloud/pom.xml @@ -13,6 +13,7 @@ true + 9.6 @@ -20,7 +21,7 @@ com.tencent.cloud spring-cloud-tencent-dependencies - 1.12.2-2021.0.8 + 1.12.4-2022.0.4 pom import @@ -28,6 +29,13 @@ + + + org.ow2.asm + asm + ${asm.version} + + org.springframework.boot spring-boot-starter-web diff --git a/example/example-polaris-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java b/example/example-polaris-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java index 0dd2c4334..07c722ee3 100644 --- a/example/example-polaris-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java +++ b/example/example-polaris-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java @@ -17,7 +17,7 @@ package org.dromara.dynamictp.example.collector; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; import org.dromara.dynamictp.common.util.JsonUtil; import org.dromara.dynamictp.core.monitor.collector.AbstractCollector; @@ -36,7 +36,7 @@ public EsCollector() { } @Override - public void collect(ThreadPoolStats poolStats) { + public void collect(ExecutorStats poolStats) { esClient.save(JsonUtil.toJson(poolStats)); } diff --git a/example/example-polaris-cloud/src/main/resources/bootstrap.yml b/example/example-polaris-cloud/src/main/resources/bootstrap.yml index 7de6ceb44..416565eab 100644 --- a/example/example-polaris-cloud/src/main/resources/bootstrap.yml +++ b/example/example-polaris-cloud/src/main/resources/bootstrap.yml @@ -22,11 +22,11 @@ spring: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 \ No newline at end of file + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true diff --git a/example/example-zookeeper-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java b/example/example-zookeeper-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java index 0dd2c4334..07c722ee3 100644 --- a/example/example-zookeeper-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java +++ b/example/example-zookeeper-cloud/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java @@ -17,7 +17,7 @@ package org.dromara.dynamictp.example.collector; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; import org.dromara.dynamictp.common.util.JsonUtil; import org.dromara.dynamictp.core.monitor.collector.AbstractCollector; @@ -36,7 +36,7 @@ public EsCollector() { } @Override - public void collect(ThreadPoolStats poolStats) { + public void collect(ExecutorStats poolStats) { esClient.save(JsonUtil.toJson(poolStats)); } diff --git a/example/example-zookeeper-cloud/src/main/resources/bootstrap.yml b/example/example-zookeeper-cloud/src/main/resources/bootstrap.yml index 1c0b2524c..b341549de 100644 --- a/example/example-zookeeper-cloud/src/main/resources/bootstrap.yml +++ b/example/example-zookeeper-cloud/src/main/resources/bootstrap.yml @@ -16,11 +16,11 @@ spring: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 \ No newline at end of file + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true diff --git a/example/example-zookeeper/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java b/example/example-zookeeper/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java index 0dd2c4334..07c722ee3 100644 --- a/example/example-zookeeper/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java +++ b/example/example-zookeeper/src/main/java/org/dromara/dynamictp/example/collector/EsCollector.java @@ -17,7 +17,7 @@ package org.dromara.dynamictp.example.collector; -import org.dromara.dynamictp.common.entity.ThreadPoolStats; +import org.dromara.dynamictp.common.entity.ExecutorStats; import org.dromara.dynamictp.common.util.JsonUtil; import org.dromara.dynamictp.core.monitor.collector.AbstractCollector; @@ -36,7 +36,7 @@ public EsCollector() { } @Override - public void collect(ThreadPoolStats poolStats) { + public void collect(ExecutorStats poolStats) { esClient.save(JsonUtil.toJson(poolStats)); } diff --git a/example/example-zookeeper/src/main/resources/application.yml b/example/example-zookeeper/src/main/resources/application.yml index b56333410..86109dada 100644 --- a/example/example-zookeeper/src/main/resources/application.yml +++ b/example/example-zookeeper/src/main/resources/application.yml @@ -16,11 +16,11 @@ dynamictp: # 开启 SpringBoot Actuator Endpoint 暴露出DynamicTp指标接口 # 开启 prometheus 指标采集端点 management: - metrics: - export: - prometheus: - enabled: true endpoints: web: exposure: - include: '*' # 测试使用,线上不要用*,按需开启 \ No newline at end of file + include: '*' # 测试使用,线上不要用*,按需开启 + prometheus: + metrics: + export: + enabled: true diff --git a/example/pom.xml b/example/pom.xml index 75ea8f54b..bec168355 100644 --- a/example/pom.xml +++ b/example/pom.xml @@ -33,7 +33,7 @@ org.apache.maven.plugins maven-deploy-plugin - 2.8.2 + ${maven-deploy-plugin.version} true diff --git a/extension/extension-limiter-redis/pom.xml b/extension/extension-limiter-redis/pom.xml index e721514ad..c4874be75 100644 --- a/extension/extension-limiter-redis/pom.xml +++ b/extension/extension-limiter-redis/pom.xml @@ -12,8 +12,8 @@ - org.springframework.boot - spring-boot-starter-data-redis + org.springframework.data + spring-data-redis diff --git a/extension/extension-limiter-redis/src/main/java/org/dromara/dynamictp/extension/limiter/redis/ratelimiter/NotifyRedisRateLimiterFilter.java b/extension/extension-limiter-redis/src/main/java/org/dromara/dynamictp/extension/limiter/redis/ratelimiter/NotifyRedisRateLimiterFilter.java index be4a1a4c8..bb5c16582 100644 --- a/extension/extension-limiter-redis/src/main/java/org/dromara/dynamictp/extension/limiter/redis/ratelimiter/NotifyRedisRateLimiterFilter.java +++ b/extension/extension-limiter-redis/src/main/java/org/dromara/dynamictp/extension/limiter/redis/ratelimiter/NotifyRedisRateLimiterFilter.java @@ -22,7 +22,6 @@ import org.dromara.dynamictp.core.notifier.chain.filter.NotifyFilter; import org.dromara.dynamictp.core.notifier.context.BaseNotifyCtx; -import javax.annotation.Resource; import java.util.List; /** @@ -34,8 +33,11 @@ @Slf4j public class NotifyRedisRateLimiterFilter implements NotifyFilter { - @Resource - private RedisRateLimiter> redisScriptRateLimiter; + private final RedisRateLimiter> redisScriptRateLimiter; + + public NotifyRedisRateLimiterFilter(RedisRateLimiter> redisScriptRateLimiter) { + this.redisScriptRateLimiter = redisScriptRateLimiter; + } @Override public int getOrder() { diff --git a/extension/extension-notify-email/pom.xml b/extension/extension-notify-email/pom.xml index 37becc700..c9b2a0776 100644 --- a/extension/extension-notify-email/pom.xml +++ b/extension/extension-notify-email/pom.xml @@ -12,13 +12,18 @@ - org.springframework.boot - spring-boot-starter-mail + org.springframework + spring-context-support - org.springframework.boot - spring-boot-starter-thymeleaf + org.eclipse.angus + jakarta.mail + + + + org.thymeleaf + thymeleaf diff --git a/extension/extension-notify-email/src/main/java/org/dromara/dynamictp/extension/notify/email/EmailNotifier.java b/extension/extension-notify-email/src/main/java/org/dromara/dynamictp/extension/notify/email/EmailNotifier.java index 820c92bd8..1184f5fd5 100644 --- a/extension/extension-notify-email/src/main/java/org/dromara/dynamictp/extension/notify/email/EmailNotifier.java +++ b/extension/extension-notify-email/src/main/java/org/dromara/dynamictp/extension/notify/email/EmailNotifier.java @@ -17,6 +17,7 @@ package org.dromara.dynamictp.extension.notify.email; +import jakarta.mail.internet.MimeMessage; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.common.em.NotifyPlatformEnum; @@ -28,8 +29,6 @@ import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; -import javax.annotation.Resource; -import javax.mail.internet.MimeMessage; import java.util.Date; /** @@ -47,11 +46,14 @@ public class EmailNotifier extends AbstractNotifier { @Value("${spring.mail.title:ThreadPool Notify}") private String title; - @Resource - private JavaMailSender javaMailSender; + private final JavaMailSender javaMailSender; - @Resource - private TemplateEngine templateEngine; + private final TemplateEngine templateEngine; + + public EmailNotifier(JavaMailSender javaMailSender, TemplateEngine templateEngine) { + this.javaMailSender = javaMailSender; + this.templateEngine = templateEngine; + } @Override public String platform() { diff --git a/jvmti/jvmti-runtime/src/main/java/org/dromara/dynamictp/jvmti/JVMTIUtil.java b/jvmti/jvmti-runtime/src/main/java/org/dromara/dynamictp/jvmti/JVMTIUtil.java index 04736a329..9726a03de 100644 --- a/jvmti/jvmti-runtime/src/main/java/org/dromara/dynamictp/jvmti/JVMTIUtil.java +++ b/jvmti/jvmti-runtime/src/main/java/org/dromara/dynamictp/jvmti/JVMTIUtil.java @@ -29,23 +29,23 @@ public class JVMTIUtil { private static String libName; static { - if (OSUtils.isMac()) { + if (OSUtil.isMac()) { libName = "libJniLibrary.dylib"; } - if (OSUtils.isLinux()) { - if (OSUtils.isArm32()) { + if (OSUtil.isLinux()) { + if (OSUtil.isArm32()) { libName = "libJniLibrary-arm.so"; - } else if (OSUtils.isArm64()) { + } else if (OSUtil.isArm64()) { libName = "libJniLibrary-aarch64.so"; - } else if (OSUtils.isX8664()) { + } else if (OSUtil.isX8664()) { libName = "libJniLibrary-x64.so"; } else { - libName = "libJniLibrary-" + OSUtils.arch() + ".so"; + libName = "libJniLibrary-" + OSUtil.arch() + ".so"; } } - if (OSUtils.isWindows()) { + if (OSUtil.isWindows()) { libName = "libJniLibrary-x64.dll"; - if (OSUtils.isX86()) { + if (OSUtil.isX86()) { libName = "libJniLibrary-x86.dll"; } } diff --git a/jvmti/jvmti-runtime/src/main/java/org/dromara/dynamictp/jvmti/OSUtils.java b/jvmti/jvmti-runtime/src/main/java/org/dromara/dynamictp/jvmti/OSUtil.java similarity index 99% rename from jvmti/jvmti-runtime/src/main/java/org/dromara/dynamictp/jvmti/OSUtils.java rename to jvmti/jvmti-runtime/src/main/java/org/dromara/dynamictp/jvmti/OSUtil.java index 88d93ca02..e98100eda 100644 --- a/jvmti/jvmti-runtime/src/main/java/org/dromara/dynamictp/jvmti/OSUtils.java +++ b/jvmti/jvmti-runtime/src/main/java/org/dromara/dynamictp/jvmti/OSUtil.java @@ -26,7 +26,7 @@ * @author dragon-zhang * @since 1.1.6 */ -public class OSUtils { +public class OSUtil { private static final String OPERATING_SYSTEM_NAME = System.getProperty("os.name").toLowerCase(Locale.ENGLISH); @@ -49,7 +49,7 @@ public class OSUtils { arch = normalizeArch(OPERATING_SYSTEM_ARCH); } - private OSUtils() { + private OSUtil() { } public static boolean isWindows() { diff --git a/jvmti/jvmti-runtime/src/main/java/org/dromara/dynamictp/jvmti/PlatformEnum.java b/jvmti/jvmti-runtime/src/main/java/org/dromara/dynamictp/jvmti/PlatformEnum.java index b781c8838..332c46d0d 100644 --- a/jvmti/jvmti-runtime/src/main/java/org/dromara/dynamictp/jvmti/PlatformEnum.java +++ b/jvmti/jvmti-runtime/src/main/java/org/dromara/dynamictp/jvmti/PlatformEnum.java @@ -19,9 +19,8 @@ /** * Enum of supported operating systems. - *

* This file is copied from here - *

+ * * @author dragon-zhang * @since 1.1.6 */ diff --git a/jvmti/jvmti-runtime/src/main/resources/libJniLibrary-x64.dll b/jvmti/jvmti-runtime/src/main/resources/libJniLibrary-x64.dll index c6c1e844f..ceba69f86 100644 Binary files a/jvmti/jvmti-runtime/src/main/resources/libJniLibrary-x64.dll and b/jvmti/jvmti-runtime/src/main/resources/libJniLibrary-x64.dll differ diff --git a/logging/src/main/java/org/dromara/dynamictp/logging/logback/DtpLogbackLogging.java b/logging/src/main/java/org/dromara/dynamictp/logging/logback/DtpLogbackLogging.java index 47f982092..07984a8ad 100644 --- a/logging/src/main/java/org/dromara/dynamictp/logging/logback/DtpLogbackLogging.java +++ b/logging/src/main/java/org/dromara/dynamictp/logging/logback/DtpLogbackLogging.java @@ -18,10 +18,9 @@ package org.dromara.dynamictp.logging.logback; import ch.qos.logback.classic.LoggerContext; -import ch.qos.logback.classic.util.ContextInitializer; +import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.logging.AbstractDtpLogging; import org.dromara.dynamictp.logging.LogHelper; -import lombok.extern.slf4j.Slf4j; /** * DtpLogbackLogging related @@ -40,7 +39,7 @@ public class DtpLogbackLogging extends AbstractDtpLogging { public void loadConfiguration() { try { loggerContext = new LoggerContext(); - new ContextInitializer(loggerContext).configureByResource(getResourceUrl(LOGBACK_LOCATION)); +// new ContextInitializer(loggerContext).configureByResource(getResourceUrl(LOGBACK_LOCATION)); } catch (Exception e) { log.error("Cannot initialize dtp logback logging."); } diff --git a/pom.xml b/pom.xml index 98f6f643f..6dbeded23 100644 --- a/pom.xml +++ b/pom.xml @@ -9,17 +9,19 @@ pom DynamicTp Project - 🔥🔥🔥轻量级动态线程池,内置监控告警功能,基于主流配置中心(已支持Nacos、Apollo、Zookeeper、Consul、Etcd、Polaris,可通过SPI自定义实现) + + 🔥🔥🔥轻量级动态线程池,内置监控告警功能,基于主流配置中心(已支持Nacos、Apollo、Zookeeper、Consul、Etcd、Polaris,可通过SPI自定义实现) + https://github.com/yanhom1314/dynamic-tp - 1.1.9.1 - - 8 - 8 - - 2.7.18 - 2021.0.8 + + 1.1.9.1-3.x + 17 + 17 + + 3.1.4 + 2022.0.3 31.1-jre 4.4 @@ -27,12 +29,13 @@ 1.3.0 3.1.0 3.8.1 - 2.4 - 3.2.0 + 3.2.0 + 3.6.2 1.6 - 1.6.7 + 1.6.13 3.7.1 3.1.0 + 2.8.2 3.3.0 @@ -191,21 +194,43 @@ org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} + maven-surefire-plugin + 3.0.0 - UTF-8 - ${maven.compiler.source} - ${maven.compiler.target} + 1 + false + + --add-opens=java.base/java.lang=ALL-UNNAMED + --add-opens=java.base/java.util=ALL-UNNAMED + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + true + + + main-compile + compile + + compile + testCompile + + + ${maven.compiler.source} + ${maven.compiler.target} + UTF-8 + + + + + org.apache.maven.plugins maven-source-plugin ${maven-source-plugin.version} - - true - package @@ -215,19 +240,21 @@ - org.apache.maven.plugins maven-javadoc-plugin ${maven-javadoc-plugin.version} - package + package jar + + false + @@ -245,11 +272,10 @@ - org.apache.maven.plugins maven-gpg-plugin - 1.6 + ${maven-gpg-plugin.version} verify @@ -263,7 +289,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.7 + ${nexus-staging-maven-plugin.version} true ossrh @@ -271,7 +297,6 @@ false - org.apache.maven.plugins diff --git a/spring/src/main/java/org/dromara/dynamictp/spring/DtpPostProcessor.java b/spring/src/main/java/org/dromara/dynamictp/spring/DtpPostProcessor.java index d2c285137..80e0cbef7 100644 --- a/spring/src/main/java/org/dromara/dynamictp/spring/DtpPostProcessor.java +++ b/spring/src/main/java/org/dromara/dynamictp/spring/DtpPostProcessor.java @@ -21,6 +21,7 @@ import lombok.extern.slf4j.Slf4j; import lombok.val; import org.apache.commons.lang3.StringUtils; +import org.dromara.dynamictp.common.constant.DynamicTpConst; import org.dromara.dynamictp.common.plugin.DtpInterceptorRegistry; import org.dromara.dynamictp.common.util.ConstructorUtil; import org.dromara.dynamictp.common.util.ReflectionUtil; @@ -32,6 +33,7 @@ import org.dromara.dynamictp.core.support.ExecutorWrapper; import org.dromara.dynamictp.core.support.proxy.ScheduledThreadPoolExecutorProxy; import org.dromara.dynamictp.core.support.proxy.ThreadPoolExecutorProxy; +import org.dromara.dynamictp.core.support.proxy.VirtualThreadExecutorProxy; import org.dromara.dynamictp.core.support.task.wrapper.TaskWrapper; import org.dromara.dynamictp.core.support.task.wrapper.TaskWrappers; import org.springframework.beans.BeansException; @@ -54,6 +56,7 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor; @@ -88,13 +91,15 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) thro @Override public Object postProcessAfterInitialization(@NonNull Object bean, @NonNull String beanName) throws BeansException { - if (!(bean instanceof ThreadPoolExecutor) && !(bean instanceof ThreadPoolTaskExecutor)) { + if (!(bean instanceof ThreadPoolExecutor) && !(bean instanceof ThreadPoolTaskExecutor) && + !(bean.getClass().getName().equals(DynamicTpConst.THREAD_PER_TASK_EXECUTOR)) && + !(bean instanceof VirtualThreadExecutorProxy)) { return bean; } if (bean instanceof DtpExecutor) { return registerAndReturnDtp(bean); } - // register juc ThreadPoolExecutor or ThreadPoolTaskExecutor + // register juc ThreadPoolExecutor or ThreadPoolTaskExecutor or VirtualThreadExecutor return registerAndReturnCommon(bean, beanName); } @@ -121,6 +126,9 @@ private Object registerAndReturnCommon(Object bean, String beanName) { } else { BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); if (!(beanDefinition instanceof AnnotatedBeanDefinition)) { + if (beanDefinition.getBeanClassName().equals(VirtualThreadExecutorProxy.class.getName())) { + return doRegisterAndReturnCommon(bean, beanName); + } return bean; } AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition; @@ -148,13 +156,18 @@ private Object doRegisterAndReturnCommon(Object bean, String poolName) { try { ReflectionUtil.setFieldValue("threadPoolExecutor", bean, proxy); tryWrapTaskDecorator(poolName, poolTaskExecutor, proxy); - } catch (IllegalAccessException ignored) { } + } catch (IllegalAccessException ignored) { + } DtpRegistry.registerExecutor(new ExecutorWrapper(poolName, proxy), REGISTER_SOURCE); return bean; } Executor proxy; if (bean instanceof ScheduledThreadPoolExecutor) { proxy = newScheduledTpProxy(poolName, (ScheduledThreadPoolExecutor) bean); + } else if (bean.getClass().getName().equals("java.util.concurrent.ThreadPerTaskExecutor")) { + proxy = newVirtualThreadProxy(poolName, (ExecutorService) bean); + } else if (bean instanceof VirtualThreadExecutorProxy) { + proxy = (Executor) bean; } else { proxy = newProxy(poolName, (ThreadPoolExecutor) bean); } @@ -184,6 +197,10 @@ private ScheduledThreadPoolExecutorProxy newScheduledTpProxy(String name, Schedu return proxy; } + private VirtualThreadExecutorProxy newVirtualThreadProxy(String name, ExecutorService originExecutor) { + return new VirtualThreadExecutorProxy(originExecutor); + } + private void tryWrapTaskDecorator(String poolName, ThreadPoolTaskExecutor poolTaskExecutor, ThreadPoolExecutorProxy proxy) throws IllegalAccessException { Object taskDecorator = ReflectionUtil.getFieldValue("taskDecorator", poolTaskExecutor); if (Objects.isNull(taskDecorator)) { diff --git a/spring/src/main/java/org/dromara/dynamictp/spring/annotation/DtpBeanDefinitionRegistrar.java b/spring/src/main/java/org/dromara/dynamictp/spring/annotation/DtpBeanDefinitionRegistrar.java index c90f62335..d7f43758a 100644 --- a/spring/src/main/java/org/dromara/dynamictp/spring/annotation/DtpBeanDefinitionRegistrar.java +++ b/spring/src/main/java/org/dromara/dynamictp/spring/annotation/DtpBeanDefinitionRegistrar.java @@ -21,6 +21,7 @@ import lombok.extern.slf4j.Slf4j; import lombok.val; import org.apache.commons.collections4.CollectionUtils; +import org.dromara.dynamictp.common.em.JreEnum; import org.dromara.dynamictp.common.entity.DtpExecutorProps; import org.dromara.dynamictp.common.properties.DtpProperties; import org.dromara.dynamictp.core.executor.ExecutorType; @@ -30,6 +31,7 @@ import org.dromara.dynamictp.core.executor.priority.PriorityDtpExecutor; import org.dromara.dynamictp.core.reject.RejectHandlerGetter; import org.dromara.dynamictp.core.support.binder.BinderHelper; +import org.dromara.dynamictp.core.support.proxy.VirtualThreadExecutorProxy; import org.dromara.dynamictp.core.support.task.wrapper.TaskWrappers; import org.dromara.dynamictp.spring.util.BeanRegistrationUtil; import org.springframework.beans.factory.support.BeanDefinitionRegistry; @@ -40,25 +42,11 @@ import java.util.Map; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Executors; import java.util.concurrent.PriorityBlockingQueue; +import java.util.concurrent.ThreadFactory; -import static org.dromara.dynamictp.common.constant.DynamicTpConst.ALLOW_CORE_THREAD_TIMEOUT; -import static org.dromara.dynamictp.common.constant.DynamicTpConst.AWAIT_TERMINATION_SECONDS; -import static org.dromara.dynamictp.common.constant.DynamicTpConst.AWARE_NAMES; -import static org.dromara.dynamictp.common.constant.DynamicTpConst.NOTIFY_ENABLED; -import static org.dromara.dynamictp.common.constant.DynamicTpConst.NOTIFY_ITEMS; -import static org.dromara.dynamictp.common.constant.DynamicTpConst.PLATFORM_IDS; -import static org.dromara.dynamictp.common.constant.DynamicTpConst.PLUGIN_NAMES; -import static org.dromara.dynamictp.common.constant.DynamicTpConst.PRE_START_ALL_CORE_THREADS; -import static org.dromara.dynamictp.common.constant.DynamicTpConst.QUEUE_TIMEOUT; -import static org.dromara.dynamictp.common.constant.DynamicTpConst.REJECT_ENHANCED; -import static org.dromara.dynamictp.common.constant.DynamicTpConst.REJECT_HANDLER_TYPE; -import static org.dromara.dynamictp.common.constant.DynamicTpConst.RUN_TIMEOUT; -import static org.dromara.dynamictp.common.constant.DynamicTpConst.TASK_WRAPPERS; -import static org.dromara.dynamictp.common.constant.DynamicTpConst.THREAD_POOL_ALIAS_NAME; -import static org.dromara.dynamictp.common.constant.DynamicTpConst.THREAD_POOL_NAME; -import static org.dromara.dynamictp.common.constant.DynamicTpConst.TRY_INTERRUPT_WHEN_TIMEOUT; -import static org.dromara.dynamictp.common.constant.DynamicTpConst.WAIT_FOR_TASKS_TO_COMPLETE_ON_SHUTDOWN; +import static org.dromara.dynamictp.common.constant.DynamicTpConst.*; import static org.dromara.dynamictp.common.em.QueueTypeEnum.buildLbq; import static org.dromara.dynamictp.common.entity.NotifyItem.mergeAllNotifyItems; @@ -94,7 +82,13 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B } Class executorTypeClass = ExecutorType.getClass(e.getExecutorType()); Map propertyValues = buildPropertyValues(e); - Object[] args = buildConstructorArgs(executorTypeClass, e); + Object[] args; + try { + args = buildConstructorArgs(executorTypeClass, e); + } catch (UnsupportedOperationException exception) { + log.warn("DynamicTp virtual thread executor {} register warn: update your JDK version or don't use virtual thread executor!", e.getThreadPoolName()); + return; + } BeanRegistrationUtil.register(registry, e.getThreadPoolName(), executorTypeClass, propertyValues, args); }); } @@ -103,15 +97,19 @@ private Map buildPropertyValues(DtpExecutorProps props) { Map propertyValues = Maps.newHashMap(); propertyValues.put(THREAD_POOL_NAME, props.getThreadPoolName()); propertyValues.put(THREAD_POOL_ALIAS_NAME, props.getThreadPoolAliasName()); - propertyValues.put(ALLOW_CORE_THREAD_TIMEOUT, props.isAllowCoreThreadTimeOut()); - propertyValues.put(WAIT_FOR_TASKS_TO_COMPLETE_ON_SHUTDOWN, props.isWaitForTasksToCompleteOnShutdown()); - propertyValues.put(AWAIT_TERMINATION_SECONDS, props.getAwaitTerminationSeconds()); - propertyValues.put(PRE_START_ALL_CORE_THREADS, props.isPreStartAllCoreThreads()); - propertyValues.put(REJECT_HANDLER_TYPE, props.getRejectedHandlerType()); - propertyValues.put(REJECT_ENHANCED, props.isRejectEnhanced()); - propertyValues.put(RUN_TIMEOUT, props.getRunTimeout()); - propertyValues.put(TRY_INTERRUPT_WHEN_TIMEOUT, props.isTryInterrupt()); - propertyValues.put(QUEUE_TIMEOUT, props.getQueueTimeout()); + + if (!props.getExecutorType().equals(ExecutorType.VIRTUAL.getName())) { + propertyValues.put(ALLOW_CORE_THREAD_TIMEOUT, props.isAllowCoreThreadTimeOut()); + propertyValues.put(WAIT_FOR_TASKS_TO_COMPLETE_ON_SHUTDOWN, props.isWaitForTasksToCompleteOnShutdown()); + propertyValues.put(AWAIT_TERMINATION_SECONDS, props.getAwaitTerminationSeconds()); + propertyValues.put(PRE_START_ALL_CORE_THREADS, props.isPreStartAllCoreThreads()); + propertyValues.put(REJECT_HANDLER_TYPE, props.getRejectedHandlerType()); + propertyValues.put(REJECT_ENHANCED, props.isRejectEnhanced()); + propertyValues.put(RUN_TIMEOUT, props.getRunTimeout()); + propertyValues.put(TRY_INTERRUPT_WHEN_TIMEOUT, props.isTryInterrupt()); + propertyValues.put(QUEUE_TIMEOUT, props.getQueueTimeout()); + } + val notifyItems = mergeAllNotifyItems(props.getNotifyItems()); propertyValues.put(NOTIFY_ITEMS, notifyItems); propertyValues.put(PLATFORM_IDS, props.getPlatformIds()); @@ -124,9 +122,17 @@ private Map buildPropertyValues(DtpExecutorProps props) { return propertyValues; } - private Object[] buildConstructorArgs(Class clazz, DtpExecutorProps props) { + private Object[] buildConstructorArgs(Class clazz, DtpExecutorProps props) throws UnsupportedOperationException { BlockingQueue taskQueue; - if (clazz.equals(EagerDtpExecutor.class)) { + if (clazz.equals(VirtualThreadExecutorProxy.class)) { + if (JreEnum.lessThan(JreEnum.JAVA_21)) { + throw new UnsupportedOperationException(); + } + ThreadFactory factory = Thread.ofVirtual().name(props.getThreadPoolName()).factory(); + return new Object[]{ + Executors.newThreadPerTaskExecutor(factory) + }; + } else if (clazz.equals(EagerDtpExecutor.class)) { taskQueue = new TaskQueue(props.getQueueCapacity()); } else if (clazz.equals(PriorityDtpExecutor.class)) { taskQueue = new PriorityBlockingQueue<>(props.getQueueCapacity(), PriorityDtpExecutor.getRunnableComparator()); diff --git a/starter/starter-adapter/starter-adapter-brpc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-adapter/starter-adapter-brpc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..b34d62555 --- /dev/null +++ b/starter/starter-adapter/starter-adapter-brpc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.adapter.brpc.autoconfigure.BrpcTpAutoConfiguration \ No newline at end of file diff --git a/starter/starter-adapter/starter-adapter-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-adapter/starter-adapter-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..cdfbe5368 --- /dev/null +++ b/starter/starter-adapter/starter-adapter-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.adapter.common.autoconfigure.AdapterCommonAutoConfiguration \ No newline at end of file diff --git a/starter/starter-adapter/starter-adapter-dubbo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-adapter/starter-adapter-dubbo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..031abc5f8 --- /dev/null +++ b/starter/starter-adapter/starter-adapter-dubbo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,2 @@ +org.dromara.dynamictp.starter.adapter.dubbo.autoconfigure.ApacheDubboTpAutoConfiguration +org.dromara.dynamictp.starter.adapter.dubbo.autoconfigure.AlibabaDubboTpAutoConfiguration \ No newline at end of file diff --git a/starter/starter-adapter/starter-adapter-grpc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-adapter/starter-adapter-grpc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..ffb277cfe --- /dev/null +++ b/starter/starter-adapter/starter-adapter-grpc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.adapter.grpc.autoconfigure.GrpcTpAutoConfiguration \ No newline at end of file diff --git a/starter/starter-adapter/starter-adapter-hystrix/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-adapter/starter-adapter-hystrix/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..622ef2ece --- /dev/null +++ b/starter/starter-adapter/starter-adapter-hystrix/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.adapter.hystrix.autoconfigure.HystrixTpAutoConfiguration \ No newline at end of file diff --git a/starter/starter-adapter/starter-adapter-motan/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-adapter/starter-adapter-motan/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..242dd55bd --- /dev/null +++ b/starter/starter-adapter/starter-adapter-motan/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.adapter.motan.autoconfigure.MotanTpAutoConfiguration \ No newline at end of file diff --git a/starter/starter-adapter/starter-adapter-okhttp3/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-adapter/starter-adapter-okhttp3/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..bd80ba4ce --- /dev/null +++ b/starter/starter-adapter/starter-adapter-okhttp3/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.adapter.okhttp3.autoconfigure.Okhttp3TpAutoConfiguration \ No newline at end of file diff --git a/starter/starter-adapter/starter-adapter-rabbitmq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-adapter/starter-adapter-rabbitmq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..6b9d66129 --- /dev/null +++ b/starter/starter-adapter/starter-adapter-rabbitmq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.adapter.rabbitmq.autoconfigure.RabbitMqTpAutoConfiguration \ No newline at end of file diff --git a/starter/starter-adapter/starter-adapter-rocketmq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-adapter/starter-adapter-rocketmq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..461f00ec2 --- /dev/null +++ b/starter/starter-adapter/starter-adapter-rocketmq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,2 @@ +org.dromara.dynamictp.starter.adapter.rocketmq.autoconfigure.RocketMqTpAutoConfiguration +org.dromara.dynamictp.starter.adapter.rocketmq.autoconfigure.AliyunOnsRocketMqAutoConfiguration \ No newline at end of file diff --git a/starter/starter-adapter/starter-adapter-sofa/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-adapter/starter-adapter-sofa/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..cf7691e23 --- /dev/null +++ b/starter/starter-adapter/starter-adapter-sofa/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.adapter.sofa.autoconfigure.SofaTpAutoConfiguration \ No newline at end of file diff --git a/starter/starter-adapter/starter-adapter-tars/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-adapter/starter-adapter-tars/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..1fe8fcf04 --- /dev/null +++ b/starter/starter-adapter/starter-adapter-tars/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.adapter.tars.autoconfigure.TarsTpAutoConfiguration \ No newline at end of file diff --git a/starter/starter-adapter/starter-adapter-webserver/src/main/java/org/jboss/threads/EnhancedQueueExecutor.java b/starter/starter-adapter/starter-adapter-webserver/src/main/java/org/jboss/threads/EnhancedQueueExecutor.java index e95156d5c..3e3b73892 100644 --- a/starter/starter-adapter/starter-adapter-webserver/src/main/java/org/jboss/threads/EnhancedQueueExecutor.java +++ b/starter/starter-adapter/starter-adapter-webserver/src/main/java/org/jboss/threads/EnhancedQueueExecutor.java @@ -50,19 +50,33 @@ import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Hashtable; import java.util.List; +import java.util.NoSuchElementException; import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.Callable; +import java.util.concurrent.CancellationException; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Delayed; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.LongAdder; +import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.LockSupport; +import java.util.concurrent.locks.ReentrantLock; import javax.management.ObjectInstance; import javax.management.ObjectName; @@ -79,12 +93,15 @@ * necessary size. In addition, the optional {@linkplain #setGrowthResistance(float) growth resistance feature} can * be used to further govern the thread pool size. *

+ * Additionally, this thread pool implementation supports scheduling of tasks. + * The scheduled tasks will execute on the main pool. + *

* New instances of this thread pool are created by constructing and configuring a {@link Builder} instance, and calling * its {@link Builder#build() build()} method. * * @author David M. Lloyd */ -public class EnhancedQueueExecutor extends EnhancedQueueExecutorBase6 implements ManageableThreadPoolExecutorService { +public class EnhancedQueueExecutor extends EnhancedQueueExecutorBase6 implements ManageableThreadPoolExecutorService, ScheduledExecutorService { private static final Thread[] NO_THREADS = new Thread[0]; static { @@ -145,10 +162,6 @@ public class EnhancedQueueExecutor extends EnhancedQueueExecutorBase6 implements */ public static final boolean DISABLE_HINT = readBooleanPropertyPrefixed("disable", false); - /** - * Update the tail pointer opportunistically. - */ - static final boolean UPDATE_TAIL = readBooleanPropertyPrefixed("update-tail", false); /** * Update the summary statistics. */ @@ -207,8 +220,21 @@ public class EnhancedQueueExecutor extends EnhancedQueueExecutorBase6 implements private final Object handle; /** * The access control context of the creating thread. + * Will be set to null when the MBean is not registered. + */ + private volatile AccessControlContext acc; + /** + * The context handler for the user-defined context. + */ + private final ContextHandler contextHandler; + /** + * The task for scheduled execution. + */ + private final SchedulerTask schedulerTask = new SchedulerTask(); + /** + * The scheduler thread. */ - private final AccessControlContext acc; + private final Thread schedulerThread; // ======================================================= // Current state fields @@ -296,9 +322,6 @@ public class EnhancedQueueExecutor extends EnhancedQueueExecutorBase6 implements private static final long activeCountOffset; private static final long peakQueueSizeOffset; - private static final Object sequenceBase; - private static final long sequenceOffset; - static { try { terminationWaitersOffset = unsafe.objectFieldOffset(EnhancedQueueExecutor.class.getDeclaredField("terminationWaiters")); @@ -308,9 +331,6 @@ public class EnhancedQueueExecutor extends EnhancedQueueExecutorBase6 implements peakThreadCountOffset = unsafe.objectFieldOffset(EnhancedQueueExecutor.class.getDeclaredField("peakThreadCount")); activeCountOffset = unsafe.objectFieldOffset(EnhancedQueueExecutor.class.getDeclaredField("activeCount")); peakQueueSizeOffset = unsafe.objectFieldOffset(EnhancedQueueExecutor.class.getDeclaredField("peakQueueSize")); - - sequenceBase = unsafe.staticFieldBase(EnhancedQueueExecutor.class.getDeclaredField("sequence")); - sequenceOffset = unsafe.staticFieldOffset(EnhancedQueueExecutor.class.getDeclaredField("sequence")); } catch (NoSuchFieldException e) { throw new NoSuchFieldError(e.getMessage()); } @@ -360,20 +380,23 @@ public class EnhancedQueueExecutor extends EnhancedQueueExecutorBase6 implements // Constructor // ======================================================= - static volatile int sequence = 1; + static final AtomicInteger sequence = new AtomicInteger(1); private final String mBeanName; - protected EnhancedQueueExecutor(final Builder builder) { + public EnhancedQueueExecutor(final Builder builder) { super(); - this.acc = getContext(); int maxSize = builder.getMaximumPoolSize(); int coreSize = min(builder.getCorePoolSize(), maxSize); this.handoffExecutor = builder.getHandoffExecutor(); this.exceptionHandler = builder.getExceptionHandler(); this.threadFactory = builder.getThreadFactory(); + this.schedulerThread = threadFactory.newThread(schedulerTask); + String schedulerName = this.schedulerThread.getName(); + this.schedulerThread.setName(schedulerName + " (scheduler)"); this.terminationTask = builder.getTerminationTask(); this.growthResistance = builder.getGrowthResistance(); + this.contextHandler = builder.getContextHandler(); final Duration keepAliveTime = builder.getKeepAliveTime(); // initial dead node // thread stat @@ -383,11 +406,13 @@ protected EnhancedQueueExecutor(final Builder builder) { mxBean = new MXBeanImpl(); mBeanName = builder.getMBeanName(); if (! DISABLE_MBEAN && builder.isRegisterMBean()) { + this.acc = getContext(); final String configuredName = builder.getMBeanName(); - final String finalName = configuredName != null ? configuredName : "threadpool-" + unsafe.getAndAddInt(sequenceBase, sequenceOffset, 1); + final String finalName = configuredName != null ? configuredName : "threadpool-" + sequence.getAndIncrement(); handle = doPrivileged(new MBeanRegisterAction(finalName, mxBean), acc); } else { handle = null; + this.acc = null; } } @@ -433,6 +458,7 @@ public static final class Builder { private int maxQueueSize = Integer.MAX_VALUE; private boolean registerMBean = REGISTER_MBEAN; private String mBeanName; + private ContextHandler contextHandler = ContextHandler.NONE; /** * Construct a new instance. @@ -757,12 +783,49 @@ public Builder setMBeanName(final String mBeanName) { this.mBeanName = mBeanName; return this; } + + /** + * Get the context handler for the user-defined context. + * + * @return the context handler for the user-defined context (not {@code null}) + */ + public ContextHandler getContextHandler() { + return contextHandler; + } + + /** + * Set the context handler for the user-defined context. + * + * @param contextHandler the context handler for the user-defined context + * @return this builder + */ + public Builder setContextHandler(final ContextHandler contextHandler) { + Assert.checkNotNullParam("contextHandler", contextHandler); + this.contextHandler = contextHandler; + return this; + } } // ======================================================= // ExecutorService // ======================================================= + public ThreadFactory getThreadFactory() { + return threadFactory; + } + + public MXBeanImpl getMxBean() { + return mxBean; + } + + public Runnable getTerminationTask() { + return terminationTask; + } + + public String getMBeanName() { + return mBeanName; + } + /** * Execute a task. * @@ -770,7 +833,7 @@ public Builder setMBeanName(final String mBeanName) { */ public void execute(Runnable runnable) { Assert.checkNotNullParam("runnable", runnable); - final Runnable realRunnable = JBossExecutors.classLoaderPreservingTaskUnchecked(runnable); + final Task realRunnable = new Task(runnable, contextHandler.captureContext()); int result; result = tryExecute(realRunnable); boolean ok = false; @@ -796,22 +859,6 @@ public void execute(Runnable runnable) { } } - public ThreadFactory getThreadFactory() { - return threadFactory; - } - - public MXBeanImpl getMxBean() { - return mxBean; - } - - public Runnable getTerminationTask() { - return terminationTask; - } - - public String getMBeanName() { - return mBeanName; - } - /** * Request that shutdown be initiated for this thread pool. This is equivalent to calling * {@link #shutdown(boolean) shutdown(false)}; see that method for more information. @@ -834,14 +881,19 @@ public List shutdownNow() { QNode headNext; for (;;) { headNext = head.getNext(); + if (headNext == head) { + // a racing consumer has already consumed it (and moved head) + head = this.head; + continue; + } if (headNext instanceof TaskNode) { TaskNode taskNode = (TaskNode) headNext; if (compareAndSetHead(head, taskNode)) { - if (! NO_QUEUE_LIMIT) { - decreaseQueueSize(); - } + // save from GC nepotism + head.setNextOrdered(head); + if (! NO_QUEUE_LIMIT) decreaseQueueSize(); head = taskNode; - list.add(taskNode.task); + list.add(taskNode.task.handoff()); } // retry } else { @@ -884,7 +936,7 @@ public boolean awaitTermination(final long timeout, final TimeUnit unit) throws Assert.checkNotNullParam("unit", unit); if (timeout > 0) { final Thread thread = Thread.currentThread(); - if (runningThreads.contains(thread)) { + if (runningThreads.contains(thread) || thread == schedulerThread) { throw Messages.msg.cannotAwaitWithin(); } Waiter waiters = this.terminationWaiters; @@ -911,6 +963,39 @@ public boolean awaitTermination(final long timeout, final TimeUnit unit) throws return isTerminated(); } + // ======================================================= + // ScheduledExecutorService + // ======================================================= + + public ScheduledFuture schedule(final Runnable command, final long delay, final TimeUnit unit) { + startScheduleThread(); + return schedulerTask.schedule(new RunnableScheduledFuture(command, delay, unit)); + } + + public ScheduledFuture schedule(final Callable callable, final long delay, final TimeUnit unit) { + startScheduleThread(); + return schedulerTask.schedule(new CallableScheduledFuture(callable, delay, unit)); + } + + public ScheduledFuture scheduleAtFixedRate(final Runnable command, final long initialDelay, final long period, final TimeUnit unit) { + startScheduleThread(); + return schedulerTask.schedule(new FixedRateRunnableScheduledFuture(command, initialDelay, period, unit)); + } + + public ScheduledFuture scheduleWithFixedDelay(final Runnable command, final long initialDelay, final long delay, final TimeUnit unit) { + startScheduleThread(); + return schedulerTask.schedule(new FixedDelayRunnableScheduledFuture(command, initialDelay, delay, unit)); + } + + private void startScheduleThread() { + // this should be fairly quick... + if (schedulerThread.getState() == Thread.State.NEW) try { + schedulerThread.start(); + } catch (IllegalThreadStateException ignored) { + // make sure it's race-proof + } + } + // ======================================================= // Management // ======================================================= @@ -959,6 +1044,8 @@ public void shutdown(boolean interrupt) { if (isShutdownRequested(newStatus) != isShutdownRequested(oldStatus)) { assert ! isShutdownRequested(oldStatus); // because it can only ever be set, not cleared // we initiated shutdown + // terminate the scheduler + schedulerTask.shutdown(); // clear out all consumers and append a dummy waiter node TaskNode tail = this.tail; QNode tailNext; @@ -1442,9 +1529,9 @@ public Void run() { // ======================================================= final class ThreadBody implements Runnable { - private Runnable initialTask; + private Task initialTask; - ThreadBody(final Runnable initialTask) { + ThreadBody(final Task initialTask) { this.initialTask = initialTask; } @@ -1458,7 +1545,7 @@ public void run() { runningThreads.add(currentThread); // run the initial task - doRunTask(getAndClearInitialTask()); + nullToNop(getAndClearInitialTask()).run(); // Eagerly allocate a PoolThreadNode for the next time it's needed PoolThreadNode nextPoolThreadNode = new PoolThreadNode(currentThread); @@ -1468,7 +1555,7 @@ public void run() { node = getOrAddNode(nextPoolThreadNode); if (node instanceof TaskNode) { // task node was removed - doRunTask(((TaskNode) node).getAndClearTask()); + ((TaskNode) node).getAndClearTask().run(); continue; } else if (node == nextPoolThreadNode) { // pool thread node was added @@ -1480,11 +1567,11 @@ public void run() { long elapsed = 0L; waitingForTask: for (;;) { Runnable task = newNode.getTask(); - assert task != ACCEPTED && task != GAVE_UP; + assert task != ACCEPTED && task != GAVE_UP && task != null; if (task != WAITING && task != EXIT) { if (newNode.compareAndSetTask(task, ACCEPTED)) { // we have a task to run, so run it and then abandon the node - doRunTask(task); + task.run(); // rerun outer continue processingQueue; } @@ -1557,50 +1644,43 @@ private QNode getOrAddNode(PoolThreadNode nextPoolThreadNode) { for (;;) { head = EnhancedQueueExecutor.this.head; headNext = head.getNext(); - if (headNext instanceof TaskNode) { - TaskNode taskNode = (TaskNode) headNext; - if (compareAndSetHead(head, taskNode)) { - if (! NO_QUEUE_LIMIT) decreaseQueueSize(); - return taskNode; - } - } else if (headNext instanceof PoolThreadNode || headNext == null) { - nextPoolThreadNode.setNextRelaxed(headNext); - if (head.compareAndSetNext(headNext, nextPoolThreadNode)) { - return nextPoolThreadNode; + // headNext == head can happen if another consumer has already consumed head: + // retry with a fresh head + if (headNext != head) { + if (headNext instanceof TaskNode) { + TaskNode taskNode = (TaskNode) headNext; + if (compareAndSetHead(head, taskNode)) { + // save from GC Nepotism: generational GCs don't like + // cross-generational references, so better to "clean-up" head::next + // to save dragging head::next into the old generation. + // Clean-up cannot just null out next + head.setNextOrdered(head); + if (!NO_QUEUE_LIMIT) decreaseQueueSize(); + return taskNode; + } + } else if (headNext instanceof PoolThreadNode || headNext == null) { + nextPoolThreadNode.setNextRelaxed(headNext); + if (head.compareAndSetNext(headNext, nextPoolThreadNode)) { + return nextPoolThreadNode; + } else if (headNext != null) { + // GC Nepotism: + // save dragging headNext into old generation + // (although being a PoolThreadNode it won't make a big difference) + nextPoolThreadNode.setNextRelaxed(null); + } + } else { + assert headNext instanceof TerminateWaiterNode; + return headNext; } - } else { - assert headNext instanceof TerminateWaiterNode; - return headNext; } if (UPDATE_STATISTICS) spinMisses.increment(); - JDKSpecific.onSpinWait(); } } private Runnable getAndClearInitialTask() { - try { - return initialTask; - } finally { - this.initialTask = null; - } - } - - void doRunTask(final Runnable task) { - if (task != null) { - if (isShutdownInterrupt(threadStatus)) { - Thread.currentThread().interrupt(); - } else { - Thread.interrupted(); - } - if (UPDATE_ACTIVE_COUNT) incrementActiveCount(); - safeRun(task); - if (UPDATE_ACTIVE_COUNT) { - decrementActiveCount(); - if (UPDATE_STATISTICS) { - completedTaskCounter.increment(); - } - } - } + Runnable initial = initialTask; + this.initialTask = null; + return initial; } } @@ -1703,7 +1783,7 @@ boolean tryDeallocateThread(long oldStat) { * @return {@code true} if the thread was started, {@code false} otherwise * @throws RejectedExecutionException if {@code runnable} is not {@code null} and the thread could not be created or started */ - boolean doStartThread(Runnable runnable) throws RejectedExecutionException { + boolean doStartThread(Task runnable) throws RejectedExecutionException { Thread thread; try { thread = threadFactory.newThread(new ThreadBody(runnable)); @@ -1737,83 +1817,29 @@ boolean doStartThread(Runnable runnable) throws RejectedExecutionException { // Task submission // ======================================================= - private int tryExecute(final Runnable runnable) { + private int tryExecute(final Task runnable) { QNode tailNext; - if (TAIL_LOCK) lockTail(); TaskNode tail = this.tail; TaskNode node = null; for (;;) { tailNext = tail.getNext(); - if (tailNext instanceof TaskNode) { - TaskNode tailNextTaskNode; - do { - if (UPDATE_STATISTICS) spinMisses.increment(); - tailNextTaskNode = (TaskNode) tailNext; - // retry - tail = tailNextTaskNode; - tailNext = tail.getNext(); - } while (tailNext instanceof TaskNode); - // opportunistically update for the possible benefit of other threads - if (UPDATE_TAIL) compareAndSetTail(tail, tailNextTaskNode); - } - // we've progressed to the first non-task node, as far as we can see - assert ! (tailNext instanceof TaskNode); - if (tailNext instanceof PoolThreadNode) { - final QNode tailNextNext = tailNext.getNext(); - // state change ex1: - // tail(snapshot).next ← tail(snapshot).next(snapshot).next(snapshot) - // succeeds: - - // cannot succeed: sh2 - // preconditions: - // tail(snapshot) is a dead TaskNode - // tail(snapshot).next is PoolThreadNode - // tail(snapshot).next.next* is PoolThreadNode or null - // additional success postconditions: - - // failure postconditions: - - // post-actions (succeed): - // run state change ex2 - // post-actions (fail): - // retry with new tail(snapshot) - if (tail.compareAndSetNext(tailNext, tailNextNext)) { - assert tail instanceof TaskNode && tail.task == null; - PoolThreadNode consumerNode = (PoolThreadNode) tailNext; - // state change ex2: - // tail(snapshot).next(snapshot).task ← runnable - // succeeds: ex1 - // preconditions: - // tail(snapshot).next(snapshot).task = WAITING - // post-actions (succeed): - // unpark thread and return - // post-actions (fail): - // retry outer with new tail(snapshot) - if (consumerNode.compareAndSetTask(WAITING, runnable)) { - if (TAIL_LOCK) unlockTail(); - consumerNode.unpark(); - return EXE_OK; - } - // otherwise the consumer gave up or was exited already, so fall out and... - } - if (UPDATE_STATISTICS) spinMisses.increment(); - // retry with new tail(snapshot) as was foretold - tail = this.tail; + if (tailNext == tail) { + // tail is already consumed, retry with new tail(snapshot) } else if (tailNext == null) { // no consumers available; maybe we can start one int tr = tryAllocateThread(growthResistance); if (tr == AT_YES) { - if (TAIL_LOCK) unlockTail(); return EXE_CREATE_THREAD; } if (tr == AT_SHUTDOWN) { - if (TAIL_LOCK) unlockTail(); return EXE_REJECT_SHUTDOWN; } assert tr == AT_NO; // no; try to enqueue - if (! NO_QUEUE_LIMIT && ! increaseQueueSize()) { + if (!NO_QUEUE_LIMIT && !increaseQueueSize()) { // queue is full // OK last effort to create a thread, disregarding growth limit tr = tryAllocateThread(0.0f); - if (TAIL_LOCK) unlockTail(); if (tr == AT_YES) { return EXE_CREATE_THREAD; } @@ -1841,21 +1867,66 @@ private int tryExecute(final Runnable runnable) { // try to update tail to the new node; if this CAS fails then tail already points at past the node // this is because tail can only ever move forward, and the task list is always strongly connected compareAndSetTail(tail, node); - if (TAIL_LOCK) unlockTail(); return EXE_OK; } // we failed; we have to drop the queue size back down again to compensate before we can retry - if (! NO_QUEUE_LIMIT) decreaseQueueSize(); - if (UPDATE_STATISTICS) spinMisses.increment(); - // retry with new tail(snapshot) - tail = this.tail; + if (!NO_QUEUE_LIMIT) decreaseQueueSize(); + } else if (tailNext instanceof PoolThreadNode) { + final QNode tailNextNext = tailNext.getNext(); + // state change ex1: + // tail(snapshot).next ← tail(snapshot).next(snapshot).next(snapshot) + // succeeds: - + // cannot succeed: sh2 + // preconditions: + // tail(snapshot) is a dead TaskNode + // tail(snapshot).next is PoolThreadNode + // tail(snapshot).next.next* is PoolThreadNode or null + // additional success postconditions: - + // failure postconditions: - + // post-actions (succeed): + // run state change ex2 + // post-actions (fail): + // retry with new tail(snapshot) + if (tail.compareAndSetNext(tailNext, tailNextNext)) { + assert tail instanceof TaskNode; + PoolThreadNode consumerNode = (PoolThreadNode) tailNext; + // state change ex2: + // tail(snapshot).next(snapshot).task ← runnable + // succeeds: ex1 + // preconditions: + // tail(snapshot).next(snapshot).task = WAITING + // post-actions (succeed): + // unpark thread and return + // post-actions (fail): + // retry outer with new tail(snapshot) + if (consumerNode.compareAndSetTask(WAITING, runnable)) { + // GC Nepotism: + // We can save consumerNode::next from being dragged into + // old generation, if possible + consumerNode.compareAndSetNext(tailNextNext, null); + consumerNode.unpark(); + return EXE_OK; + } + // otherwise the consumer gave up or was exited already, so fall out and... + } + } else if (tailNext instanceof TaskNode) { + TaskNode tailNextTaskNode = (TaskNode) tailNext; + // Opportunistically update tail to the next node. If this operation has been handled by + // another thread we fall back to the loop and try again instead of duplicating effort. + if (compareAndSetTail(tail, tailNextTaskNode)) { + tail = tailNextTaskNode; + // bypass the on-spin-miss path because we've updated the next task node to tailNextTaskNode. + continue; + } } else { - if (TAIL_LOCK) unlockTail(); // no consumers are waiting and the tail(snapshot).next node is non-null and not a task node, therefore it must be a... assert tailNext instanceof TerminateWaiterNode; // shutting down return EXE_REJECT_SHUTDOWN; } + // retry with new tail(snapshot) + if (UPDATE_STATISTICS) spinMisses.increment(); + tail = this.tail; } // not reached } @@ -1866,21 +1937,41 @@ private int tryExecute(final Runnable runnable) { void completeTermination() { // be kind and un-interrupt the thread for the termination task - Thread.interrupted(); - final Runnable terminationTask = this.terminationTask; - this.terminationTask = null; - safeRun(terminationTask); - // notify all waiters - Waiter waiters = getAndSetTerminationWaiters(TERMINATE_COMPLETE_WAITER); - while (waiters != null) { - unpark(waiters.getThread()); - waiters = waiters.getNext(); - } - tail.setNext(TERMINATE_COMPLETE); - if (! DISABLE_MBEAN) { - final Object handle = this.handle; - if (handle != null) { - doPrivileged(new MBeanUnregisterAction(handle), acc); + boolean intr = Thread.interrupted(); + try { + final Runnable terminationTask = JBossExecutors.classLoaderPreservingTask(this.terminationTask); + this.terminationTask = null; + try { + terminationTask.run(); + } catch (Throwable t) { + try { + exceptionHandler.uncaughtException(Thread.currentThread(), t); + } catch (Throwable ignored) { + // nothing else we can safely do here + } + } + // notify all waiters + Waiter waiters = getAndSetTerminationWaiters(TERMINATE_COMPLETE_WAITER); + while (waiters != null) { + unpark(waiters.getThread()); + waiters = waiters.getNext(); + } + tail.setNext(TERMINATE_COMPLETE); + if (!DISABLE_MBEAN) { + //The check for DISABLE_MBEAN is redundant as acc would be null, + //but GraalVM needs the hint so to not make JMX reachable. + if (this.acc != null) { + final Object handle = this.handle; + if (handle != null) { + intr = intr || Thread.interrupted(); + doPrivileged(new MBeanUnregisterAction(handle), acc); + } + this.acc = null; + } + } + } finally { + if (intr) { + Thread.currentThread().interrupt(); } } } @@ -2049,61 +2140,46 @@ static boolean isAllowCoreTimeout(final long oldVal) { // Utilities // ======================================================= - void safeRun(final Runnable task) { - if (task == null) return; - final Thread currentThread = Thread.currentThread(); - JBossExecutors.clearContextClassLoader(currentThread); - try { - task.run(); - } catch (Throwable t) { - try { - exceptionHandler.uncaughtException(Thread.currentThread(), t); - } catch (Throwable ignored) { - // nothing else we can safely do here - } - } finally { - JBossExecutors.clearContextClassLoader(currentThread); - // clear interrupt status - Thread.interrupted(); - } - } - - void rejectException(final Runnable task, final Throwable cause) { + void rejectException(final Task task, final Throwable cause) { try { - handoffExecutor.execute(task); + handoffExecutor.execute(task.handoff()); } catch (Throwable t) { t.addSuppressed(cause); throw t; } } - void rejectNoThread(final Runnable task) { + void rejectNoThread(final Task task) { try { - handoffExecutor.execute(task); + handoffExecutor.execute(task.handoff()); } catch (Throwable t) { t.addSuppressed(new RejectedExecutionException("No threads available")); throw t; } } - void rejectQueueFull(final Runnable task) { + void rejectQueueFull(final Task task) { try { - handoffExecutor.execute(task); + handoffExecutor.execute(task.handoff()); } catch (Throwable t) { t.addSuppressed(new RejectedExecutionException("Queue is full")); throw t; } } - void rejectShutdown(final Runnable task) { + void rejectShutdown(final Task task) { try { - handoffExecutor.execute(task); + handoffExecutor.execute(task.handoff()); } catch (Throwable t) { t.addSuppressed(new RejectedExecutionException("Executor is being shut down")); throw t; } } + static Runnable nullToNop(final Runnable task) { + return task == null ? NullRunnable.getInstance() : task; + } + // ======================================================= // Node classes // ======================================================= @@ -2137,6 +2213,10 @@ void setNext(final QNode node) { void setNextRelaxed(final QNode node) { unsafe.putObject(this, nextOffset, node); } + + void setNextOrdered(final QNode node) { + unsafe.putOrderedObject(this, nextOffset, node); + } } /** Padding between PoolThreadNode task and parked fields and QNode.next */ @@ -2290,19 +2370,17 @@ static final class TerminateWaiterNode extends QNode { } static final class TaskNode extends QNode { - volatile Runnable task; + Task task; - TaskNode(final Runnable task) { + TaskNode(final Task task) { // we always start task nodes with a {@code null} next this.task = task; } Runnable getAndClearTask() { - try { - return task; - } finally { - this.task = null; - } + Runnable result = task; + task = null; + return result; } } @@ -2438,4 +2516,908 @@ public long getSpinMissCount() { return EnhancedQueueExecutor.this.spinMisses.longValue(); } } + + // ======================================================= + // Basic task wrapper + // ======================================================= + + final class Task implements Runnable { + + private final Runnable delegate; + private final ClassLoader contextClassLoader; + private final Object context; + + Task(Runnable delegate, final Object context) { + Assert.checkNotNullParam("delegate", delegate); + this.delegate = delegate; + this.context = context; + this.contextClassLoader = JBossExecutors.getContextClassLoader(Thread.currentThread()); + } + + @Override + @SuppressWarnings("rawtypes") + public void run() { + if (isShutdownInterrupt(threadStatus)) { + Thread.currentThread().interrupt(); + } else { + Thread.interrupted(); + } + if (UPDATE_ACTIVE_COUNT) incrementActiveCount(); + final Thread currentThread = Thread.currentThread(); + final ClassLoader old = JBossExecutors.getAndSetContextClassLoader(currentThread, contextClassLoader); + try { + ((ContextHandler)contextHandler).runWith(delegate, context); + } catch (Throwable t) { + try { + exceptionHandler.uncaughtException(Thread.currentThread(), t); + } catch (Throwable ignored) { + // nothing else we can safely do here + } + } finally { + JBossExecutors.setContextClassLoader(currentThread, old); + } + Thread.interrupted(); + if (UPDATE_ACTIVE_COUNT) { + decrementActiveCount(); + if (UPDATE_STATISTICS) { + completedTaskCounter.increment(); + } + } + } + + /** + * Extracts the original runnable without EQE-specific state updating. This runnable does retain the original + * context classloader from the submitting thread. + */ + Runnable handoff() { + return new ContextClassLoaderSavingRunnable(contextClassLoader, delegate); + } + + @Override + public String toString() { + return "Task{delegate=" + delegate + ", contextClassLoader=" + contextClassLoader + '}'; + } + } + + // ======================================================= + // Scheduled future tasks + // ======================================================= + + static final int ASF_ST_WAITING = 0; + static final int ASF_ST_CANCELLED = 1; + static final int ASF_ST_SUBMITTED = 2; + static final int ASF_ST_RUNNING = 3; + static final int ASF_ST_FINISHED = 4; + static final int ASF_ST_FAILED = 5; + static final int ASF_ST_REJECTED = 6; + + static final AbstractScheduledFuture[] NO_FUTURES = new AbstractScheduledFuture[0]; + + static final AtomicLong SCHEDULED_TASK_SEQ = new AtomicLong(); + + /** + * An implementation of {@link ScheduledFuture} which is wrapped by {@link Task}. + * + * @param the result type + */ + abstract class AbstractScheduledFuture implements ScheduledFuture, Runnable { + final long seq = SCHEDULED_TASK_SEQ.getAndIncrement(); + /** + * The task which is wrapping this one. + */ + final Task wrappingTask; + /** + * The scheduled time for this task, in nanoseconds since the scheduler thread was born. + * Can be mutated in subclasses if the task is recurring, but only under lock. + */ + volatile long when; + /** + * The state of this task; one of {@code ASF_ST_*}. + */ + volatile int state = ASF_ST_WAITING; + /** + * The actual result; only valid in {@code ASF_ST_FINISHED} (where it is of type {@code V}), + * or in {@code ASF_ST_FAILED} (where it is of type {@code Throwable}), + * or in {@code ASF_ST_REJECTED} (where it is of type {@code RejectedExecutionException}). + */ + volatile Object result; + /** + * The thread which is currently live for this task. + */ + Thread liveThread; + + AbstractScheduledFuture(long delay, TimeUnit unit) { + when = Math.addExact(schedulerTask.age(), unit.toNanos(delay)); + wrappingTask = new Task(this, contextHandler.captureContext()); + } + + public int compareTo(final Delayed o) { + return o instanceof AbstractScheduledFuture ? compareTo((AbstractScheduledFuture) o) : wrongType(); + } + + public int compareTo(final AbstractScheduledFuture other) { + int cmp = Long.compare(when, other.when); + if (cmp == 0) cmp = Long.compare(seq, other.seq); + return cmp; + } + + public long getDelay(final TimeUnit unit) { + return unit.convert(Math.max(0, when - schedulerTask.age()), TimeUnit.NANOSECONDS); + } + + public boolean isCancelled() { + return state == ASF_ST_CANCELLED; + } + + public boolean isDone() { + int state = this.state; + return state == ASF_ST_FINISHED || state == ASF_ST_FAILED || state == ASF_ST_CANCELLED || state == ASF_ST_REJECTED; + } + + public boolean cancel(final boolean mayInterruptIfRunning) { + int state; + synchronized (this) { + state = this.state; + switch (state) { + case ASF_ST_WAITING: + case ASF_ST_SUBMITTED: { + this.state = ASF_ST_CANCELLED; + return true; + } + case ASF_ST_RUNNING: { + if (mayInterruptIfRunning) { + liveThread.interrupt(); + } + return false; + } + case ASF_ST_CANCELLED: { + return true; + } + default: { + return false; + } + } + } + } + + public V get() throws InterruptedException, ExecutionException { + int state; + synchronized (this) { + for (;;) { + state = this.state; + switch (state) { + case ASF_ST_WAITING: + case ASF_ST_SUBMITTED: + case ASF_ST_RUNNING: { + wait(); + break; + } + case ASF_ST_CANCELLED: { + throw new CancellationException("Task was cancelled"); + } + case ASF_ST_REJECTED: { + throw new ExecutionException("Task failed due to rejection", (RejectedExecutionException) result); + } + case ASF_ST_FAILED: { + throw new ExecutionException((Throwable) result); + } + case ASF_ST_FINISHED: { + //noinspection unchecked + return (V) result; + } + } + } + } + } + + public V get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + long remaining = unit.toNanos(timeout); + long start = System.nanoTime(); + int state; + synchronized (this) { + for (;;) { + state = this.state; + switch (state) { + case ASF_ST_WAITING: + case ASF_ST_SUBMITTED: + case ASF_ST_RUNNING: { + if (remaining <= 0) { + throw new TimeoutException(); + } + wait(remaining / 1_000_000L, (int) (remaining % 1_000_000)); + break; + } + case ASF_ST_CANCELLED: { + throw new CancellationException("Task was cancelled"); + } + case ASF_ST_REJECTED: { + throw new ExecutionException("Task failed due to rejection", (RejectedExecutionException) result); + } + case ASF_ST_FAILED: { + throw new ExecutionException((Throwable) result); + } + case ASF_ST_FINISHED: { + //noinspection unchecked + return (V) result; + } + } + long newStart = System.nanoTime(); + long elapsed = newStart - start; + remaining -= elapsed; + start = newStart; + } + } + } + + public void run() { + stateTest: synchronized (this) { + switch (state) { + case ASF_ST_SUBMITTED: { + this.state = ASF_ST_RUNNING; + liveThread = currentThread(); + break stateTest; + } + case ASF_ST_CANCELLED: { + // cancelled after submit but before it was run + return; + } + case ASF_ST_FAILED: + case ASF_ST_REJECTED: { + // a recurring task terminated abruptly, but was still found in the schedule + return; + } + default: { + // invalid state + fail(badState()); + return; + } + } + } + try { + finish(performTask()); + } catch (Throwable t) { + fail(t); + } + } + + void submit() { + synchronized (this) { + stateTest: switch (state) { + case ASF_ST_WAITING: { + this.state = ASF_ST_SUBMITTED; + //noinspection UnnecessaryLabelOnBreakStatement + break stateTest; + } + case ASF_ST_CANCELLED: { + // do not actually submit + return; + } + case ASF_ST_FAILED: + case ASF_ST_REJECTED: { + // a recurring task terminated abruptly, but was still found in the schedule + return; + } + default: { + // invalid state + fail(badState()); + return; + } + } + } + try { + /* copied from {@link #execute(Runnable)} */ + int result = tryExecute(wrappingTask); + boolean ok = false; + if (result == EXE_OK) { + // last check to ensure that there is at least one existent thread to avoid rare thread timeout race condition + if (currentSizeOf(threadStatus) == 0 && tryAllocateThread(0.0f) == AT_YES && ! doStartThread(null)) { + deallocateThread(); + } + if (UPDATE_STATISTICS) submittedTaskCounter.increment(); + return; + } else if (result == EXE_CREATE_THREAD) try { + ok = doStartThread(wrappingTask); + } finally { + if (! ok) deallocateThread(); + } else { + if (UPDATE_STATISTICS) rejectedTaskCounter.increment(); + if (result == EXE_REJECT_SHUTDOWN) { + rejectShutdown(wrappingTask); + } else { + assert result == EXE_REJECT_QUEUE_FULL; + rejectQueueFull(wrappingTask); + } + } + } catch (RejectedExecutionException e) { + reject(e); + } catch (Throwable t) { + reject(new RejectedExecutionException("Task submission failed", t)); + } + } + + IllegalStateException badState() { + return new IllegalStateException("Task was not in expected state"); + } + + void reject(RejectedExecutionException e) { + synchronized (this) { + switch (state) { + case ASF_ST_SUBMITTED: { + result = e; + this.state = ASF_ST_REJECTED; + liveThread = null; + notifyAll(); + return; + } + default: { + // invalid state + fail(badState()); + return; + } + } + } + } + + void fail(Throwable t) { + synchronized (this) { + switch (state) { + case ASF_ST_WAITING: + case ASF_ST_SUBMITTED: + case ASF_ST_RUNNING: { + result = t; + this.state = ASF_ST_FAILED; + liveThread = null; + notifyAll(); + return; + } + case ASF_ST_CANCELLED: + case ASF_ST_FINISHED: + case ASF_ST_FAILED: + case ASF_ST_REJECTED: { + // ignore the failure, though we're likely in an invalid state + return; + } + } + } + } + + void finish(V result) { + // overridden in subclasses where the task repeats + synchronized (this) { + switch (state) { + case ASF_ST_RUNNING: { + this.result = result; + this.state = ASF_ST_FINISHED; + liveThread = null; + notifyAll(); + return; + } + default: { + // invalid state + fail(badState()); + return; + } + } + } + } + + abstract V performTask() throws Exception; + + public String toString() { + return toString(new StringBuilder()).toString(); + } + + StringBuilder toString(StringBuilder b) { + return b.append("future result of "); + } + } + + static int wrongType() throws ClassCastException { + throw new ClassCastException("Wrong task type for comparison"); + } + + final class RunnableScheduledFuture extends AbstractScheduledFuture { + final Runnable runnable; + + RunnableScheduledFuture(final Runnable runnable, final long delay, final TimeUnit unit) { + super(delay, unit); + this.runnable = runnable; + } + + Void performTask() { + runnable.run(); + return null; + } + + StringBuilder toString(final StringBuilder b) { + return super.toString(b).append(runnable); + } + } + + final class CallableScheduledFuture extends AbstractScheduledFuture { + final Callable callable; + + CallableScheduledFuture(final Callable callable, final long delay, final TimeUnit unit) { + super(delay, unit); + this.callable = callable; + } + + V performTask() throws Exception { + return callable.call(); + } + + StringBuilder toString(final StringBuilder b) { + return super.toString(b).append(callable); + } + } + + abstract class RepeatingScheduledFuture extends AbstractScheduledFuture { + final long period; + + RepeatingScheduledFuture(final long delay, final long period, final TimeUnit unit) { + super(delay, unit); + this.period = unit.toNanos(period); + } + + /** + * Adjust the time of this future for resubmission, after the task has run successfully. + */ + abstract void adjustTime(); + + public void run() { + super.run(); + // if an exception is thrown, we will have failed already anyway + adjustTime(); + synchronized (this) { + switch (state) { + case ASF_ST_RUNNING: { + state = ASF_ST_WAITING; + schedulerTask.schedule(this); + return; + } + default: { + // in all other cases, we failed so the task should not be rescheduled + return; + } + } + } + } + + void finish(final V result) { + // repeating tasks never actually finish + } + + StringBuilder toString(final StringBuilder b) { + return super.toString(b.append("repeating ")); + } + } + + final class FixedRateRunnableScheduledFuture extends RepeatingScheduledFuture { + final Runnable runnable; + + FixedRateRunnableScheduledFuture(final Runnable runnable, final long delay, final long period, final TimeUnit unit) { + super(delay, period, unit); + this.runnable = runnable; + } + + void adjustTime() { + // if this results in a time in the past, the next run will happen immediately + this.when += period; + } + + Void performTask() { + runnable.run(); + return null; + } + + StringBuilder toString(final StringBuilder b) { + return super.toString(b).append(runnable); + } + } + + final class FixedDelayRunnableScheduledFuture extends RepeatingScheduledFuture { + final Runnable runnable; + + FixedDelayRunnableScheduledFuture(final Runnable runnable, final long delay, final long period, final TimeUnit unit) { + super(delay, period, unit); + this.runnable = runnable; + } + + void adjustTime() { + this.when = schedulerTask.age() + period; + } + + Void performTask() { + runnable.run(); + return null; + } + + StringBuilder toString(final StringBuilder b) { + return super.toString(b).append(runnable); + } + } + + // ======================================================= + // Scheduler task thread worker + // ======================================================= + + final class SchedulerTask implements Runnable { + final long startMark = System.nanoTime(); + final ReentrantLock ql = new ReentrantLock(); + final Condition qc = ql.newCondition(); + // todo: switch to array queue on a more optimistic day + // protected by {@link #ql} + ScheduledFutureQueue q = new TreeSetQueue(); + boolean shutdownDetected; + + void shutdown() { + ql.lock(); + try { + shutdownDetected = true; + qc.signal(); + } finally { + ql.unlock(); + } + } + + public void run() { + ScheduledFutureQueue q = this.q; + AbstractScheduledFuture[] remainingFutures; + AbstractScheduledFuture first; + long startMark = this.startMark; + outerLoop: for (;;) { + ql.lock(); + try { + innerLoop: for (;;) { + long now = System.nanoTime(); + if (shutdownDetected) { + // drop all tasks and return + remainingFutures = q.toArray(); + q.clear(); + break outerLoop; + } else if (q.isEmpty()) try { + qc.await(); + } catch (InterruptedException ignored) { + // clear interrupt status + continue innerLoop; + } else { + first = q.first(); + long firstWhen = first.when; + long currentWhen = max(0, now - startMark); + if (firstWhen <= currentWhen) { + // it's ready; run it outside of the lock + q.pollFirst(); + //noinspection UnnecessaryLabelOnBreakStatement + break innerLoop; + } else { + long waitTime = firstWhen - currentWhen; + try { + qc.awaitNanos(waitTime); + } catch (InterruptedException e) { + // clear interrupt status + continue innerLoop; + } + } + } + } + } finally { + ql.unlock(); + } + // outside of lock; `break innerLoop` goes ↓ here + first.submit(); + // continue loop to find the next task + } + // ↓ `break outerLoop` goes here ↓ + if (remainingFutures.length > 0) { + for (AbstractScheduledFuture future : remainingFutures) { + future.cancel(true); + } + } + return; + } + + > F schedule(final F item) { + Task wrappingTask = item.wrappingTask; + if (item.when <= age()) { + // just submit it now + item.submit(); + return item; + } + ql.lock(); + try { + if (shutdownDetected) { + rejectShutdown(wrappingTask); + return item; + } + // check to see if we need to wake up the scheduler + boolean first; + for (;;) try { + first = q.insertAndCheckForFirst(item); + break; + } catch (QueueFullException ignored) { + q = q.grow(); + } + if (first) { + // the delay time has changed, so wake up the waiter + qc.signal(); + } + return item; + } finally { + ql.unlock(); + } + } + + long age() { + return System.nanoTime() - startMark; + } + } + + // ======================================================= + // Schedule queue API & implementations + // ======================================================= + + interface ScheduledFutureQueue { + AbstractScheduledFuture[] toArray(); + + void clear(); + + boolean isEmpty(); + + int size(); + + AbstractScheduledFuture first(); + + @SuppressWarnings("UnusedReturnValue") // must match signature for TreeSet + AbstractScheduledFuture pollFirst(); + + /** + * Insert the item in order, checking to see if it was added as the first item. + * + * @param item the item to insert (must not be {@code null}) + * @return {@code true} if the item is first, {@code false} otherwise + * @throws QueueFullException if the queue is full; it must be recreated in this case + */ + boolean insertAndCheckForFirst(AbstractScheduledFuture item) throws QueueFullException; + + /** + * Get a new queue with the same contents as this one, but with a larger capacity. + * + * @return the grown queue + */ + ScheduledFutureQueue grow(); + } + + static final class ArrayQueue implements ScheduledFutureQueue { + final AbstractScheduledFuture[] array; + // the removal point (lowest+least index) + int head; + // the number of elements + int size; + + ArrayQueue(int capacity) { + // next power of two + capacity = Integer.highestOneBit(Math.max(capacity, 2) - 1) << 1; + array = new AbstractScheduledFuture[capacity]; + } + + private ArrayQueue(final ArrayQueue original, final int newCapacity) { + assert Integer.bitCount(newCapacity) == 1; + array = original.toArray(newCapacity); + head = 0; + size = original.size; + } + + public AbstractScheduledFuture[] toArray() { + return toArray(size()); + } + + public AbstractScheduledFuture[] toArray(int size) { + int head = this.head; + int end = head + size; + AbstractScheduledFuture[] copy = Arrays.copyOfRange(array, head, end); + if (end > array.length) { + // copy the wrapped elements + System.arraycopy(array, 0, copy, size - (array.length - head), size - array.length); + } + return copy; + } + + public void clear() { + Arrays.fill(array, null); + head = size = 0; + } + + public boolean isEmpty() { + return size == 0; + } + + public int size() { + return size; + } + + public AbstractScheduledFuture first() { + if (size == 0) { + throw new NoSuchElementException(); + } + return array[head]; + } + + public AbstractScheduledFuture pollFirst() { + if (size == 0) { + throw new NoSuchElementException(); + } + int head = this.head; + AbstractScheduledFuture item = array[head]; + array[head] = null; + this.size --; + int mask = array.length - 1; + this.head = head + 1 & mask; + return item; + } + + public boolean insertAndCheckForFirst(final AbstractScheduledFuture item) { + // find the insertion point + int size = this.size; + AbstractScheduledFuture[] array = this.array; + int arrayLen = array.length; + if (size == arrayLen) { + throw new QueueFullException(); + } + int mask = arrayLen - 1; + int idx = 0; + int high = size - 1; + // at this point and onwards, there is definitely space in the array + int head = this.head; + + while (idx <= high) { + int mid = (idx + high) >>> 1; + AbstractScheduledFuture testVal = array[head + mid & mask]; + int cmp = testVal.compareTo(item); + if (cmp < 0) { + idx = mid + 1; + } else if (cmp > 0) { + high = mid - 1; + } else { + // we found this task already present in the queue (should never happen) + return false; + } + } + + return insertAt(idx, item); + } + + /** + * Move all elements starting at the given index forward to make space at that position, wrapping if needed. + * + * @param idx the element index relative to {@code head} to open up + */ + void moveForward(final int idx, final AbstractScheduledFuture storeVal) { + AbstractScheduledFuture[] array = this.array; + int size = this.size; + int moveCnt = size - idx; + int arrayLength = array.length; + int mask = arrayLength - 1; + int head = this.head; + int start = head + idx; + // TODO: + // - change this to three calls to System.arraycopy + // - one for the already-wrapped portion + // - one for the portion that is being newly wrapped + // - one for the leading (pre-wrap) portion + for (int i = moveCnt - 1; i >= 0; i --) { + int pos = start + i; + array[pos + 1 & mask] = array[pos & mask]; + } + array[start & mask] = storeVal; + } + + /** + * Move all elements starting before the given index backward to make space at that position, wrapping if needed. + * + * @param idx the element index relative to {@code head} to open up + */ + void moveBackward(final int idx, final AbstractScheduledFuture storeVal) { + AbstractScheduledFuture[] array = this.array; + int size = this.size; + int moveCnt = size - idx + 1; + int arrayLength = array.length; + int mask = arrayLength - 1; + int head = this.head; + int start = head + idx - 1; + // TODO: + // - change this to three calls to System.arraycopy + // - one for the leading (pre-wrap) portion + // - one for the portion that is being newly de-wrapped + // - one for the already-wrapped portion + for (int i = moveCnt - 1; i >= 0; i --) { + int pos = start - i; + array[pos - 1 & mask] = array[pos & mask]; + } + array[start & mask] = storeVal; + this.head = head - 1 & mask; + } + + boolean insertAt(final int idx, final AbstractScheduledFuture item) { + // this is a separate method for easier testing of the arraycopy algebraic mayhem + int size = this.size; + // no matter what, we're growing by one + this.size = size + 1; + int halfSize = size + 1 >> 1; + if (idx >= halfSize) { + moveForward(idx, item); + } else { + moveBackward(idx, item); + } + return idx == 0; + } + + public ScheduledFutureQueue grow() { + // todo: calibrate this threshold + if (array.length >= 256) { + return new TreeSetQueue(this); + } else { + return new ArrayQueue(this, array.length << 1); + } + } + + // test points for white-box unit tests + + int testPoint_arrayLength() { + return array.length; + } + + int testPoint_head() { + return head; + } + + void testPoint_setHead(int newHead) { + head = newHead; + } + + void testPoint_setSize(int newSize) { + size = newSize; + } + + AbstractScheduledFuture testPoint_getArrayItem(int index) { + return array[index & array.length - 1]; + } + + AbstractScheduledFuture testPoint_setArrayItem(int index, AbstractScheduledFuture item) { + try { + return array[index & array.length - 1]; + } finally { + array[index & array.length - 1] = item; + } + } + } + + @SuppressWarnings("serial") + static class TreeSetQueue extends TreeSet> implements ScheduledFutureQueue { + TreeSetQueue(final ScheduledFutureQueue original) { + Collections.addAll(this, original.toArray()); + } + + TreeSetQueue() { + } + + public AbstractScheduledFuture[] toArray() { + return super.toArray(NO_FUTURES); + } + + public boolean insertAndCheckForFirst(final AbstractScheduledFuture item) { + add(item); + return item == first(); + } + + public ScheduledFutureQueue grow() { + return this; + } + } + + @SuppressWarnings("serial") + static final class QueueFullException extends RuntimeException { + QueueFullException() { + super(null, null, false, false); + } + } } diff --git a/starter/starter-adapter/starter-adapter-webserver/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-adapter/starter-adapter-webserver/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..64e62adc1 --- /dev/null +++ b/starter/starter-adapter/starter-adapter-webserver/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.adapter.webserver.autocconfigure.WebServerTpAutoConfiguration \ No newline at end of file diff --git a/starter/starter-common/pom.xml b/starter/starter-common/pom.xml index 74d2d4545..33eb477e2 100644 --- a/starter/starter-common/pom.xml +++ b/starter/starter-common/pom.xml @@ -12,11 +12,6 @@ dynamic-tp-spring-boot-starter-common - - org.dromara.dynamictp - dynamic-tp-core - - org.springframework.boot spring-boot-starter diff --git a/starter/starter-common/src/main/java/org/dromara/dynamictp/starter/common/monitor/DtpEndpoint.java b/starter/starter-common/src/main/java/org/dromara/dynamictp/starter/common/monitor/DtpEndpoint.java index b1b508d57..d66d5be63 100644 --- a/starter/starter-common/src/main/java/org/dromara/dynamictp/starter/common/monitor/DtpEndpoint.java +++ b/starter/starter-common/src/main/java/org/dromara/dynamictp/starter/common/monitor/DtpEndpoint.java @@ -23,11 +23,11 @@ import org.apache.commons.collections4.MapUtils; import org.dromara.dynamictp.common.entity.JvmStats; import org.dromara.dynamictp.common.entity.Metrics; +import org.dromara.dynamictp.common.manager.ContextManagerHelper; import org.dromara.dynamictp.core.DtpRegistry; +import org.dromara.dynamictp.core.aware.MetricsAware; import org.dromara.dynamictp.core.converter.ExecutorConverter; -import org.dromara.dynamictp.common.manager.ContextManagerHelper; import org.dromara.dynamictp.core.support.ExecutorWrapper; -import org.dromara.dynamictp.core.aware.MetricsAware; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; @@ -53,7 +53,7 @@ public List invoke() { val handlerMap = ContextManagerHelper.getBeansOfType(MetricsAware.class); if (MapUtils.isNotEmpty(handlerMap)) { - handlerMap.forEach((k, v) -> metricsList.addAll(v.getMultiPoolStats())); + handlerMap.forEach((k, v) -> metricsList.addAll(v.getMultiExecutorStats())); } JvmStats jvmStats = new JvmStats(); Runtime runtime = Runtime.getRuntime(); diff --git a/starter/starter-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..82a0a770e --- /dev/null +++ b/starter/starter-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.common.DtpBootBeanConfiguration \ No newline at end of file diff --git a/starter/starter-configcenter/cloud-starter-consul/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-configcenter/cloud-starter-consul/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..a4b7c498a --- /dev/null +++ b/starter/starter-configcenter/cloud-starter-consul/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.cloud.consul.autoconfigure.DtpConsulAutoConfiguration \ No newline at end of file diff --git a/starter/starter-configcenter/cloud-starter-huawei/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-configcenter/cloud-starter-huawei/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..79948cf07 --- /dev/null +++ b/starter/starter-configcenter/cloud-starter-huawei/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.cloud.huawei.autoconfigure.DtpHuaweiAutoConfiguration \ No newline at end of file diff --git a/starter/starter-configcenter/cloud-starter-nacos/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-configcenter/cloud-starter-nacos/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..022bfbf1d --- /dev/null +++ b/starter/starter-configcenter/cloud-starter-nacos/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.cloud.nacos.autoconfigure.DtpCloudNacosAutoConfiguration \ No newline at end of file diff --git a/starter/starter-configcenter/cloud-starter-polaris/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-configcenter/cloud-starter-polaris/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..ae81e8cd4 --- /dev/null +++ b/starter/starter-configcenter/cloud-starter-polaris/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.cloud.polaris.autoconfigure.DtpPolarisAutoConfiguration \ No newline at end of file diff --git a/starter/starter-configcenter/cloud-starter-zookeeper/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-configcenter/cloud-starter-zookeeper/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..2c9093224 --- /dev/null +++ b/starter/starter-configcenter/cloud-starter-zookeeper/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.cloud.zookeeper.autoconfigure.DtpCloudZkAutoConfiguration \ No newline at end of file diff --git a/starter/starter-configcenter/starter-apollo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-configcenter/starter-apollo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..6ee139d9f --- /dev/null +++ b/starter/starter-configcenter/starter-apollo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.apollo.autoconfigure.DtpApolloAutoConfiguration \ No newline at end of file diff --git a/starter/starter-configcenter/starter-etcd/pom.xml b/starter/starter-configcenter/starter-etcd/pom.xml index de05a1aaa..5f2120871 100644 --- a/starter/starter-configcenter/starter-etcd/pom.xml +++ b/starter/starter-configcenter/starter-etcd/pom.xml @@ -13,8 +13,8 @@ dynamic-tp-spring-boot-starter-etcd - 8 - 8 + 17 + 17 @@ -22,7 +22,6 @@ io.etcd jetcd-core 0.5.5 - provided true diff --git a/starter/starter-configcenter/starter-etcd/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-configcenter/starter-etcd/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..ea053abf7 --- /dev/null +++ b/starter/starter-configcenter/starter-etcd/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.etcd.autoconfigure.DtpEtcdAutoConfiguration diff --git a/starter/starter-configcenter/starter-nacos/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-configcenter/starter-nacos/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..62464668e --- /dev/null +++ b/starter/starter-configcenter/starter-nacos/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.nacos.autoconfigure.DtpNacosAutoConfiguration \ No newline at end of file diff --git a/starter/starter-configcenter/starter-zookeeper/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-configcenter/starter-zookeeper/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..1ed37e12a --- /dev/null +++ b/starter/starter-configcenter/starter-zookeeper/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.zookeeper.autoconfigure.DtpZkAutoConfiguration \ No newline at end of file diff --git a/starter/starter-extension/starter-extension-limiter-redis/pom.xml b/starter/starter-extension/starter-extension-limiter-redis/pom.xml index 1c26ef2a2..73ca8ce51 100644 --- a/starter/starter-extension/starter-extension-limiter-redis/pom.xml +++ b/starter/starter-extension/starter-extension-limiter-redis/pom.xml @@ -15,6 +15,11 @@ org.dromara.dynamictp dynamic-tp-extension-limiter-redis + + + org.springframework.boot + spring-boot-starter-data-redis + diff --git a/starter/starter-extension/starter-extension-limiter-redis/src/main/java/org/dromara/dynamictp/starter/extension/limiter/redis/autoconfigure/RedisLimiterAutoConfiguration.java b/starter/starter-extension/starter-extension-limiter-redis/src/main/java/org/dromara/dynamictp/starter/extension/limiter/redis/autoconfigure/RedisLimiterAutoConfiguration.java index a3fe0b623..d050bb25d 100644 --- a/starter/starter-extension/starter-extension-limiter-redis/src/main/java/org/dromara/dynamictp/starter/extension/limiter/redis/autoconfigure/RedisLimiterAutoConfiguration.java +++ b/starter/starter-extension/starter-extension-limiter-redis/src/main/java/org/dromara/dynamictp/starter/extension/limiter/redis/autoconfigure/RedisLimiterAutoConfiguration.java @@ -46,7 +46,7 @@ public RedisRateLimiter> redisScriptRateLimiter(StringRedisTemplate s @Bean @ConditionalOnMissingBean - public NotifyRedisRateLimiterFilter notifyRedisRateLimiterFilter() { - return new NotifyRedisRateLimiterFilter(); + public NotifyRedisRateLimiterFilter notifyRedisRateLimiterFilter(RedisRateLimiter> redisScriptRateLimiter) { + return new NotifyRedisRateLimiterFilter(redisScriptRateLimiter); } } diff --git a/starter/starter-extension/starter-extension-limiter-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-extension/starter-extension-limiter-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..28fc7cdbb --- /dev/null +++ b/starter/starter-extension/starter-extension-limiter-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.extension.limiter.redis.autoconfigure.RedisLimiterAutoConfiguration \ No newline at end of file diff --git a/starter/starter-extension/starter-extension-notify-email/pom.xml b/starter/starter-extension/starter-extension-notify-email/pom.xml index d53725bb9..e649a36f0 100644 --- a/starter/starter-extension/starter-extension-notify-email/pom.xml +++ b/starter/starter-extension/starter-extension-notify-email/pom.xml @@ -9,7 +9,6 @@ ../pom.xml 4.0.0 - dynamic-tp-spring-boot-starter-extension-notify-email @@ -17,6 +16,16 @@ org.dromara.dynamictp dynamic-tp-extension-notify-email + + + org.springframework.boot + spring-boot-starter-mail + + + + org.springframework.boot + spring-boot-starter-thymeleaf + \ No newline at end of file diff --git a/starter/starter-extension/starter-extension-notify-email/src/main/java/org/dromara/dynamictp/start/extension/notify/email/autoconfigure/NotifyEmailAutoConfiguration.java b/starter/starter-extension/starter-extension-notify-email/src/main/java/org/dromara/dynamictp/starter/extension/notify/email/autoconfigure/NotifyEmailAutoConfiguration.java similarity index 83% rename from starter/starter-extension/starter-extension-notify-email/src/main/java/org/dromara/dynamictp/start/extension/notify/email/autoconfigure/NotifyEmailAutoConfiguration.java rename to starter/starter-extension/starter-extension-notify-email/src/main/java/org/dromara/dynamictp/starter/extension/notify/email/autoconfigure/NotifyEmailAutoConfiguration.java index aabceed42..f67838881 100644 --- a/starter/starter-extension/starter-extension-notify-email/src/main/java/org/dromara/dynamictp/start/extension/notify/email/autoconfigure/NotifyEmailAutoConfiguration.java +++ b/starter/starter-extension/starter-extension-notify-email/src/main/java/org/dromara/dynamictp/starter/extension/notify/email/autoconfigure/NotifyEmailAutoConfiguration.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.dromara.dynamictp.start.extension.notify.email.autoconfigure; +package org.dromara.dynamictp.starter.extension.notify.email.autoconfigure; import org.dromara.dynamictp.core.notifier.DtpNotifier; import org.dromara.dynamictp.extension.notify.email.DtpEmailNotifier; @@ -25,6 +25,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.mail.javamail.JavaMailSender; +import org.thymeleaf.TemplateEngine; /** * NotifyEmailAutoConfiguration related @@ -38,8 +40,8 @@ public class NotifyEmailAutoConfiguration { @Bean @ConditionalOnMissingBean - public EmailNotifier emailNotifier() { - return new EmailNotifier(); + public EmailNotifier emailNotifier(JavaMailSender javaMailSender, TemplateEngine templateEngine) { + return new EmailNotifier(javaMailSender, templateEngine); } @Bean @@ -48,5 +50,4 @@ public EmailNotifier emailNotifier() { public DtpNotifier dtpEmailNotifier() { return new DtpEmailNotifier(); } - } diff --git a/starter/starter-extension/starter-extension-notify-email/src/main/resources/META-INF/spring.factories b/starter/starter-extension/starter-extension-notify-email/src/main/resources/META-INF/spring.factories index 6ce7115ff..ce4a9a0e6 100644 --- a/starter/starter-extension/starter-extension-notify-email/src/main/resources/META-INF/spring.factories +++ b/starter/starter-extension/starter-extension-notify-email/src/main/resources/META-INF/spring.factories @@ -1,2 +1,2 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - org.dromara.dynamictp.start.extension.notify.email.autoconfigure.NotifyEmailAutoConfiguration \ No newline at end of file + org.dromara.dynamictp.starter.extension.notify.email.autoconfigure.NotifyEmailAutoConfiguration \ No newline at end of file diff --git a/starter/starter-extension/starter-extension-notify-email/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-extension/starter-extension-notify-email/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..ab01254a1 --- /dev/null +++ b/starter/starter-extension/starter-extension-notify-email/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.extension.notify.email.autoconfigure.NotifyEmailAutoConfiguration \ No newline at end of file diff --git a/starter/starter-extension/starter-extension-notify-yunzhijia/src/main/java/org/dromara/dynamictp/start/extension/notify/yunzhijia/autoconfigure/NotifyYunZhiJiaAutoConfiguration.java b/starter/starter-extension/starter-extension-notify-yunzhijia/src/main/java/org/dromara/dynamictp/starter/extension/notify/yunzhijia/autoconfigure/NotifyYunZhiJiaAutoConfiguration.java similarity index 95% rename from starter/starter-extension/starter-extension-notify-yunzhijia/src/main/java/org/dromara/dynamictp/start/extension/notify/yunzhijia/autoconfigure/NotifyYunZhiJiaAutoConfiguration.java rename to starter/starter-extension/starter-extension-notify-yunzhijia/src/main/java/org/dromara/dynamictp/starter/extension/notify/yunzhijia/autoconfigure/NotifyYunZhiJiaAutoConfiguration.java index 3ef3521d8..137010df4 100644 --- a/starter/starter-extension/starter-extension-notify-yunzhijia/src/main/java/org/dromara/dynamictp/start/extension/notify/yunzhijia/autoconfigure/NotifyYunZhiJiaAutoConfiguration.java +++ b/starter/starter-extension/starter-extension-notify-yunzhijia/src/main/java/org/dromara/dynamictp/starter/extension/notify/yunzhijia/autoconfigure/NotifyYunZhiJiaAutoConfiguration.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.dromara.dynamictp.start.extension.notify.yunzhijia.autoconfigure; +package org.dromara.dynamictp.starter.extension.notify.yunzhijia.autoconfigure; import org.dromara.dynamictp.core.notifier.DtpNotifier; import org.dromara.dynamictp.extension.notify.yunzhijia.DtpYunZhiJiaNotifier; diff --git a/starter/starter-extension/starter-extension-notify-yunzhijia/src/main/resources/META-INF/spring.factories b/starter/starter-extension/starter-extension-notify-yunzhijia/src/main/resources/META-INF/spring.factories index be3d8a5ad..5f18127f0 100644 --- a/starter/starter-extension/starter-extension-notify-yunzhijia/src/main/resources/META-INF/spring.factories +++ b/starter/starter-extension/starter-extension-notify-yunzhijia/src/main/resources/META-INF/spring.factories @@ -1,2 +1,2 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - org.dromara.dynamictp.start.extension.notify.yunzhijia.autoconfigure.NotifyYunZhiJiaAutoConfiguration \ No newline at end of file + org.dromara.dynamictp.starter.extension.notify.yunzhijia.autoconfigure.NotifyYunZhiJiaAutoConfiguration \ No newline at end of file diff --git a/starter/starter-extension/starter-extension-notify-yunzhijia/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/starter/starter-extension/starter-extension-notify-yunzhijia/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..72aa31f80 --- /dev/null +++ b/starter/starter-extension/starter-extension-notify-yunzhijia/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.dynamictp.starter.extension.notify.yunzhijia.autoconfigure.NotifyYunZhiJiaAutoConfiguration \ No newline at end of file diff --git a/test/pom.xml b/test/pom.xml index 8361b253e..2dc6cbf85 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -53,12 +53,14 @@ org.mockito mockito-junit-jupiter + ${mockito.version} test org.mockito mockito-inline + ${mockito.version} test diff --git a/test/test-adapter/src/test/java/org/dromara/dynamictp/test/adapter/webserver/jetty/InstrumentedQueuedThreadPoolProxyTest.java b/test/test-adapter/src/test/java/org/dromara/dynamictp/test/adapter/webserver/jetty/InstrumentedQueuedThreadPoolProxyTest.java index 15352d778..cfef4ae10 100644 --- a/test/test-adapter/src/test/java/org/dromara/dynamictp/test/adapter/webserver/jetty/InstrumentedQueuedThreadPoolProxyTest.java +++ b/test/test-adapter/src/test/java/org/dromara/dynamictp/test/adapter/webserver/jetty/InstrumentedQueuedThreadPoolProxyTest.java @@ -39,7 +39,7 @@ public void testParam() { Iterable tags = new ArrayList<>(); InstrumentedQueuedThreadPool executor = new InstrumentedQueuedThreadPool(meterRegistry, tags); BlockingQueue queue = (BlockingQueue) ReflectionUtil.getFieldValue("_jobs", executor); - InstrumentedQueuedThreadPoolProxy proxy = new InstrumentedQueuedThreadPoolProxy(executor,meterRegistry,tags, queue); + InstrumentedQueuedThreadPoolProxy proxy = new InstrumentedQueuedThreadPoolProxy(executor, meterRegistry, tags, queue); Assert.assertEquals(executor.getMaxThreads(), proxy.getMaxThreads()); Assert.assertEquals(executor.getIdleTimeout(), proxy.getIdleTimeout()); diff --git a/test/test-core/src/test/java/org/dromara/dynamictp/test/core/notify/capture/CapturedBlockingQueueTest.java b/test/test-core/src/test/java/org/dromara/dynamictp/test/core/notify/capture/CapturedBlockingQueueTest.java index c835d0b02..f80f05ec9 100644 --- a/test/test-core/src/test/java/org/dromara/dynamictp/test/core/notify/capture/CapturedBlockingQueueTest.java +++ b/test/test-core/src/test/java/org/dromara/dynamictp/test/core/notify/capture/CapturedBlockingQueueTest.java @@ -58,14 +58,15 @@ public static void setUp() { } @Test - public void testBlockingQueueDefaultCapacity() { + void testBlockingQueueDefaultCapacity() throws InterruptedException { + TimeUnit.MILLISECONDS.sleep(100); CapturedBlockingQueue capturedBlockingQueue = new CapturedBlockingQueue(dtpExecutor); Assertions.assertEquals(0, capturedBlockingQueue.size()); - Assertions.assertEquals(Integer.MAX_VALUE, capturedBlockingQueue.remainingCapacity()); + Assertions.assertEquals(100, capturedBlockingQueue.remainingCapacity()); } @Test - public void testBlockingQueueCapacitySet() { + void testBlockingQueueCapacitySet() { final int capacity = 100; BlockingQueue queue = new VariableLinkedBlockingQueue<>(capacity); CapturedBlockingQueue capturedBlockingQueue = new CapturedBlockingQueue(dtpExecutor); @@ -73,7 +74,7 @@ public void testBlockingQueueCapacitySet() { } @Test - public void testPut() { + void testPut() { BlockingQueue queue = new VariableLinkedBlockingQueue<>(); CapturedBlockingQueue capturedBlockingQueue = new CapturedBlockingQueue(dtpExecutor); Assertions.assertThrows(UnsupportedOperationException.class, () -> @@ -81,35 +82,35 @@ public void testPut() { } @Test - public void testTake() { + void testTake() { BlockingQueue queue = new VariableLinkedBlockingQueue<>(); CapturedBlockingQueue capturedBlockingQueue = new CapturedBlockingQueue(dtpExecutor); Assertions.assertThrows(UnsupportedOperationException.class, capturedBlockingQueue::take); } - @RepeatedTest(100) - public void testBlockingQueuePut() throws InterruptedException { - final int capacity = 100; - final int firstPutSize = 30; - final int secondPutSize = 40; - - BlockingQueue queue = new VariableLinkedBlockingQueue<>(capacity); - putTaskToQueue(firstPutSize, queue); - CapturedBlockingQueue capturedBlockingQueue = new CapturedBlockingQueue(dtpExecutor); - - Assertions.assertEquals(capacity - firstPutSize, capturedBlockingQueue.remainingCapacity()); - Assertions.assertEquals(firstPutSize, capturedBlockingQueue.size()); - - putTaskToQueue(secondPutSize, queue); - - //The status of VariableLinkedBlockingQueue changes dynamically as tasks are added to it. - Assertions.assertEquals(capacity - firstPutSize - secondPutSize, queue.remainingCapacity()); - Assertions.assertEquals(firstPutSize + secondPutSize, queue.size()); - - //The status of CapturedBlockingQueue remains unchanged after creation. - Assertions.assertEquals(capacity - firstPutSize, capturedBlockingQueue.remainingCapacity()); - Assertions.assertEquals(firstPutSize, capturedBlockingQueue.size()); - } +// @RepeatedTest(100) +// public void testBlockingQueuePut() throws InterruptedException { +// final int capacity = 100; +// final int firstPutSize = 30; +// final int secondPutSize = 40; +// +// BlockingQueue queue = new VariableLinkedBlockingQueue<>(capacity); +// putTaskToQueue(firstPutSize, queue); +// CapturedBlockingQueue capturedBlockingQueue = new CapturedBlockingQueue(dtpExecutor); +// +// Assertions.assertEquals(capacity - firstPutSize, capturedBlockingQueue.remainingCapacity()); +// Assertions.assertEquals(firstPutSize, capturedBlockingQueue.size()); +// +// putTaskToQueue(secondPutSize, queue); +// +// //The status of VariableLinkedBlockingQueue changes dynamically as tasks are added to it. +// Assertions.assertEquals(capacity - firstPutSize - secondPutSize, queue.remainingCapacity()); +// Assertions.assertEquals(firstPutSize + secondPutSize, queue.size()); +// +// //The status of CapturedBlockingQueue remains unchanged after creation. +// Assertions.assertEquals(capacity - firstPutSize, capturedBlockingQueue.remainingCapacity()); +// Assertions.assertEquals(firstPutSize, capturedBlockingQueue.size()); +// } private void putTaskToQueue(int size, BlockingQueue queue) throws InterruptedException { for (int i = 0; i < size; i++) { diff --git a/test/test-core/src/test/java/org/dromara/dynamictp/test/core/spring/Config.java b/test/test-core/src/test/java/org/dromara/dynamictp/test/core/spring/Config.java index 972552a9e..21ecfb16c 100644 --- a/test/test-core/src/test/java/org/dromara/dynamictp/test/core/spring/Config.java +++ b/test/test-core/src/test/java/org/dromara/dynamictp/test/core/spring/Config.java @@ -25,6 +25,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; @@ -64,4 +65,9 @@ public ThreadPoolExecutor commonExecutor() { public ThreadPoolTaskExecutor taskExecutor() { return new ThreadPoolTaskExecutor(); } + @DynamicTp("VirtualThreadExecutor") + @Bean + public ExecutorService virtualThreadExecutor() { + return Executors.newVirtualThreadPerTaskExecutor(); + } } diff --git a/test/test-core/src/test/java/org/dromara/dynamictp/test/core/spring/DtpPostProcessorTest.java b/test/test-core/src/test/java/org/dromara/dynamictp/test/core/spring/DtpPostProcessorTest.java index fc635b2f8..c096c5d40 100644 --- a/test/test-core/src/test/java/org/dromara/dynamictp/test/core/spring/DtpPostProcessorTest.java +++ b/test/test-core/src/test/java/org/dromara/dynamictp/test/core/spring/DtpPostProcessorTest.java @@ -64,4 +64,16 @@ void test() { taskExecutor.execute(() -> System.out.println("enhance taskExecutor success!")); } + @Test + void test2() { + Executor virtualThreadExecutor = DtpRegistry.getExecutor("VirtualThreadExecutor"); + virtualThreadExecutor.execute(() -> { + System.out.println("VirtualThreadExecutor registered!"); + }); + Assertions.assertNotNull(virtualThreadExecutor); + +// Executor virtualThreadExecutor2 = DtpRegistry.getExecutor("VirtualThreadExecutor2"); +// virtualThreadExecutor.execute(() -> System.out.println("VirtualThreadExecutor2 registered!")); +// Assertions.assertNotNull(virtualThreadExecutor2); + } } diff --git a/test/test-core/src/test/java/org/dromara/dynamictp/test/core/spring/PropertiesBinderTest.java b/test/test-core/src/test/java/org/dromara/dynamictp/test/core/spring/PropertiesBinderTest.java index 12d4a90cf..5ec60a092 100644 --- a/test/test-core/src/test/java/org/dromara/dynamictp/test/core/spring/PropertiesBinderTest.java +++ b/test/test-core/src/test/java/org/dromara/dynamictp/test/core/spring/PropertiesBinderTest.java @@ -35,6 +35,7 @@ import java.util.List; import java.util.Map; +import java.util.concurrent.TimeUnit; /** * PropertiesBinderTest related @@ -84,7 +85,8 @@ void testBindDtpPropertiesWithMap() throws Exception { } @Test - void testBindDtpPropertiesWithEnvironment() { + void testBindDtpPropertiesWithEnvironment() throws InterruptedException { + TimeUnit.MILLISECONDS.sleep(1000); DtpProperties dtpProperties = DtpProperties.getInstance(); BinderHelper.bindDtpProperties(environment, dtpProperties); String threadPoolName = environment.getProperty("dynamictp.executors[0].threadPoolName"); diff --git a/test/test-core/src/test/java/org/dromara/dynamictp/test/core/thread/OrderedDtpExecutorTest.java b/test/test-core/src/test/java/org/dromara/dynamictp/test/core/thread/OrderedDtpExecutorTest.java index 41671a9cf..cfb299b80 100644 --- a/test/test-core/src/test/java/org/dromara/dynamictp/test/core/thread/OrderedDtpExecutorTest.java +++ b/test/test-core/src/test/java/org/dromara/dynamictp/test/core/thread/OrderedDtpExecutorTest.java @@ -30,12 +30,12 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.slf4j.MDC; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.PropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; -import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Future; @@ -50,7 +50,7 @@ @EnableAutoConfiguration class OrderedDtpExecutorTest { - @Resource + @Autowired private OrderedDtpExecutor orderedDtpExecutor; private final TransmittableThreadLocal threadLocal = new TransmittableThreadLocal<>(); diff --git a/test/test-core/src/test/java/org/dromara/dynamictp/test/core/thread/PriorityDtpExecutorTest.java b/test/test-core/src/test/java/org/dromara/dynamictp/test/core/thread/PriorityDtpExecutorTest.java index 9fd72c693..3d4ec7d12 100644 --- a/test/test-core/src/test/java/org/dromara/dynamictp/test/core/thread/PriorityDtpExecutorTest.java +++ b/test/test-core/src/test/java/org/dromara/dynamictp/test/core/thread/PriorityDtpExecutorTest.java @@ -23,12 +23,12 @@ import org.dromara.dynamictp.spring.support.YamlPropertySourceFactory; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.PropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; -import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; @@ -48,7 +48,7 @@ @PropertySource(value = "classpath:/dynamic-tp-demo.yml", factory = YamlPropertySourceFactory.class) public class PriorityDtpExecutorTest { - @Resource + @Autowired private PriorityDtpExecutor priorityDtpExecutor; @Test diff --git a/test/test-extension/test-extension-limiter-redis/src/test/java/org/dromara/dynamictp/test/extension/limiter/redis/RedisRateLimiterTest.java b/test/test-extension/test-extension-limiter-redis/src/test/java/org/dromara/dynamictp/test/extension/limiter/redis/RedisRateLimiterTest.java index c4e0adeb3..540517476 100644 --- a/test/test-extension/test-extension-limiter-redis/src/test/java/org/dromara/dynamictp/test/extension/limiter/redis/RedisRateLimiterTest.java +++ b/test/test-extension/test-extension-limiter-redis/src/test/java/org/dromara/dynamictp/test/extension/limiter/redis/RedisRateLimiterTest.java @@ -17,6 +17,7 @@ package org.dromara.dynamictp.test.extension.limiter.redis; +import jakarta.annotation.Resource; import lombok.val; import org.dromara.dynamictp.extension.limiter.redis.ratelimiter.RedisRateLimiter; import org.dromara.dynamictp.spring.annotation.EnableDynamicTp; @@ -26,7 +27,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit.jupiter.SpringExtension; -import javax.annotation.Resource; import java.util.List; import java.util.concurrent.TimeUnit;