From 2f75263fa16ebc4ad156f2977134957e9fd7b7fa Mon Sep 17 00:00:00 2001 From: yanrongzhen Date: Tue, 9 May 2023 21:27:34 +0800 Subject: [PATCH] Fix the problem that command line startup cannot be enhanced. --- .../hippo4j/agent/bootstrap/Hippo4jAgent.java | 13 +- hippo4j-agent/hippo4j-agent-core/pom.xml | 6 - .../AgentThreadPoolExecutorHolder.java | 5 +- .../AgentThreadPoolInstanceRegistry.java | 5 +- .../hippo4j/agent/core/util/ReflectUtil.java | 3 +- .../core/util/ThreadPoolPropertyKey.java | 32 +++++ .../EventPublishingFinishedInterceptor.java | 118 +++++++++++------- .../v1/SpringApplicationRunInterceptor.java | 100 +++++++++++++++ .../SpringApplicationRunInstrumentation.java | 68 ++++++++++ .../src/main/resources/hippo4j-plugin.def | 3 +- .../thread-pool-plugin/pom.xml | 6 + ...lExecutorConstructorMethodInterceptor.java | 45 +------ .../pom.xml | 17 +++ 13 files changed, 322 insertions(+), 99 deletions(-) create mode 100644 hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/ThreadPoolPropertyKey.java create mode 100644 hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/SpringApplicationRunInterceptor.java create mode 100644 hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/define/SpringApplicationRunInstrumentation.java diff --git a/hippo4j-agent/hippo4j-agent-bootstrap/src/main/java/cn/hippo4j/agent/bootstrap/Hippo4jAgent.java b/hippo4j-agent/hippo4j-agent-bootstrap/src/main/java/cn/hippo4j/agent/bootstrap/Hippo4jAgent.java index 36fd81c2..afae5cc0 100644 --- a/hippo4j-agent/hippo4j-agent-bootstrap/src/main/java/cn/hippo4j/agent/bootstrap/Hippo4jAgent.java +++ b/hippo4j-agent/hippo4j-agent-bootstrap/src/main/java/cn/hippo4j/agent/bootstrap/Hippo4jAgent.java @@ -18,6 +18,7 @@ package cn.hippo4j.agent.bootstrap; import cn.hippo4j.agent.core.boot.AgentPackageNotFoundException; +import cn.hippo4j.agent.core.boot.DefaultNamedThreadFactory; import cn.hippo4j.agent.core.boot.ServiceManager; import cn.hippo4j.agent.core.conf.Config; import cn.hippo4j.agent.core.conf.SnifferConfigInitializer; @@ -48,6 +49,10 @@ import java.security.ProtectionDomain; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import static net.bytebuddy.matcher.ElementMatchers.nameContains; import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; @@ -136,6 +141,12 @@ public class Hippo4jAgent { LOGGER.error(e, "Hippo4j agent boot failure."); } + try { + Class.forName("java.util.concurrent.ThreadPoolExecutor"); + } catch (ClassNotFoundException e) { + LOGGER.error(e, "Hippo4j agent boot failure."); + } + Runtime.getRuntime() .addShutdownHook(new Thread(ServiceManager.INSTANCE::shutdown, "hippo4j service shutdown thread")); } @@ -179,7 +190,7 @@ public class Hippo4jAgent { } private static ElementMatcher.Junction allHippo4jAgentExcludeToolkit() { - return nameStartsWith("cn.hippo4j.agent").and(not(nameStartsWith("cn.hippo4j.agent.toolkit."))); + return nameStartsWith("cn.hippo4j").and(not(nameStartsWith("cn.hippo4j.agent.toolkit."))); } private static class Listener implements AgentBuilder.Listener { diff --git a/hippo4j-agent/hippo4j-agent-core/pom.xml b/hippo4j-agent/hippo4j-agent-core/pom.xml index e5d711ec..16935905 100644 --- a/hippo4j-agent/hippo4j-agent-core/pom.xml +++ b/hippo4j-agent/hippo4j-agent-core/pom.xml @@ -68,12 +68,6 @@ - - com.github.stefanbirkner - system-rules - ${ststem-rules.version} - test - org.openjdk.jmh jmh-generator-annprocess diff --git a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/registry/AgentThreadPoolExecutorHolder.java b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/registry/AgentThreadPoolExecutorHolder.java index deccaa59..42df259e 100644 --- a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/registry/AgentThreadPoolExecutorHolder.java +++ b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/registry/AgentThreadPoolExecutorHolder.java @@ -22,6 +22,7 @@ import cn.hippo4j.agent.core.logging.api.LogManager; import cn.hippo4j.common.config.ExecutorProperties; import lombok.Data; +import java.util.Properties; import java.util.concurrent.ThreadPoolExecutor; @Data @@ -35,12 +36,12 @@ public class AgentThreadPoolExecutorHolder { private ThreadPoolExecutor executor; - private ExecutorProperties properties; + private Properties properties; public AgentThreadPoolExecutorHolder() { } - public AgentThreadPoolExecutorHolder(String executorName, ThreadPoolExecutor executor, ExecutorProperties properties) { + public AgentThreadPoolExecutorHolder(String executorName, ThreadPoolExecutor executor, Properties properties) { this.executorName = executorName; this.executor = executor; this.properties = properties; diff --git a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/registry/AgentThreadPoolInstanceRegistry.java b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/registry/AgentThreadPoolInstanceRegistry.java index b70228c3..3b34210e 100644 --- a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/registry/AgentThreadPoolInstanceRegistry.java +++ b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/registry/AgentThreadPoolInstanceRegistry.java @@ -23,6 +23,7 @@ import cn.hippo4j.common.config.ExecutorProperties; import java.util.Map; import java.util.Optional; +import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadPoolExecutor; @@ -32,6 +33,8 @@ public class AgentThreadPoolInstanceRegistry { private final Map holderMap = new ConcurrentHashMap<>(); + public final Map> earlyConstructMap = new ConcurrentHashMap<>(); + private volatile static AgentThreadPoolInstanceRegistry INSTANCE; private AgentThreadPoolInstanceRegistry() { @@ -52,7 +55,7 @@ public class AgentThreadPoolInstanceRegistry { return holderMap; } - public void putHolder(String executorName, ThreadPoolExecutor executor, ExecutorProperties properties) { + public void putHolder(String executorName, ThreadPoolExecutor executor, Properties properties) { AgentThreadPoolExecutorHolder holder = new AgentThreadPoolExecutorHolder(executorName, executor, properties); holderMap.put(executorName, holder); } diff --git a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/ReflectUtil.java b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/ReflectUtil.java index 9a7cc2d1..e6fed965 100644 --- a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/ReflectUtil.java +++ b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/ReflectUtil.java @@ -30,11 +30,12 @@ public class ReflectUtil { private static final ILog LOGGER = LogManager.getLogger(ReflectUtil.class); public static List getStaticFieldsFromType(Class clazz, Class declaredType) { - Field[] fields = clazz.getFields(); + Field[] fields = clazz.getDeclaredFields(); List result = new ArrayList<>(); for (Field field : fields) { if (field.getType().isAssignableFrom(declaredType) && Modifier.isStatic(field.getModifiers())) { + field.setAccessible(true); result.add(field); } } diff --git a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/ThreadPoolPropertyKey.java b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/ThreadPoolPropertyKey.java new file mode 100644 index 00000000..89148adb --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/ThreadPoolPropertyKey.java @@ -0,0 +1,32 @@ +/* + * 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.core.util; + +public interface ThreadPoolPropertyKey { + + String THREAD_POOL_ID = "threadPoolId"; + String CORE_POOL_SIZE = "corePoolSize"; + String MAXIMUM_POOL_SIZE = "maximumPoolSize"; + String ALLOW_CORE_THREAD_TIME_OUT = "allowCoreThreadTimeOut"; + String KEEP_ALIVE_TIME = "keepAliveTime"; + String BLOCKING_QUEUE = "blockingQueue"; + String QUEUE_CAPACITY = "queueCapacity"; + String THREAD_NAME_PREFIX = "threadNamePrefix"; + String REJECTED_HANDLER = "rejectedHandler"; + String EXECUTE_TIME_OUT = "executeTimeOut"; +} diff --git a/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/EventPublishingFinishedInterceptor.java b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/EventPublishingFinishedInterceptor.java index 856489bc..1017c46b 100644 --- a/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/EventPublishingFinishedInterceptor.java +++ b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/EventPublishingFinishedInterceptor.java @@ -24,6 +24,7 @@ import cn.hippo4j.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInt import cn.hippo4j.agent.core.plugin.interceptor.enhance.MethodInterceptResult; import cn.hippo4j.agent.core.registry.AgentThreadPoolExecutorHolder; import cn.hippo4j.agent.core.registry.AgentThreadPoolInstanceRegistry; +import cn.hippo4j.agent.core.util.ThreadPoolPropertyKey; import cn.hippo4j.agent.plugin.spring.common.SpringPropertiesLoader; import cn.hippo4j.common.executor.support.BlockingQueueTypeEnum; import cn.hippo4j.common.executor.support.RejectedPolicyTypeEnum; @@ -60,6 +61,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.Properties; import java.util.Set; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadPoolExecutor; @@ -143,20 +145,21 @@ public class EventPublishingFinishedInterceptor implements InstanceMethodsAround BootstrapConfigProperties afterConfigProperties = bindProperties(afterConfigMap, context); List executors = afterConfigProperties.getExecutors(); - for (ExecutorProperties properties : executors) { - String threadPoolId = properties.getThreadPoolId(); - // if (!match(properties)) { - // continue; - // } - if (!checkConsistency(threadPoolId, properties)) { + for (ExecutorProperties afterProperties : executors) { + String threadPoolId = afterProperties.getThreadPoolId(); + AgentThreadPoolExecutorHolder holder = AgentThreadPoolInstanceRegistry.getInstance().getHolder(threadPoolId); + if (holder.isEmpty() || holder.getExecutor() == null) { continue; } + ExecutorProperties beforeProperties = convert(holder.getProperties()); - dynamicRefreshPool(threadPoolId, properties); - AgentThreadPoolExecutorHolder holder = AgentThreadPoolInstanceRegistry.getInstance().getHolder(properties.getThreadPoolId()); - ExecutorProperties beforeProperties = holder.getProperties(); - holder.setProperties(failDefaultExecutorProperties(beforeProperties, properties)); // do refresh. - ChangeParameterNotifyRequest changeRequest = buildChangeRequest(beforeProperties, properties); + if (!checkConsistency(threadPoolId, beforeProperties, afterProperties)) { + continue; + } + + dynamicRefreshPool(beforeProperties, afterProperties); + holder.setProperties(failDefaultExecutorProperties(beforeProperties, afterProperties)); // do refresh. + ChangeParameterNotifyRequest changeRequest = buildChangeRequest(beforeProperties, afterProperties); LOGGER.info(CHANGE_THREAD_POOL_TEXT, threadPoolId, String.format(CHANGE_DELIMITER, beforeProperties.getCorePoolSize(), changeRequest.getNowCorePoolSize()), @@ -175,9 +178,8 @@ public class EventPublishingFinishedInterceptor implements InstanceMethodsAround /** * Dynamic refresh pool. */ - private void dynamicRefreshPool(String threadPoolId, ExecutorProperties afterProperties) { + private void dynamicRefreshPool(ExecutorProperties beforeProperties, ExecutorProperties afterProperties) { AgentThreadPoolExecutorHolder holder = AgentThreadPoolInstanceRegistry.getInstance().getHolder(afterProperties.getThreadPoolId()); - ExecutorProperties beforeProperties = holder.getProperties(); ThreadPoolExecutor executor = holder.getExecutor(); if (afterProperties.getMaximumPoolSize() != null && afterProperties.getCorePoolSize() != null) { ThreadPoolExecutorUtil.safeSetPoolSize(executor, afterProperties.getCorePoolSize(), afterProperties.getMaximumPoolSize()); @@ -219,31 +221,60 @@ public class EventPublishingFinishedInterceptor implements InstanceMethodsAround * Fail default executor properties. * * @param beforeProperties old properties - * @param properties new properties + * @param afterProperties new properties * @return executor properties */ - private ExecutorProperties failDefaultExecutorProperties(ExecutorProperties beforeProperties, ExecutorProperties properties) { - return ExecutorProperties.builder() - .corePoolSize(Optional.ofNullable(properties.getCorePoolSize()).orElse(beforeProperties.getCorePoolSize())) - .maximumPoolSize(Optional.ofNullable(properties.getMaximumPoolSize()).orElse(beforeProperties.getMaximumPoolSize())) - .blockingQueue(properties.getBlockingQueue()) - .queueCapacity(Optional.ofNullable(properties.getQueueCapacity()).orElse(beforeProperties.getQueueCapacity())) - .keepAliveTime(Optional.ofNullable(properties.getKeepAliveTime()).orElse(beforeProperties.getKeepAliveTime())) - .executeTimeOut(Optional.ofNullable(properties.getExecuteTimeOut()).orElse(beforeProperties.getExecuteTimeOut())) - .rejectedHandler(Optional.ofNullable(properties.getRejectedHandler()).orElse(beforeProperties.getRejectedHandler())) - .allowCoreThreadTimeOut(Optional.ofNullable(properties.getAllowCoreThreadTimeOut()).orElse(beforeProperties.getAllowCoreThreadTimeOut())) + private Properties failDefaultExecutorProperties(ExecutorProperties beforeProperties, ExecutorProperties afterProperties) { + return convert(ExecutorProperties.builder() + .corePoolSize(Optional.ofNullable(afterProperties.getCorePoolSize()).orElse(beforeProperties.getCorePoolSize())) + .maximumPoolSize(Optional.ofNullable(afterProperties.getMaximumPoolSize()).orElse(beforeProperties.getMaximumPoolSize())) + .blockingQueue(afterProperties.getBlockingQueue()) + .queueCapacity(Optional.ofNullable(afterProperties.getQueueCapacity()).orElse(beforeProperties.getQueueCapacity())) + .keepAliveTime(Optional.ofNullable(afterProperties.getKeepAliveTime()).orElse(beforeProperties.getKeepAliveTime())) + .executeTimeOut(Optional.ofNullable(afterProperties.getExecuteTimeOut()).orElse(beforeProperties.getExecuteTimeOut())) + .rejectedHandler(Optional.ofNullable(afterProperties.getRejectedHandler()).orElse(beforeProperties.getRejectedHandler())) + .allowCoreThreadTimeOut(Optional.ofNullable(afterProperties.getAllowCoreThreadTimeOut()).orElse(beforeProperties.getAllowCoreThreadTimeOut())) .threadPoolId(beforeProperties.getThreadPoolId()) + .build()); + } + + private ExecutorProperties convert(Properties properties) { + return ExecutorProperties.builder() + .threadPoolId((String) properties.get(ThreadPoolPropertyKey.THREAD_POOL_ID)) + .corePoolSize((Integer) properties.get(ThreadPoolPropertyKey.CORE_POOL_SIZE)) + .maximumPoolSize((Integer) properties.get(ThreadPoolPropertyKey.MAXIMUM_POOL_SIZE)) + .allowCoreThreadTimeOut((Boolean) properties.get(ThreadPoolPropertyKey.ALLOW_CORE_THREAD_TIME_OUT)) + .keepAliveTime((Long) properties.get(ThreadPoolPropertyKey.KEEP_ALIVE_TIME)) + .blockingQueue((String) properties.get(ThreadPoolPropertyKey.BLOCKING_QUEUE)) + .queueCapacity((Integer) properties.get(ThreadPoolPropertyKey.QUEUE_CAPACITY)) + .threadNamePrefix((String) properties.get(ThreadPoolPropertyKey.THREAD_NAME_PREFIX)) + .rejectedHandler((String) properties.get(ThreadPoolPropertyKey.REJECTED_HANDLER)) + .executeTimeOut((Long) properties.get(ThreadPoolPropertyKey.EXECUTE_TIME_OUT)) .build(); } + private Properties convert(ExecutorProperties executorProperties) { + Properties properties = new Properties(); + Optional.ofNullable(executorProperties.getCorePoolSize()).ifPresent(v -> properties.put(ThreadPoolPropertyKey.CORE_POOL_SIZE, v)); + Optional.ofNullable(executorProperties.getMaximumPoolSize()).ifPresent(v -> properties.put(ThreadPoolPropertyKey.MAXIMUM_POOL_SIZE, v)); + Optional.ofNullable(executorProperties.getBlockingQueue()).ifPresent(v -> properties.put(ThreadPoolPropertyKey.BLOCKING_QUEUE, v)); + Optional.ofNullable(executorProperties.getQueueCapacity()).ifPresent(v -> properties.put(ThreadPoolPropertyKey.QUEUE_CAPACITY, v)); + Optional.ofNullable(executorProperties.getKeepAliveTime()).ifPresent(v -> properties.put(ThreadPoolPropertyKey.KEEP_ALIVE_TIME, v)); + Optional.ofNullable(executorProperties.getExecuteTimeOut()).ifPresent(v -> properties.put(ThreadPoolPropertyKey.EXECUTE_TIME_OUT, v)); + Optional.ofNullable(executorProperties.getRejectedHandler()).ifPresent(v -> properties.put(ThreadPoolPropertyKey.REJECTED_HANDLER, v)); + Optional.ofNullable(executorProperties.getAllowCoreThreadTimeOut()).ifPresent(v -> properties.put(ThreadPoolPropertyKey.ALLOW_CORE_THREAD_TIME_OUT, v)); + Optional.ofNullable(executorProperties.getThreadPoolId()).ifPresent(v -> properties.put(ThreadPoolPropertyKey.THREAD_POOL_ID, v)); + return properties; + } + /** * Construct change parameter notify request instance. * * @param beforeProperties old properties - * @param properties new properties + * @param afterProperties new properties * @return instance */ - private ChangeParameterNotifyRequest buildChangeRequest(ExecutorProperties beforeProperties, ExecutorProperties properties) { + private ChangeParameterNotifyRequest buildChangeRequest(ExecutorProperties beforeProperties, ExecutorProperties afterProperties) { ChangeParameterNotifyRequest changeParameterNotifyRequest = ChangeParameterNotifyRequest.builder() .beforeCorePoolSize(beforeProperties.getCorePoolSize()) .beforeMaximumPoolSize(beforeProperties.getMaximumPoolSize()) @@ -252,14 +283,14 @@ public class EventPublishingFinishedInterceptor implements InstanceMethodsAround .beforeQueueCapacity(beforeProperties.getQueueCapacity()) .beforeRejectedName(beforeProperties.getRejectedHandler()) .beforeExecuteTimeOut(beforeProperties.getExecuteTimeOut()) - .blockingQueueName(properties.getBlockingQueue()) - .nowCorePoolSize(Optional.ofNullable(properties.getCorePoolSize()).orElse(beforeProperties.getCorePoolSize())) - .nowMaximumPoolSize(Optional.ofNullable(properties.getMaximumPoolSize()).orElse(beforeProperties.getMaximumPoolSize())) - .nowAllowsCoreThreadTimeOut(Optional.ofNullable(properties.getAllowCoreThreadTimeOut()).orElse(beforeProperties.getAllowCoreThreadTimeOut())) - .nowKeepAliveTime(Optional.ofNullable(properties.getKeepAliveTime()).orElse(beforeProperties.getKeepAliveTime())) - .nowQueueCapacity(Optional.ofNullable(properties.getQueueCapacity()).orElse(beforeProperties.getQueueCapacity())) - .nowRejectedName(Optional.ofNullable(properties.getRejectedHandler()).orElse(beforeProperties.getRejectedHandler())) - .nowExecuteTimeOut(Optional.ofNullable(properties.getExecuteTimeOut()).orElse(beforeProperties.getExecuteTimeOut())) + .blockingQueueName(afterProperties.getBlockingQueue()) + .nowCorePoolSize(Optional.ofNullable(afterProperties.getCorePoolSize()).orElse(beforeProperties.getCorePoolSize())) + .nowMaximumPoolSize(Optional.ofNullable(afterProperties.getMaximumPoolSize()).orElse(beforeProperties.getMaximumPoolSize())) + .nowAllowsCoreThreadTimeOut(Optional.ofNullable(afterProperties.getAllowCoreThreadTimeOut()).orElse(beforeProperties.getAllowCoreThreadTimeOut())) + .nowKeepAliveTime(Optional.ofNullable(afterProperties.getKeepAliveTime()).orElse(beforeProperties.getKeepAliveTime())) + .nowQueueCapacity(Optional.ofNullable(afterProperties.getQueueCapacity()).orElse(beforeProperties.getQueueCapacity())) + .nowRejectedName(Optional.ofNullable(afterProperties.getRejectedHandler()).orElse(beforeProperties.getRejectedHandler())) + .nowExecuteTimeOut(Optional.ofNullable(afterProperties.getExecuteTimeOut()).orElse(beforeProperties.getExecuteTimeOut())) .build(); changeParameterNotifyRequest.setThreadPoolId(beforeProperties.getThreadPoolId()); return changeParameterNotifyRequest; @@ -269,23 +300,22 @@ public class EventPublishingFinishedInterceptor implements InstanceMethodsAround * Check consistency. * * @param threadPoolId - * @param properties + * @param afterProperties */ - private boolean checkConsistency(String threadPoolId, ExecutorProperties properties) { + private boolean checkConsistency(String threadPoolId, ExecutorProperties beforeProperties, ExecutorProperties afterProperties) { AgentThreadPoolExecutorHolder holder = AgentThreadPoolInstanceRegistry.getInstance().getHolder(threadPoolId); if (holder.isEmpty() || holder.getExecutor() == null) { return false; } ThreadPoolExecutor executor = holder.getExecutor(); - ExecutorProperties beforeProperties = holder.getProperties(); - return (properties.getCorePoolSize() != null && !Objects.equals(beforeProperties.getCorePoolSize(), properties.getCorePoolSize())) - || (properties.getMaximumPoolSize() != null && !Objects.equals(beforeProperties.getMaximumPoolSize(), properties.getMaximumPoolSize())) - || (properties.getAllowCoreThreadTimeOut() != null && !Objects.equals(beforeProperties.getAllowCoreThreadTimeOut(), properties.getAllowCoreThreadTimeOut())) - || (properties.getExecuteTimeOut() != null && !Objects.equals(beforeProperties.getExecuteTimeOut(), properties.getExecuteTimeOut())) - || (properties.getKeepAliveTime() != null && !Objects.equals(beforeProperties.getKeepAliveTime(), properties.getKeepAliveTime())) - || (properties.getRejectedHandler() != null && !Objects.equals(beforeProperties.getRejectedHandler(), properties.getRejectedHandler())) + return (afterProperties.getCorePoolSize() != null && !Objects.equals(beforeProperties.getCorePoolSize(), afterProperties.getCorePoolSize())) + || (afterProperties.getMaximumPoolSize() != null && !Objects.equals(beforeProperties.getMaximumPoolSize(), afterProperties.getMaximumPoolSize())) + || (afterProperties.getAllowCoreThreadTimeOut() != null && !Objects.equals(beforeProperties.getAllowCoreThreadTimeOut(), afterProperties.getAllowCoreThreadTimeOut())) + || (afterProperties.getExecuteTimeOut() != null && !Objects.equals(beforeProperties.getExecuteTimeOut(), afterProperties.getExecuteTimeOut())) + || (afterProperties.getKeepAliveTime() != null && !Objects.equals(beforeProperties.getKeepAliveTime(), afterProperties.getKeepAliveTime())) + || (afterProperties.getRejectedHandler() != null && !Objects.equals(beforeProperties.getRejectedHandler(), afterProperties.getRejectedHandler())) || - ((properties.getQueueCapacity() != null && !Objects.equals(beforeProperties.getQueueCapacity(), properties.getQueueCapacity()) + ((afterProperties.getQueueCapacity() != null && !Objects.equals(beforeProperties.getQueueCapacity(), afterProperties.getQueueCapacity()) && Objects.equals(BlockingQueueTypeEnum.RESIZABLE_LINKED_BLOCKING_QUEUE.getName(), executor.getQueue().getClass().getSimpleName()))); } diff --git a/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/SpringApplicationRunInterceptor.java b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/SpringApplicationRunInterceptor.java new file mode 100644 index 00000000..f75980f4 --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/SpringApplicationRunInterceptor.java @@ -0,0 +1,100 @@ +/* + * 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.plugin.spring.boot.v1; + +import cn.hippo4j.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import cn.hippo4j.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; +import cn.hippo4j.agent.core.plugin.interceptor.enhance.MethodInterceptResult; +import cn.hippo4j.agent.core.registry.AgentThreadPoolInstanceRegistry; +import cn.hippo4j.agent.core.util.ReflectUtil; +import cn.hippo4j.agent.core.util.ThreadPoolPropertyKey; +import cn.hippo4j.common.executor.support.BlockingQueueTypeEnum; +import cn.hippo4j.common.executor.support.RejectedPolicyTypeEnum; +import cn.hippo4j.common.toolkit.BooleanUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class SpringApplicationRunInterceptor implements InstanceMethodsAroundInterceptor { + + private static final Logger LOGGER = LoggerFactory.getLogger(SpringApplicationRunInterceptor.class); + + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, MethodInterceptResult result) throws Throwable { + + } + + @Override + public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, Object ret) throws Throwable { + registerThreadPoolInstances(); + LOGGER.info("[Hippo4j-Agent] Registered thread pool instances successfully."); + return ret; + } + + private void registerThreadPoolInstances() { + Map> earlyConstructMap = AgentThreadPoolInstanceRegistry.getInstance().earlyConstructMap; + for (Map.Entry> entry : earlyConstructMap.entrySet()) { + ThreadPoolExecutor enhancedInstance = entry.getKey(); + Class declaredClass = entry.getValue(); + List declaredFields = ReflectUtil.getStaticFieldsFromType(declaredClass, ThreadPoolExecutor.class); + for (Field field : declaredFields) { + try { + Object value = field.get(null); + if (value == enhancedInstance) { + String threadPoolId = declaredClass.getName() + "#" + field.getName(); + register(threadPoolId, enhancedInstance); + break; + } + } catch (IllegalAccessException e) { + LOGGER.error("Get static field error.", e); + } + } + } + } + + private void register(String threadPoolId, ThreadPoolExecutor executor) { + // build parameter properties. + Properties properties = new Properties(); + properties.put(ThreadPoolPropertyKey.THREAD_POOL_ID, threadPoolId); + properties.put(ThreadPoolPropertyKey.CORE_POOL_SIZE, executor.getCorePoolSize()); + properties.put(ThreadPoolPropertyKey.MAXIMUM_POOL_SIZE, executor.getMaximumPoolSize()); + properties.put(ThreadPoolPropertyKey.ALLOW_CORE_THREAD_TIME_OUT, BooleanUtil.toBoolean(String.valueOf(executor.allowsCoreThreadTimeOut()))); + properties.put(ThreadPoolPropertyKey.KEEP_ALIVE_TIME, executor.getKeepAliveTime(TimeUnit.MILLISECONDS)); + properties.put(ThreadPoolPropertyKey.BLOCKING_QUEUE, BlockingQueueTypeEnum.getBlockingQueueTypeEnumByName(executor.getQueue().getClass().getSimpleName()).getName()); + properties.put(ThreadPoolPropertyKey.QUEUE_CAPACITY, executor.getQueue().remainingCapacity()); + properties.put(ThreadPoolPropertyKey.THREAD_NAME_PREFIX, threadPoolId); + properties.put(ThreadPoolPropertyKey.REJECTED_HANDLER, RejectedPolicyTypeEnum.getRejectedPolicyTypeEnumByName(executor.getRejectedExecutionHandler().getClass().getSimpleName()).getName()); + properties.put(ThreadPoolPropertyKey.EXECUTE_TIME_OUT, 10000L); + + // register executor. + AgentThreadPoolInstanceRegistry.getInstance().putHolder(threadPoolId, executor, properties); + + } + + @Override + public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, Throwable t) { + + } +} diff --git a/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/define/SpringApplicationRunInstrumentation.java b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/define/SpringApplicationRunInstrumentation.java new file mode 100644 index 00000000..ea2403a3 --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/define/SpringApplicationRunInstrumentation.java @@ -0,0 +1,68 @@ +/* + * 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.plugin.spring.boot.v1.define; + +import cn.hippo4j.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import cn.hippo4j.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import cn.hippo4j.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; +import cn.hippo4j.agent.core.plugin.match.ClassMatch; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; + +import static cn.hippo4j.agent.core.plugin.match.NameMatch.byName; +import static net.bytebuddy.matcher.ElementMatchers.named; + +public class SpringApplicationRunInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + + private static final String ENHANCE_CLASS = "org.springframework.boot.SpringApplication"; + + private static final String SPRING_APPLICATION_RUN_INTERCEPTOR = "cn.hippo4j.agent.plugin.spring.boot.v1.SpringApplicationRunInterceptor"; + + @Override + protected ClassMatch enhanceClass() { + return byName(ENHANCE_CLASS); + } + + @Override + public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[0]; + } + + @Override + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[]{ + new InstanceMethodsInterceptPoint() { + + @Override + public ElementMatcher getMethodsMatcher() { + return named("run"); + } + + @Override + public String getMethodsInterceptor() { + return SPRING_APPLICATION_RUN_INTERCEPTOR; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + } + }; + } +} diff --git a/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/resources/hippo4j-plugin.def b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/resources/hippo4j-plugin.def index 8bb37e3a..bcea5121 100644 --- a/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/resources/hippo4j-plugin.def +++ b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/resources/hippo4j-plugin.def @@ -14,4 +14,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -spring-boot-1.x=cn.hippo4j.agent.plugin.spring.boot.v1.define.EventPublishingRunListenerInstrumentation \ No newline at end of file +spring-boot-1.x=cn.hippo4j.agent.plugin.spring.boot.v1.define.EventPublishingRunListenerInstrumentation +spring-boot-1.x=cn.hippo4j.agent.plugin.spring.boot.v1.define.SpringApplicationRunInstrumentation \ No newline at end of file diff --git a/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/pom.xml b/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/pom.xml index 019cb64c..ac99d683 100644 --- a/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/pom.xml +++ b/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/pom.xml @@ -16,6 +16,12 @@ cn.hippo4j hippo4j-core ${project.version} + provided + + + cn.hippo4j + hippo4j-common + ${project.version} \ No newline at end of file diff --git a/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/src/main/java/cn/hippo4j/agent/plugin/thread/pool/ThreadPoolExecutorConstructorMethodInterceptor.java b/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/src/main/java/cn/hippo4j/agent/plugin/thread/pool/ThreadPoolExecutorConstructorMethodInterceptor.java index 49d35c13..1f6835b4 100644 --- a/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/src/main/java/cn/hippo4j/agent/plugin/thread/pool/ThreadPoolExecutorConstructorMethodInterceptor.java +++ b/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/src/main/java/cn/hippo4j/agent/plugin/thread/pool/ThreadPoolExecutorConstructorMethodInterceptor.java @@ -24,20 +24,12 @@ import cn.hippo4j.agent.core.plugin.interceptor.enhance.EnhancedInstance; import cn.hippo4j.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; import cn.hippo4j.agent.core.registry.AgentThreadPoolInstanceRegistry; import cn.hippo4j.agent.core.util.CollectionUtil; -import cn.hippo4j.agent.core.util.ReflectUtil; import cn.hippo4j.agent.core.util.StringUtil; -import cn.hippo4j.common.config.ExecutorProperties; -import cn.hippo4j.common.executor.support.BlockingQueueTypeEnum; -import cn.hippo4j.common.executor.support.RejectedPolicyTypeEnum; -import cn.hippo4j.common.toolkit.BooleanUtil; - -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; public class ThreadPoolExecutorConstructorMethodInterceptor implements InstanceConstructorInterceptor { @@ -54,41 +46,8 @@ public class ThreadPoolExecutorConstructorMethodInterceptor implements InstanceC } StackTraceElement declaredClassStackTraceElement = stackTraceElements.get(0); String declaredClassName = declaredClassStackTraceElement.getClassName(); - List staticFieldsFromType = ReflectUtil.getStaticFieldsFromType(Class.forName(declaredClassName), - ThreadPoolExecutor.class); - for (Field field : staticFieldsFromType) { - try { - Object value = field.get(null); - if (value != null) { - String threadPoolId = declaredClassName + "#" + field.getName(); - ThreadPoolExecutor executor = (ThreadPoolExecutor) field.get(null); - register(threadPoolId, executor); - } - } catch (IllegalAccessException e) { - LOGGER.error(String.format("ExecutorNameUtil, register thread pool error. ClassName=[%s], ThreadPoolFieldName=[%s]", - objInst.getClass().getName(), field.getName()), e); - } - } - } - - private void register(String threadPoolId, ThreadPoolExecutor executor) { - // build parameter info. - ExecutorProperties executorProperties = ExecutorProperties.builder() - .threadPoolId(threadPoolId) - .corePoolSize(executor.getCorePoolSize()) - .maximumPoolSize(executor.getMaximumPoolSize()) - .allowCoreThreadTimeOut(BooleanUtil.toBoolean(String.valueOf(executor.allowsCoreThreadTimeOut()))) - .keepAliveTime(executor.getKeepAliveTime(TimeUnit.MILLISECONDS)) - .blockingQueue(BlockingQueueTypeEnum.getBlockingQueueTypeEnumByName(executor.getQueue().getClass().getSimpleName()).getName()) - .queueCapacity(executor.getQueue().remainingCapacity()) - .threadNamePrefix(threadPoolId) - .rejectedHandler(RejectedPolicyTypeEnum.getRejectedPolicyTypeEnumByName(executor.getRejectedExecutionHandler().getClass().getSimpleName()).getName()) - .executeTimeOut(10000L) - .build(); - - // register executor. - AgentThreadPoolInstanceRegistry.getInstance().putHolder(threadPoolId, executor, executorProperties); - + Class declaredClass = Thread.currentThread().getContextClassLoader().loadClass(declaredClassName); + AgentThreadPoolInstanceRegistry.getInstance().earlyConstructMap.put((ThreadPoolExecutor) objInst, declaredClass); } private List getStackTraceElements() { diff --git a/hippo4j-example/hippo4j-config-apollo-spring-boot-1x-starter-example/pom.xml b/hippo4j-example/hippo4j-config-apollo-spring-boot-1x-starter-example/pom.xml index 33f94765..cfdab36b 100644 --- a/hippo4j-example/hippo4j-config-apollo-spring-boot-1x-starter-example/pom.xml +++ b/hippo4j-example/hippo4j-config-apollo-spring-boot-1x-starter-example/pom.xml @@ -78,4 +78,21 @@ 1.1.3 + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + +