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> contentParams = Arrays.asList(data1, data2); + Class responseClass = String.class; + MessageTypeEnum messageType = MessageTypeEnum.DEFAULT; + MessageWrapper messageWrapper = new MessageWrapper(contentParams, responseClass, messageType); + MessageConvert.convert(messageWrapper); + }); + } +}