diff --git a/agent/hippo4j-agent-plugin/adapter-plugins/dubbo-plugin/pom.xml b/agent/hippo4j-agent-plugin/adapter-plugins/dubbo-plugin/pom.xml
new file mode 100644
index 00000000..5304c6eb
--- /dev/null
+++ b/agent/hippo4j-agent-plugin/adapter-plugins/dubbo-plugin/pom.xml
@@ -0,0 +1,29 @@
+
+
+
+ hippo4j-agent-adapter-plugins
+ cn.hippo4j
+ ${revision}
+
+ 4.0.0
+
+ dubbo-plugin
+
+
+
+ org.apache.dubbo
+ dubbo
+ provided
+
+
+
+ cn.hippo4j
+ hippo4j-threadpool-infra-common
+ ${project.version}
+
+
+
+
+
\ No newline at end of file
diff --git a/agent/hippo4j-agent-plugin/adapter-plugins/dubbo-plugin/src/main/java/cn/hippo4j/agent/adapter/dubbo/DubboThreadPoolAdapter.java b/agent/hippo4j-agent-plugin/adapter-plugins/dubbo-plugin/src/main/java/cn/hippo4j/agent/adapter/dubbo/DubboThreadPoolAdapter.java
new file mode 100644
index 00000000..855972ea
--- /dev/null
+++ b/agent/hippo4j-agent-plugin/adapter-plugins/dubbo-plugin/src/main/java/cn/hippo4j/agent/adapter/dubbo/DubboThreadPoolAdapter.java
@@ -0,0 +1,87 @@
+/*
+ * 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 cn.hippo4j.agent.adapter.dubbo;
+
+import cn.hippo4j.common.executor.ThreadPoolRegistry;
+import cn.hippo4j.common.executor.support.BlockingQueueTypeEnum;
+import cn.hippo4j.common.executor.support.RejectedPolicyTypeEnum;
+import cn.hippo4j.common.model.executor.ExecutorProperties;
+import cn.hippo4j.common.toolkit.BooleanUtil;
+import cn.hippo4j.common.toolkit.ReflectUtil;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadPoolExecutor;
+import org.apache.dubbo.common.Version;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.store.DataStore;
+import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
+
+/**
+ * Dubbo thread-pool adapter.
+ */
+public class DubboThreadPoolAdapter {
+
+ public static void registerExecutors() {
+ boolean isLegacyVersion = true;
+ String poolKey = ExecutorService.class.getName();
+ // Since 2.7.5, Dubbo has changed the way thread pools are used
+ // fixed https://github.com/opengoofy/hippo4j/issues/708
+ try {
+ if (Version.getIntVersion(Version.getVersion()) < 2070500) {
+ isLegacyVersion = false;
+ }
+ } catch (Exception ex) {
+ }
+
+ try {
+ if (isLegacyVersion) {
+ DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
+ Map executors = dataStore.get(poolKey);
+ executors.forEach((key, value) -> putHolder(mark() + key, (ThreadPoolExecutor) value));
+ return;
+ }
+ ExecutorRepository executorRepository = ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension();
+ ConcurrentMap> data =
+ (ConcurrentMap>) ReflectUtil.getFieldValue(executorRepository, "data");
+ ConcurrentMap executorServiceMap = data.get(poolKey);
+ executorServiceMap.forEach((key, value) -> putHolder(mark() + key, (ThreadPoolExecutor) value));
+ } catch (Exception ex) {
+ }
+ }
+
+ private static void putHolder(String executorName, ThreadPoolExecutor executor) {
+ if (executor == null) {
+ return;
+ }
+ ExecutorProperties executorProperties = ExecutorProperties.builder()
+ .threadPoolId(executorName)
+ .corePoolSize(executor.getCorePoolSize())
+ .maximumPoolSize(executor.getMaximumPoolSize())
+ .allowCoreThreadTimeOut(BooleanUtil.toBoolean(String.valueOf(executor.allowsCoreThreadTimeOut())))
+ .blockingQueue(BlockingQueueTypeEnum.getBlockingQueueTypeEnumByName(executor.getQueue().getClass().getSimpleName()).getName())
+ .queueCapacity(executor.getQueue().remainingCapacity())
+ .rejectedHandler(RejectedPolicyTypeEnum.getRejectedPolicyTypeEnumByName(executor.getRejectedExecutionHandler().getClass().getSimpleName()).getName())
+ .build();
+ ThreadPoolRegistry.putHolder(executorName, executor, executorProperties);
+ }
+
+ public static String mark() {
+ return "Dubbo";
+ }
+}
diff --git a/agent/hippo4j-agent-plugin/adapter-plugins/pom.xml b/agent/hippo4j-agent-plugin/adapter-plugins/pom.xml
index 38bfb05c..1c52b2e9 100644
--- a/agent/hippo4j-agent-plugin/adapter-plugins/pom.xml
+++ b/agent/hippo4j-agent-plugin/adapter-plugins/pom.xml
@@ -10,6 +10,7 @@
hippo4j-agent-adapter-plugins
+ pom
8
@@ -17,4 +18,8 @@
UTF-8
+
+ dubbo-plugin
+
+
\ No newline at end of file
diff --git a/agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1x-plugin/pom.xml b/agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1x-plugin/pom.xml
index ccec3c7b..b3d2cbf9 100644
--- a/agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1x-plugin/pom.xml
+++ b/agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1x-plugin/pom.xml
@@ -49,6 +49,12 @@
${project.version}
provided
+
+
+ cn.hippo4j
+ dubbo-plugin
+
+
\ No newline at end of file
diff --git a/agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/interceptor/EventPublishingFinishedInterceptor.java b/agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/interceptor/EventPublishingFinishedInterceptor.java
index 93b7d1ef..777194f0 100644
--- a/agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/interceptor/EventPublishingFinishedInterceptor.java
+++ b/agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/interceptor/EventPublishingFinishedInterceptor.java
@@ -17,6 +17,7 @@
package cn.hippo4j.agent.plugin.spring.boot.v1.interceptor;
+import cn.hippo4j.agent.adapter.dubbo.DubboThreadPoolAdapter;
import cn.hippo4j.agent.core.logging.api.ILog;
import cn.hippo4j.agent.core.logging.api.LogManager;
import cn.hippo4j.agent.core.plugin.interceptor.enhance.EnhancedInstance;
@@ -56,6 +57,7 @@ public class EventPublishingFinishedInterceptor implements InstanceMethodsAround
SpringPropertiesLoader.loadSpringProperties(context.getEnvironment());
ThreadPoolDynamicRefresh dynamicRefreshSpring1x = new DynamicThreadPoolChangeHandlerSpring1x(context);
dynamicRefreshSpring1x.registerListener();
+ DubboThreadPoolAdapter.registerExecutors();
return ret;
}
diff --git a/agent/pom.xml b/agent/pom.xml
index d0a8b793..0d899eab 100644
--- a/agent/pom.xml
+++ b/agent/pom.xml
@@ -154,6 +154,11 @@
${jmh.version}
test
+
+ cn.hippo4j
+ dubbo-plugin
+ ${project.version}
+
diff --git a/docs/i18n/zh/docusaurus-plugin-content-pages/users.md b/docs/i18n/zh/docusaurus-plugin-content-pages/users.md
index c780d5e1..f06de39a 100644
--- a/docs/i18n/zh/docusaurus-plugin-content-pages/users.md
+++ b/docs/i18n/zh/docusaurus-plugin-content-pages/users.md
@@ -5,7 +5,7 @@ title: 采用公司
## 谁在使用 Hippo4j
-共计 38+ 家公司生产接入 Hippo4j,按照公司登记时间排序。
+共计 39+ 家公司生产接入 Hippo4j,按照公司登记时间排序。
- [身边云](https://serviceshare.com)
- [思派健康科技](https://www.medbanks.cn)
@@ -45,6 +45,7 @@ title: 采用公司
- [神州数码(西安)](https://www.digitalchina.com)
- [广联达科技股份有限公司](https://www.glodon.com)
- [天健联创控股集团有限公司](https://www.tjlc.com.cn)
+- [知乎](https://www.zhihu.com/)
## 登记
diff --git a/docs/src/pages/users.md b/docs/src/pages/users.md
index c780d5e1..f06de39a 100644
--- a/docs/src/pages/users.md
+++ b/docs/src/pages/users.md
@@ -5,7 +5,7 @@ title: 采用公司
## 谁在使用 Hippo4j
-共计 38+ 家公司生产接入 Hippo4j,按照公司登记时间排序。
+共计 39+ 家公司生产接入 Hippo4j,按照公司登记时间排序。
- [身边云](https://serviceshare.com)
- [思派健康科技](https://www.medbanks.cn)
@@ -45,6 +45,7 @@ title: 采用公司
- [神州数码(西安)](https://www.digitalchina.com)
- [广联达科技股份有限公司](https://www.glodon.com)
- [天健联创控股集团有限公司](https://www.tjlc.com.cn)
+- [知乎](https://www.zhihu.com/)
## 登记
diff --git a/infra/common/src/main/java/cn/hippo4j/common/toolkit/MessageConvert.java b/infra/common/src/main/java/cn/hippo4j/common/toolkit/MessageConvert.java
index 3be85745..6a5d1fbc 100644
--- a/infra/common/src/main/java/cn/hippo4j/common/toolkit/MessageConvert.java
+++ b/infra/common/src/main/java/cn/hippo4j/common/toolkit/MessageConvert.java
@@ -31,6 +31,10 @@ import lombok.SneakyThrows;
*/
public class MessageConvert {
+ private MessageConvert(){
+
+ }
+
/**
* {@link Message} to {@link MessageWrapper}.
*
diff --git a/infra/common/src/test/java/cn/hippo4j/common/toolkit/MessageConvertTest.java b/infra/common/src/test/java/cn/hippo4j/common/toolkit/MessageConvertTest.java
new file mode 100644
index 00000000..88677d9f
--- /dev/null
+++ b/infra/common/src/test/java/cn/hippo4j/common/toolkit/MessageConvertTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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 cn.hippo4j.common.toolkit;
+
+import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
+import cn.hippo4j.common.monitor.*;
+import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+
+/***
+ * @description : Todo
+ * @author : DDDreame
+ * @date : 2023/5/27 23:24
+ */
+public class MessageConvertTest {
+
+ @Test
+ public void testConvert() {
+ AbstractMessage message = new RuntimeMessage();
+ List runtimeMessages = new ArrayList<>();
+ ThreadPoolRunStateInfo poolRunState = ThreadPoolRunStateInfo.builder()
+ .tpId("testTPid")
+ .activeSize(4)
+ .poolSize(12)
+ .completedTaskCount(8L)
+ .largestPoolSize(12)
+ .currentLoad("6")
+ .clientLastRefreshTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
+ .peakLoad("20")
+ .queueSize(0)
+ .queueRemainingCapacity(512)
+ .rejectCount(0L)
+ .timestamp(System.currentTimeMillis())
+ .build();
+ RuntimeMessage runtimeMessage = BeanUtil.convert(poolRunState, RuntimeMessage.class);
+ runtimeMessage.setGroupKey("test-groupKeys");
+ runtimeMessages.add(runtimeMessage);
+
+ message.setMessageType(MessageTypeEnum.RUNTIME);
+ message.setMessages(runtimeMessages);
+ MessageWrapper messageWrapper = MessageConvert.convert(message);
+ Assertions.assertNotNull(messageWrapper);
+ }
+
+ @Test
+ public void testMessageWrapperConvert() {
+ AbstractMessage message = new RuntimeMessage();
+ List runtimeMessages = new ArrayList<>();
+ ThreadPoolRunStateInfo poolRunState = ThreadPoolRunStateInfo.builder()
+ .tpId("testTPid")
+ .activeSize(4)
+ .poolSize(12)
+ .completedTaskCount(8L)
+ .largestPoolSize(12)
+ .currentLoad("6")
+ .clientLastRefreshTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
+ .peakLoad("20")
+ .queueSize(0)
+ .queueRemainingCapacity(512)
+ .rejectCount(0L)
+ .timestamp(System.currentTimeMillis())
+ .build();
+ RuntimeMessage runtimeMessage = BeanUtil.convert(poolRunState, RuntimeMessage.class);
+ runtimeMessage.setGroupKey("test-groupKeys");
+ runtimeMessages.add(runtimeMessage);
+
+ message.setMessageType(MessageTypeEnum.RUNTIME);
+ message.setMessages(runtimeMessages);
+ MessageWrapper messageWrapper = MessageConvert.convert(message);
+ Message messageResult = MessageConvert.convert(messageWrapper);
+ Assertions.assertNotNull(messageResult);
+ Assertions.assertEquals(message, messageResult);
+ }
+
+ @Test
+ public void testMessageWrapperConvertException() {
+ Assertions.assertThrows(Exception.class, ()->{
+ Map data1 = new HashMap<>();
+ data1.put("key1", "value1");
+ data1.put("key2", 123);
+ Map data2 = new HashMap<>();
+ data2.put("key3", true);
+ data2.put("key4", 3.14);
+ List