Fix the problem that command line startup cannot be enhanced. (#1234)

pull/1238/head
yanrongzhen 1 year ago committed by GitHub
parent bc849c1556
commit fcbc5f702e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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<NamedElement> 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 {

@ -68,12 +68,6 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-rules</artifactId>
<version>${ststem-rules.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>

@ -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;

@ -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<String, AgentThreadPoolExecutorHolder> holderMap = new ConcurrentHashMap<>();
public final Map<ThreadPoolExecutor, Class<?>> 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);
}

@ -30,11 +30,12 @@ public class ReflectUtil {
private static final ILog LOGGER = LogManager.getLogger(ReflectUtil.class);
public static List<Field> getStaticFieldsFromType(Class<?> clazz, Class<?> declaredType) {
Field[] fields = clazz.getFields();
Field[] fields = clazz.getDeclaredFields();
List<Field> result = new ArrayList<>();
for (Field field : fields) {
if (field.getType().isAssignableFrom(declaredType)
&& Modifier.isStatic(field.getModifiers())) {
field.setAccessible(true);
result.add(field);
}
}

@ -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";
}

@ -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<ExecutorProperties> 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())));
}

@ -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<ThreadPoolExecutor, Class<?>> earlyConstructMap = AgentThreadPoolInstanceRegistry.getInstance().earlyConstructMap;
for (Map.Entry<ThreadPoolExecutor, Class<?>> entry : earlyConstructMap.entrySet()) {
ThreadPoolExecutor enhancedInstance = entry.getKey();
Class<?> declaredClass = entry.getValue();
List<Field> 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) {
}
}

@ -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<MethodDescription> getMethodsMatcher() {
return named("run");
}
@Override
public String getMethodsInterceptor() {
return SPRING_APPLICATION_RUN_INTERCEPTOR;
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}

@ -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
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

@ -16,6 +16,12 @@
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-core</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-common</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

@ -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<Field> 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<StackTraceElement> getStackTraceElements() {

@ -78,4 +78,21 @@
<version>1.1.3</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

Loading…
Cancel
Save