Complete the agent of springboot1.x version in config mode. (#1215)

pull/1219/head
yanrongzhen 2 years ago committed by GitHub
parent e188855997
commit f1321052c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -79,6 +79,12 @@
<artifactId>jmh-generator-annprocess</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-common</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>

@ -20,6 +20,7 @@ package cn.hippo4j.agent.core.boot;
import cn.hippo4j.agent.core.logging.api.ILog;
import cn.hippo4j.agent.core.logging.api.LogManager;
import cn.hippo4j.agent.core.util.ConfigInitializer;
import lombok.extern.slf4j.Slf4j;
import java.util.Collections;
import java.util.HashSet;
@ -38,17 +39,21 @@ public class SpringBootConfigInitializer {
private static long PROPERTIES_LOAD_TIME;
private static Properties SPRING_PROPERTIES = null;
public static Properties SPRING_PROPERTIES = null;
private SpringBootConfigInitializer() {
}
public static boolean isSpringPropertiesEmpty() {
return SPRING_PROPERTIES == null || SPRING_PROPERTIES.isEmpty();
}
public static synchronized void initializeConfig(SpringBootConfig springBootConfig) {
if (SPRING_PROPERTIES != null) {
try {
LOG.info("initialize Spring Config Class {}.", springBootConfig.root());
ConfigInitializer.initialize(SPRING_PROPERTIES, springBootConfig.root());
ConfigInitializer.initialize(SPRING_PROPERTIES, springBootConfig.root(), true);
} catch (Throwable e) {
LOG.error(e, "Failed to set the agent settings {} to Config={} ", SPRING_PROPERTIES, springBootConfig.root());
}

@ -17,6 +17,7 @@
package cn.hippo4j.agent.core.conf;
import cn.hippo4j.agent.core.boot.SpringBootConfig;
import cn.hippo4j.agent.core.logging.core.LogLevel;
import cn.hippo4j.agent.core.logging.core.LogOutput;
import cn.hippo4j.agent.core.logging.core.ResolverType;
@ -358,6 +359,31 @@ public class Config {
* Mount the folders of the plugins. The folder path is relative to agent.jar.
*/
public static List<String> MOUNT = Arrays.asList("plugins", "activations");
public static class ThreadPool {
public static List<String> EXCLUDE_PACKAGE_PREFIX = Arrays.asList(
"java", "sun", "okhttp3", "retrofit2", "reactor",
"org.apache", "io.netty", "org.springframework", "com.ctrip", "com.google",
"io.undertow", "org.xnio", "org.jboss", "com.zaxxer", "org.redisson", "com.alibaba",
"com.netflix", "com.mysql", "rx.internal", "io.shardingjdbc", "org.drools", "org.elasticsearch",
"ch.qos.logback", "net.sf.ehcache");
}
public static class Apollo {
public static class App {
public static String ID;
}
public static String META;
public static class BootStrap {
public static boolean ENABLED = false;
public static List<String> NAMESPACES;
}
}
}
public static class Correlation {

@ -33,4 +33,7 @@ public class Constants {
public static String EVENT_LAYER_NAME = "GENERAL";
public static int NULL_VALUE = 0;
public static String SPRING_BOOT_CONFIG_PREFIX = "spring.dynamic.thread-pool";
}

@ -106,9 +106,9 @@ public class SnifferConfigInitializer {
Config.Agent.CLUSTER);
}
}
if (StringUtil.isEmpty(Config.Collector.BACKEND_SERVICE)) {
throw new ExceptionInInitializerError("`collector.backend_service` is missing.");
}
// if (StringUtil.isEmpty(Config.Collector.BACKEND_SERVICE)) {
// throw new ExceptionInInitializerError("`collector.backend_service` is missing.");
// }
if (Config.Plugin.PEER_MAX_LENGTH <= 3) {
LOGGER.warn(
"PEER_MAX_LENGTH configuration:{} error, the default value of 200 will be used.",

@ -0,0 +1,52 @@
/*
* 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.registry;
import cn.hippo4j.agent.core.logging.api.ILog;
import cn.hippo4j.agent.core.logging.api.LogManager;
import cn.hippo4j.common.config.ExecutorProperties;
import lombok.Data;
import java.util.concurrent.ThreadPoolExecutor;
@Data
public class AgentThreadPoolExecutorHolder {
private static final ILog LOGGER = LogManager.getLogger(AgentThreadPoolExecutorHolder.class);
public static final AgentThreadPoolExecutorHolder EMPTY = new AgentThreadPoolExecutorHolder();
private String executorName;
private ThreadPoolExecutor executor;
private ExecutorProperties properties;
public AgentThreadPoolExecutorHolder() {
}
public AgentThreadPoolExecutorHolder(String executorName, ThreadPoolExecutor executor, ExecutorProperties properties) {
this.executorName = executorName;
this.executor = executor;
this.properties = properties;
}
public boolean isEmpty() {
return this == EMPTY;
}
}

@ -0,0 +1,63 @@
/*
* 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.registry;
import cn.hippo4j.agent.core.logging.api.ILog;
import cn.hippo4j.agent.core.logging.api.LogManager;
import cn.hippo4j.common.config.ExecutorProperties;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
public class AgentThreadPoolInstanceRegistry {
private static final ILog LOGGER = LogManager.getLogger(AgentThreadPoolInstanceRegistry.class);
private final Map<String, AgentThreadPoolExecutorHolder> holderMap = new ConcurrentHashMap<>();
private volatile static AgentThreadPoolInstanceRegistry INSTANCE;
private AgentThreadPoolInstanceRegistry() {
}
public static AgentThreadPoolInstanceRegistry getInstance() {
if (INSTANCE == null) {
synchronized (AgentThreadPoolInstanceRegistry.class) {
if (INSTANCE == null) {
INSTANCE = new AgentThreadPoolInstanceRegistry();
}
}
}
return INSTANCE;
}
public Map<String, AgentThreadPoolExecutorHolder> getHolderMap() {
return holderMap;
}
public void putHolder(String executorName, ThreadPoolExecutor executor, ExecutorProperties properties) {
AgentThreadPoolExecutorHolder holder = new AgentThreadPoolExecutorHolder(executorName, executor, properties);
holderMap.put(executorName, holder);
}
public AgentThreadPoolExecutorHolder getHolder(String executorName) {
return Optional.ofNullable(holderMap.get(executorName)).orElse(AgentThreadPoolExecutorHolder.EMPTY);
}
}

@ -0,0 +1,27 @@
/*
* 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 AgentThreadPoolConstants {
String TOMCAT_NAME_PREFIX = "namePrefix";
String DUBBO_NAME_PREFIX = "mPrefix";
String DUBBO_THREAD_NAME = "DubboServerHandler";
String THREAD_POOL_NAME_DUBBO = "dubbo";
}

@ -41,4 +41,24 @@ public final class CollectionUtil {
public static boolean isEmpty(Collection collection) {
return collection == null || collection.isEmpty();
}
/**
* Is empty.
*
* @param map
* @return
*/
public static boolean isEmpty(Map<?, ?> map) {
return map == null || map.isEmpty();
}
/**
* Is not empty.
*
* @param map
* @return
*/
public static boolean isNotEmpty(Map<?, ?> map) {
return !isEmpty(map);
}
}

@ -30,14 +30,18 @@ import java.util.*;
public class ConfigInitializer {
public static void initialize(Properties properties, Class<?> rootConfigType) throws IllegalAccessException {
initNextLevel(properties, rootConfigType, new ConfigDesc());
initNextLevel(properties, rootConfigType, new ConfigDesc(), false);
}
public static void initialize(Properties properties, Class<?> rootConfigType, boolean isSpringProperties) throws IllegalAccessException {
initNextLevel(properties, rootConfigType, new ConfigDesc(), isSpringProperties);
}
private static void initNextLevel(Properties properties, Class<?> recentConfigType,
ConfigDesc parentDesc) throws IllegalArgumentException, IllegalAccessException {
ConfigDesc parentDesc, boolean isSpringProperties) throws IllegalArgumentException, IllegalAccessException {
for (Field field : recentConfigType.getFields()) {
if (Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())) {
String configKey = (parentDesc + "." + field.getName()).toLowerCase();
String configKey = (parentDesc + "." + (isSpringProperties ? field.getName().replace("_", "-") : field.getName())).toLowerCase();
Class<?> type = field.getType();
if (type.equals(Map.class)) {
@ -78,8 +82,10 @@ public class ConfigInitializer {
}
}
for (Class<?> innerConfiguration : recentConfigType.getClasses()) {
parentDesc.append(innerConfiguration.getSimpleName());
initNextLevel(properties, innerConfiguration, parentDesc);
String simpleName = innerConfiguration.getSimpleName();
String description = isSpringProperties ? simpleName.replace("_", "-") : simpleName;
parentDesc.append(description);
initNextLevel(properties, innerConfiguration, parentDesc, isSpringProperties);
parentDesc.removeLastDesc();
}
}

@ -0,0 +1,44 @@
/*
* 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;
import cn.hippo4j.agent.core.logging.api.ILog;
import cn.hippo4j.agent.core.logging.api.LogManager;
import java.lang.reflect.Field;
public class ExecutorNameUtil {
private static final ILog LOGGER = LogManager.getLogger(ExecutorNameUtil.class);
public static boolean isTomcatExecutor(Object threadFactory) {
try {
if ("org.apache.tomcat.util.threads.TaskThreadFactory".equals(threadFactory.getClass().getName())) {
Field namePrefixField = threadFactory.getClass().getDeclaredField(AgentThreadPoolConstants.TOMCAT_NAME_PREFIX);
namePrefixField.setAccessible(true);
String namePrefix = (String) namePrefixField.get(threadFactory);
if (RegexUtil.isTomcatNameMatch(namePrefix)) {
return true;
}
}
} catch (Throwable t) {
LOGGER.error("Fail to put tomcat executor", t);
}
return false;
}
}

@ -0,0 +1,43 @@
/*
* 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;
import cn.hippo4j.agent.core.logging.api.ILog;
import cn.hippo4j.agent.core.logging.api.LogManager;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
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();
List<Field> result = new ArrayList<>();
for (Field field : fields) {
if (field.getType().isAssignableFrom(declaredType) &&
Modifier.isStatic(field.getModifiers())) {
result.add(field);
}
}
return result;
}
}

@ -0,0 +1,31 @@
/*
* 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;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexUtil {
private static final String TOMCAT_NAME_PATTERN_STRING = "http\\S+nio\\S+-exec-";
private static final Pattern TOMCAT_NAME_PATTERN = Pattern.compile(TOMCAT_NAME_PATTERN_STRING);
public static boolean isTomcatNameMatch(String executorName) {
return TOMCAT_NAME_PATTERN.matcher(executorName).find();
}
}

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-agent-plugin</artifactId>
<version>${revision}</version>
</parent>
<artifactId>apollo-plugin</artifactId>
<properties>
<apollo.version>1.9.1</apollo.version>
</properties>
<dependencies>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>${apollo.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

@ -0,0 +1,37 @@
/*
* 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.apollo;
import cn.hippo4j.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import cn.hippo4j.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.ConfigFile;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import com.ctrip.framework.apollo.internals.DefaultConfig;
import com.ctrip.framework.apollo.model.ConfigChange;
import java.util.HashMap;
import java.util.Map;
public class DefaultConfigConstructorInterceptor implements InstanceConstructorInterceptor {
@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable {
}
}

@ -0,0 +1,45 @@
/*
* 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.apollo.boot;
import cn.hippo4j.agent.core.boot.BootService;
import cn.hippo4j.agent.core.boot.DefaultImplementor;
@DefaultImplementor
public class ApolloPluginBootService implements BootService {
@Override
public void prepare() throws Throwable {
}
@Override
public void boot() throws Throwable {
}
@Override
public void onComplete() throws Throwable {
}
@Override
public void shutdown() throws Throwable {
}
}

@ -0,0 +1,63 @@
/*
* 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.apollo.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 cn.hippo4j.agent.core.plugin.match.NameMatch;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import static net.bytebuddy.matcher.ElementMatchers.any;
public class ApolloInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final String ENHANCE_CLASS = "com.ctrip.framework.apollo.internals.DefaultConfig";
private static final String CONSTRUCTOR_INTERCEPT_CLASS = "cn.hippo4j.agent.plugin.apollo.DefaultConfigConstructorInterceptor";
@Override
protected ClassMatch enhanceClass() {
return NameMatch.byName(ENHANCE_CLASS);
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[]{
new ConstructorInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getConstructorMatcher() {
return any();
}
@Override
public String getConstructorInterceptor() {
return CONSTRUCTOR_INTERCEPT_CLASS;
}
}
};
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[0];
}
}

@ -0,0 +1,17 @@
# 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.
cn.hippo4j.agent.plugin.apollo.boot.ApolloPluginBootService

@ -0,0 +1,17 @@
# 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.
apollo-plugin=cn.hippo4j.agent.plugin.apollo.define.ApolloInstrumentation

@ -13,6 +13,8 @@
<packaging>pom</packaging>
<modules>
<module>spring-plugins</module>
<module>thread-pool-plugin</module>
<module>apollo-plugin</module>
</modules>
<properties>
@ -29,6 +31,21 @@
<ant-nodeps.version>1.8.1</ant-nodeps.version>
</properties>
<dependencies>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-agent-core</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>${bytebuddy.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>

@ -32,19 +32,4 @@
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-agent-core</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>${bytebuddy.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

@ -13,8 +13,21 @@
<properties>
<spring.boot.version>1.5.22.RELEASE</spring.boot.version>
<apollo.version>1.9.1</apollo.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.hippo4j</groupId>
@ -24,10 +37,30 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring.boot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>${apollo.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-config-spring-boot-1x-starter</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

@ -0,0 +1,45 @@
/*
* 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.boot.SpringBootConfig;
import java.util.Arrays;
import java.util.List;
public class ApolloSpringBootProperties {
public static class Spring {
public static class Dynamic {
@SpringBootConfig(root = ApolloSpringBootProperties.class)
public static class Thread_Pool {
@SpringBootConfig(root = ApolloSpringBootProperties.class)
public static class Apollo {
public static List<String> NAMESPACE = Arrays.asList("application");
}
public static String CONFIG_FILE_TYPE;
}
}
}
}

@ -17,27 +17,59 @@
package cn.hippo4j.agent.plugin.spring.boot.v1;
import cn.hippo4j.agent.core.boot.SpringBootConfigInitializer;
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;
import cn.hippo4j.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
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.plugin.spring.common.SpringPropertiesLoader;
import cn.hippo4j.common.executor.support.BlockingQueueTypeEnum;
import cn.hippo4j.common.executor.support.RejectedPolicyTypeEnum;
import cn.hippo4j.common.executor.support.ResizableCapacityLinkedBlockingQueue;
import cn.hippo4j.common.toolkit.CollectionUtil;
import cn.hippo4j.common.toolkit.MapUtil;
import cn.hippo4j.common.toolkit.ThreadPoolExecutorUtil;
import cn.hippo4j.config.springboot.starter.config.BootstrapConfigProperties;
import cn.hippo4j.common.config.ExecutorProperties;
import cn.hippo4j.config.springboot.starter.parser.ConfigFileTypeEnum;
import cn.hippo4j.config.springboot.starter.parser.ConfigParserHandler;
import cn.hippo4j.config.springboot.starter.support.GlobalCoreThreadPoolManage;
import cn.hippo4j.core.executor.DynamicThreadPoolExecutor;
import cn.hippo4j.message.request.ChangeParameterNotifyRequest;
import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.ConfigFile;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import com.ctrip.framework.apollo.model.ConfigChange;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.support.ResourceEditorRegistrar;
import org.springframework.boot.bind.CustomPropertyNamePatternsMatcher;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.boot.bind.RelaxedNames;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.*;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import static cn.hippo4j.agent.core.conf.Constants.SPRING_BOOT_CONFIG_PREFIX;
import static cn.hippo4j.common.constant.ChangeThreadPoolConstants.CHANGE_DELIMITER;
import static cn.hippo4j.common.constant.ChangeThreadPoolConstants.CHANGE_THREAD_POOL_TEXT;
import static cn.hippo4j.config.springboot1x.starter.refresher.SpringBoot1xBootstrapConfigPropertiesBinderAdapt.getNames;
public class EventPublishingFinishedInterceptor implements InstanceMethodsAroundInterceptor {
private static final ILog LOGGER = LogManager.getLogger(EventPublishingFinishedInterceptor.class);
private static final ILog FILE_LOGGER = LogManager.getLogger(EventPublishingFinishedInterceptor.class);
private static final Logger LOGGER = LoggerFactory.getLogger(EventPublishingFinishedInterceptor.class);
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
@ -48,9 +80,211 @@ public class EventPublishingFinishedInterceptor implements InstanceMethodsAround
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
ConfigurableApplicationContext context = (ConfigurableApplicationContext) allArguments[0];
SpringPropertiesLoader.loadSpringProperties(context.getEnvironment());
List<String> apolloNamespaces = ApolloSpringBootProperties.Spring.Dynamic.Thread_Pool.Apollo.NAMESPACE;
String namespace = apolloNamespaces.get(0);
String configFileType = ApolloSpringBootProperties.Spring.Dynamic.Thread_Pool.CONFIG_FILE_TYPE;
com.ctrip.framework.apollo.Config config = ConfigService.getConfig(String.format("%s.%s", namespace, configFileType));
ConfigChangeListener configChangeListener = configChangeEvent -> {
String replacedNamespace = namespace.replaceAll("." + configFileType, "");
ConfigFileFormat configFileFormat = ConfigFileFormat.fromString(configFileType);
ConfigFile configFile = ConfigService.getConfigFile(replacedNamespace, configFileFormat);
Map<String, Object> newChangeValueMap = new HashMap<>();
configChangeEvent.changedKeys().stream().filter(each -> each.contains(SPRING_BOOT_CONFIG_PREFIX)).forEach(each -> {
ConfigChange change = configChangeEvent.getChange(each);
String newValue = change.getNewValue();
newChangeValueMap.put(each, newValue);
});
dynamicRefresh(configFile.getContent(), newChangeValueMap, context);
};
config.addChangeListener(configChangeListener);
LOGGER.info("Dynamic thread pool refresher, add apollo listener success. namespace: {}", namespace);
return ret;
}
public BootstrapConfigProperties bindProperties(Map<Object, Object> configInfo, ApplicationContext applicationContext) {
BootstrapConfigProperties bindableCoreProperties = new BootstrapConfigProperties();
if (MapUtil.isEmpty(configInfo)) {
return bindableCoreProperties;
}
RelaxedNames relaxedNames = new RelaxedNames(BootstrapConfigProperties.PREFIX);
Set<String> names = getNames(bindableCoreProperties, relaxedNames);
Map<String, Object> stringConfigInfo = new HashMap<>(configInfo.size());
configInfo.forEach((key, value) -> stringConfigInfo.put(key.toString(), value));
MapPropertySource test = new MapPropertySource("Hippo4j", stringConfigInfo);
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(test);
PropertyValues propertyValues = CustomPropertyNamePatternsMatcher.getPropertySourcesPropertyValues(names, propertySources);
RelaxedDataBinder dataBinder = new RelaxedDataBinder(bindableCoreProperties, BootstrapConfigProperties.PREFIX);
dataBinder.setAutoGrowCollectionLimit(Integer.MAX_VALUE);
dataBinder.setIgnoreNestedProperties(false);
dataBinder.setIgnoreInvalidFields(false);
dataBinder.setIgnoreUnknownFields(true);
ResourceEditorRegistrar resourceEditorRegistrar = new ResourceEditorRegistrar(applicationContext, applicationContext.getEnvironment());
resourceEditorRegistrar.registerCustomEditors(dataBinder);
dataBinder.bind(propertyValues);
return bindableCoreProperties;
}
public void dynamicRefresh(String configContent, Map<String, Object> newValueChangeMap, ApplicationContext context) {
try {
String configFileType = ApolloSpringBootProperties.Spring.Dynamic.Thread_Pool.CONFIG_FILE_TYPE;
Map<Object, Object> afterConfigMap = ConfigParserHandler.getInstance().parseConfig(configContent,
ConfigFileTypeEnum.of(configFileType));
if (CollectionUtil.isNotEmpty(newValueChangeMap)) {
Optional.ofNullable(afterConfigMap).ifPresent(each -> each.putAll(newValueChangeMap));
}
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)) {
continue;
}
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);
LOGGER.info(CHANGE_THREAD_POOL_TEXT,
threadPoolId,
String.format(CHANGE_DELIMITER, beforeProperties.getCorePoolSize(), changeRequest.getNowCorePoolSize()),
String.format(CHANGE_DELIMITER, beforeProperties.getMaximumPoolSize(), changeRequest.getNowMaximumPoolSize()),
String.format(CHANGE_DELIMITER, beforeProperties.getQueueCapacity(), changeRequest.getNowQueueCapacity()),
String.format(CHANGE_DELIMITER, beforeProperties.getKeepAliveTime(), changeRequest.getNowKeepAliveTime()),
String.format(CHANGE_DELIMITER, beforeProperties.getExecuteTimeOut(), changeRequest.getNowExecuteTimeOut()),
String.format(CHANGE_DELIMITER, beforeProperties.getRejectedHandler(), changeRequest.getNowRejectedName()),
String.format(CHANGE_DELIMITER, beforeProperties.getAllowCoreThreadTimeOut(), changeRequest.getNowAllowsCoreThreadTimeOut()));
}
} catch (Exception ex) {
LOGGER.error("[Hippo4j-Agent] config mode dynamic refresh failed.", ex);
}
}
/**
* Dynamic refresh pool.
*/
private void dynamicRefreshPool(String threadPoolId, 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());
} else {
if (afterProperties.getMaximumPoolSize() != null) {
executor.setMaximumPoolSize(afterProperties.getMaximumPoolSize());
}
if (afterProperties.getCorePoolSize() != null) {
executor.setCorePoolSize(afterProperties.getCorePoolSize());
}
}
if (afterProperties.getAllowCoreThreadTimeOut() != null && !Objects.equals(beforeProperties.getAllowCoreThreadTimeOut(), afterProperties.getAllowCoreThreadTimeOut())) {
executor.allowCoreThreadTimeOut(afterProperties.getAllowCoreThreadTimeOut());
}
if (afterProperties.getExecuteTimeOut() != null && !Objects.equals(beforeProperties.getExecuteTimeOut(), afterProperties.getExecuteTimeOut())) {
if (executor instanceof DynamicThreadPoolExecutor) {
((DynamicThreadPoolExecutor) executor).setExecuteTimeOut(afterProperties.getExecuteTimeOut());
}
}
if (afterProperties.getRejectedHandler() != null && !Objects.equals(beforeProperties.getRejectedHandler(), afterProperties.getRejectedHandler())) {
RejectedExecutionHandler rejectedExecutionHandler = RejectedPolicyTypeEnum.createPolicy(afterProperties.getRejectedHandler());
executor.setRejectedExecutionHandler(rejectedExecutionHandler);
}
if (afterProperties.getKeepAliveTime() != null && !Objects.equals(beforeProperties.getKeepAliveTime(), afterProperties.getKeepAliveTime())) {
executor.setKeepAliveTime(afterProperties.getKeepAliveTime(), TimeUnit.SECONDS);
}
if (afterProperties.getQueueCapacity() != null && !Objects.equals(beforeProperties.getQueueCapacity(), afterProperties.getQueueCapacity())
&& Objects.equals(BlockingQueueTypeEnum.RESIZABLE_LINKED_BLOCKING_QUEUE.getName(), executor.getQueue().getClass().getSimpleName())) {
if (executor.getQueue() instanceof ResizableCapacityLinkedBlockingQueue) {
ResizableCapacityLinkedBlockingQueue<?> queue = (ResizableCapacityLinkedBlockingQueue<?>) executor.getQueue();
queue.setCapacity(afterProperties.getQueueCapacity());
} else {
LOGGER.warn("The queue length cannot be modified. Queue type mismatch. Current queue type: {}", executor.getQueue().getClass().getSimpleName());
}
}
}
/**
* Fail default executor properties.
*
* @param beforeProperties old properties
* @param properties 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()))
.threadPoolId(beforeProperties.getThreadPoolId())
.build();
}
/**
* Construct change parameter notify request instance.
*
* @param beforeProperties old properties
* @param properties new properties
* @return instance
*/
private ChangeParameterNotifyRequest buildChangeRequest(ExecutorProperties beforeProperties, ExecutorProperties properties) {
ChangeParameterNotifyRequest changeParameterNotifyRequest = ChangeParameterNotifyRequest.builder()
.beforeCorePoolSize(beforeProperties.getCorePoolSize())
.beforeMaximumPoolSize(beforeProperties.getMaximumPoolSize())
.beforeAllowsCoreThreadTimeOut(beforeProperties.getAllowCoreThreadTimeOut())
.beforeKeepAliveTime(beforeProperties.getKeepAliveTime())
.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()))
.build();
changeParameterNotifyRequest.setThreadPoolId(beforeProperties.getThreadPoolId());
return changeParameterNotifyRequest;
}
/**
* Check consistency.
*
* @param threadPoolId
* @param properties
*/
private boolean checkConsistency(String threadPoolId, ExecutorProperties properties) {
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()))
||
((properties.getQueueCapacity() != null && !Objects.equals(beforeProperties.getQueueCapacity(), properties.getQueueCapacity())
&& Objects.equals(BlockingQueueTypeEnum.RESIZABLE_LINKED_BLOCKING_QUEUE.getName(), executor.getQueue().getClass().getSimpleName())));
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {

@ -0,0 +1,51 @@
/*
* 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.plugin.spring.common.SpringEnvironmentSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.ConfigurableEnvironment;
import java.lang.reflect.Method;
public class EventPublishingRunListenerEnvironmentPreparedInterceptor implements InstanceMethodsAroundInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(EventPublishingRunListenerEnvironmentPreparedInterceptor.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 {
ConfigurableEnvironment environment = (ConfigurableEnvironment) allArguments[0];
SpringEnvironmentSupport.disableNonAgentSwitch(environment);
LOGGER.info("[Hippo4j-Agent] Switch off in non-Agent mode.");
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
}
}

@ -32,6 +32,7 @@ public class EventPublishingRunListenerInstrumentation extends ClassInstanceMeth
private static final String ENHANCE_CLASS = "org.springframework.boot.context.event.EventPublishingRunListener";
private static final String EVENT_PUBLISHING_FINISHED_INTERCEPTOR = "cn.hippo4j.agent.plugin.spring.boot.v1.EventPublishingFinishedInterceptor";
private static final String EVENT_PUBLISHING_ENVIRONMENT_PREPARED_INTERCEPTOR = "cn.hippo4j.agent.plugin.spring.boot.v1.EventPublishingRunListenerEnvironmentPreparedInterceptor";
@Override
protected ClassMatch enhanceClass() {
@ -58,6 +59,23 @@ public class EventPublishingRunListenerInstrumentation extends ClassInstanceMeth
return EVENT_PUBLISHING_FINISHED_INTERCEPTOR;
}
@Override
public boolean isOverrideArgs() {
return false;
}
},
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("environmentPrepared");
}
@Override
public String getMethodsInterceptor() {
return EVENT_PUBLISHING_ENVIRONMENT_PREPARED_INTERCEPTOR;
}
@Override
public boolean isOverrideArgs() {
return false;

@ -0,0 +1,34 @@
/*
* 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.common;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import java.util.HashMap;
import java.util.Map;
public class SpringEnvironmentSupport {
public static void disableNonAgentSwitch(ConfigurableEnvironment environment) {
Map<String, Object> map = new HashMap<>();
map.put("spring.dynamic.thread-pool.enable", false); // Switch off in non-Agent mode
MapPropertySource propertySource = new MapPropertySource("Hippo4j-Agent-Properties", map);
environment.getPropertySources().addFirst(propertySource);
}
}

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-agent-plugin</artifactId>
<version>${revision}</version>
</parent>
<artifactId>thread-pool-plugin</artifactId>
<dependencies>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-core</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

@ -0,0 +1,146 @@
/*
* 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.thread.pool;
import cn.hippo4j.agent.core.conf.Config;
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;
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.model.register.DynamicThreadPoolRegisterParameter;
import cn.hippo4j.common.model.register.DynamicThreadPoolRegisterWrapper;
import cn.hippo4j.common.model.register.notify.DynamicThreadPoolRegisterCoreNotifyParameter;
import cn.hippo4j.common.toolkit.BooleanUtil;
import cn.hippo4j.core.executor.DynamicThreadPoolWrapper;
import cn.hippo4j.core.executor.manage.GlobalThreadPoolManage;
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 {
private static final ILog LOGGER = LogManager.getLogger(ThreadPoolExecutorConstructorMethodInterceptor.class);
private static final List<String> EXCLUDE_STACK_TRACE_ELEMENT_CLASS_PREFIX = Arrays.asList("java", "cn.hippo4j.agent");
@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable {
List<StackTraceElement> stackTraceElements = getStackTraceElements();
if (CollectionUtil.isEmpty(stackTraceElements)) {
return;
}
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);
}
private List<StackTraceElement> getStackTraceElements() {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
int i;
for (i = 0; i < stackTraceElements.length; i++) {
String fullClassName = stackTraceElements[i].getClassName();
if (isBusinessStackTraceClassName(fullClassName)) {
if (isExcludeThreadPoolClass(fullClassName)) {
return Collections.emptyList();
} else {
break;
}
}
}
List<StackTraceElement> result = new ArrayList<>(3); // Find up to three layers
for (int j = 0; i < stackTraceElements.length && j < 3; i++, j++) {
String fullClassName = stackTraceElements[i].getClassName();
if (isExcludeThreadPoolClass(fullClassName)) {
break;
} else {
result.add(stackTraceElements[i]);
}
}
return result;
}
private boolean isBusinessStackTraceClassName(String className) {
for (String prefix : EXCLUDE_STACK_TRACE_ELEMENT_CLASS_PREFIX) {
if (className.startsWith(prefix)) {
return false;
}
}
return true;
}
private boolean isExcludeThreadPoolClass(String className) {
if (StringUtil.isBlank(className)) {
return true;
}
List<String> excludePackagePrefix = Config.Plugin.ThreadPool.EXCLUDE_PACKAGE_PREFIX;
for (String excludePrefix : excludePackagePrefix) {
if (className.startsWith(excludePrefix)) {
return true;
}
}
return false;
}
}

@ -0,0 +1,73 @@
/*
* 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.thread.pool.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 cn.hippo4j.agent.core.plugin.match.NameMatch;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
public class ThreadPoolExecutorInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final String ENHANCE_CLASS = "java.util.concurrent.ThreadPoolExecutor";
private static final String CONSTRUCTOR_INTERCEPT_CLASS = "cn.hippo4j.agent.plugin.thread.pool.ThreadPoolExecutorConstructorMethodInterceptor";
private static final int CONSTRUCTOR_INTERCEPT_PARAMETER_LENGTH = 7;
@Override
protected ClassMatch enhanceClass() {
return NameMatch.byName(ENHANCE_CLASS);
}
@Override
public boolean isBootstrapInstrumentation() {
return true;
}
/**
* The constructor method that only intercepts all parameters prevents repeated interception.
*/
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[]{
new ConstructorInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getConstructorMatcher() {
return takesArguments(CONSTRUCTOR_INTERCEPT_PARAMETER_LENGTH);
}
@Override
public String getConstructorInterceptor() {
return CONSTRUCTOR_INTERCEPT_CLASS;
}
}
};
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[0];
}
}

@ -0,0 +1,17 @@
# 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.
thread-pool-plugin=cn.hippo4j.agent.plugin.thread.pool.define.ThreadPoolExecutorInstrumentation

@ -17,6 +17,8 @@
package cn.hippo4j.common.api;
import cn.hippo4j.common.config.ExecutorNotifyProperties;
/**
* Interface for thread pool configuration.
*/

@ -118,7 +118,7 @@ public interface ThreadPoolCheckAlarm extends CommandLineRunner {
*/
@Override
public void asyncSendRejectedAlarm(String threadPoolId) {
log.info("Ignore async send rejected alarm for ExecuteService '{}'", threadPoolId);
log.debug("Ignore async send rejected alarm for ExecuteService '{}'", threadPoolId);
}
/**
@ -131,7 +131,7 @@ public interface ThreadPoolCheckAlarm extends CommandLineRunner {
*/
@Override
public void asyncSendExecuteTimeOutAlarm(String threadPoolId, long executeTime, long executeTimeOut, ThreadPoolExecutor threadPoolExecutor) {
log.info("Ignore async send execute time out alarm for ExecuteService '{}'", threadPoolId);
log.debug("Ignore async send execute time out alarm for ExecuteService '{}'", threadPoolId);
}
@Override

@ -15,7 +15,7 @@
* limitations under the License.
*/
package cn.hippo4j.common.api;
package cn.hippo4j.common.config;
import lombok.AllArgsConstructor;
import lombok.Data;

@ -15,9 +15,8 @@
* limitations under the License.
*/
package cn.hippo4j.config.springboot.starter.config;
package cn.hippo4j.common.config;
import cn.hippo4j.common.api.ExecutorNotifyProperties;
import cn.hippo4j.common.api.IExecutorProperties;
import lombok.AllArgsConstructor;
import lombok.Builder;

@ -113,4 +113,6 @@ public class Constants {
public static final int HTTP_EXECUTE_TIMEOUT = 5000;
public static final String CLIENT_VERSION = "Client-Version";
public static final String CONFIGURATION_PROPERTIES_PREFIX = "spring.dynamic.thread-pool";
}

@ -1,3 +1,20 @@
/*
* 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.core.proxy;
import cn.hippo4j.common.api.ThreadPoolCheckAlarm;
@ -42,7 +59,7 @@ public class RejectedProxyInvocationHandlerTest {
@Test
public void testInvoke() throws Throwable {
Object[] mockArgs = new Object[] {"arg1", "arg2"};
Object[] mockArgs = new Object[]{"arg1", "arg2"};
MockedStatic<ApplicationContextHolder> mockedStatic = Mockito.mockStatic(ApplicationContextHolder.class);
mockedStatic.when(ApplicationContextHolder::getInstance).thenReturn(applicationContext);
mockedStatic.when(() -> ApplicationContextHolder.getBean(ThreadPoolCheckAlarm.class)).thenReturn(mockAlarmHandler);

@ -50,3 +50,21 @@ spring.dynamic.thread-pool.executors[1].active-alarm=80
spring.dynamic.thread-pool.executors[1].capacity-alarm=80
spring.dynamic.thread-pool.executors[1].notify.interval=8
spring.dynamic.thread-pool.executors[1].notify.receives=chen.ma
# For hippo4j-agent mode (Optional)
spring.dynamic.thread-pool.executors[2].thread-pool-id = cn.hippo4j.example.core.config.DynamicThreadPoolConfig#FIELD1
spring.dynamic.thread-pool.executors[2].thread-name-prefix = DynamicThreadPoolConfig#FIELD1
spring.dynamic.thread-pool.executors[2].core-pool-size = 2
spring.dynamic.thread-pool.executors[2].maximum-pool-size = 52
spring.dynamic.thread-pool.executors[2].queue-capacity = 1024
spring.dynamic.thread-pool.executors[2].blocking-queue = ResizableCapacityLinkedBlockingQueue
spring.dynamic.thread-pool.executors[2].execute-time-out = 800
spring.dynamic.thread-pool.executors[2].rejected-handler = AbortPolicy
spring.dynamic.thread-pool.executors[2].keep-alive-time = 6691
spring.dynamic.thread-pool.executors[2].allow-core-thread-time-out = true
spring.dynamic.thread-pool.executors[2].alarm = true
spring.dynamic.thread-pool.executors[2].active-alarm = 80
spring.dynamic.thread-pool.executors[2].capacity-alarm = 80
spring.dynamic.thread-pool.executors[2].notify.interval = 8
spring.dynamic.thread-pool.executors[2].notify.receives = nobodyiam

@ -28,8 +28,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.*;
import static cn.hippo4j.common.constant.Constants.AVAILABLE_PROCESSORS;
import static cn.hippo4j.example.core.constant.GlobalTestConstant.MESSAGE_CONSUME;
@ -42,6 +41,12 @@ import static cn.hippo4j.example.core.constant.GlobalTestConstant.MESSAGE_PRODUC
@Configuration
public class DynamicThreadPoolConfig {
public static final ThreadPoolExecutor FIELD1 = new ThreadPoolExecutor(10, 20,
1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(20));
public static final ThreadPoolExecutor FIELD2 = new ThreadPoolExecutor(10, 20,
1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(20));
@Bean
@DynamicThreadPool
public Executor messageConsumeTtlDynamicThreadPool() {

@ -29,6 +29,7 @@ import org.apache.catalina.Server;
import org.apache.catalina.startup.Tomcat;
import org.eclipse.jetty.webapp.WebAppContext;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
@ -47,6 +48,7 @@ public class WebThreadPoolHandlerConfiguration1x {
@Configuration
@ConditionalOnClass({Servlet.class, Tomcat.class})
@ConditionalOnBean(WebThreadPoolRunStateHandler.class)
@ConditionalOnMissingBean(value = WebThreadPoolService.class, search = SearchStrategy.CURRENT)
static class EmbeddedTomcat {
@ -64,6 +66,7 @@ public class WebThreadPoolHandlerConfiguration1x {
*/
@Configuration
@ConditionalOnClass({Servlet.class, Server.class, Loader.class, WebAppContext.class})
@ConditionalOnBean(WebThreadPoolRunStateHandler.class)
@ConditionalOnMissingBean(value = WebThreadPoolService.class, search = SearchStrategy.CURRENT)
static class EmbeddedJetty {
@ -78,6 +81,7 @@ public class WebThreadPoolHandlerConfiguration1x {
*/
@Configuration
@ConditionalOnClass({Servlet.class, Undertow.class, SslClientAuthMode.class})
@ConditionalOnBean(WebThreadPoolRunStateHandler.class)
@ConditionalOnMissingBean(value = WebThreadPoolService.class, search = SearchStrategy.CURRENT)
static class EmbeddedUndertow {

@ -73,7 +73,7 @@ public class SpringBoot1xBootstrapConfigPropertiesBinderAdapt implements Applica
return bindableCoreProperties;
}
private static Set<String> getNames(Object target, Iterable<String> prefixes) {
public static Set<String> getNames(Object target, Iterable<String> prefixes) {
Set<String> names = new LinkedHashSet<>();
if (target != null) {
PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(target.getClass());

@ -17,6 +17,7 @@
package cn.hippo4j.config.springboot.starter.config;
import cn.hippo4j.common.config.ExecutorProperties;
import cn.hippo4j.config.springboot.starter.parser.ConfigFileTypeEnum;
import cn.hippo4j.core.config.BootstrapPropertiesInterface;
import lombok.Getter;
@ -24,7 +25,6 @@ import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@ -17,7 +17,7 @@
package cn.hippo4j.config.springboot.starter.config;
import cn.hippo4j.common.api.ExecutorNotifyProperties;
import cn.hippo4j.common.config.ExecutorNotifyProperties;
import cn.hippo4j.common.api.IExecutorProperties;
import lombok.Data;

@ -18,8 +18,9 @@
package cn.hippo4j.config.springboot.starter.notify;
import cn.hippo4j.adapter.web.WebThreadPoolService;
import cn.hippo4j.common.api.ExecutorNotifyProperties;
import cn.hippo4j.common.config.ExecutorNotifyProperties;
import cn.hippo4j.common.api.IExecutorProperties;
import cn.hippo4j.common.config.ExecutorProperties;
import cn.hippo4j.common.toolkit.CollectionUtil;
import cn.hippo4j.common.toolkit.StringUtil;
import cn.hippo4j.config.springboot.starter.config.*;

@ -24,13 +24,12 @@ import cn.hippo4j.common.executor.support.ResizableCapacityLinkedBlockingQueue;
import cn.hippo4j.common.toolkit.CollectionUtil;
import cn.hippo4j.common.toolkit.ThreadPoolExecutorUtil;
import cn.hippo4j.config.springboot.starter.config.BootstrapConfigProperties;
import cn.hippo4j.config.springboot.starter.config.ExecutorProperties;
import cn.hippo4j.common.config.ExecutorProperties;
import cn.hippo4j.config.springboot.starter.notify.ConfigModeNotifyConfigBuilder;
import cn.hippo4j.config.springboot.starter.support.GlobalCoreThreadPoolManage;
import cn.hippo4j.core.executor.DynamicThreadPoolExecutor;
import cn.hippo4j.core.executor.manage.GlobalThreadPoolManage;
import cn.hippo4j.message.dto.NotifyConfigDTO;
import cn.hippo4j.message.enums.NotifyTypeEnum;
import cn.hippo4j.message.request.ChangeParameterNotifyRequest;
import cn.hippo4j.message.service.GlobalNotifyAlarmManage;
import cn.hippo4j.message.service.Hippo4jBaseSendMessageService;

@ -19,7 +19,7 @@ package cn.hippo4j.config.springboot.starter.refresher.event;
import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hippo4j.config.springboot.starter.config.BootstrapConfigProperties;
import cn.hippo4j.config.springboot.starter.config.ExecutorProperties;
import cn.hippo4j.common.config.ExecutorProperties;
import cn.hippo4j.config.springboot.starter.notify.ConfigModeNotifyConfigBuilder;
import cn.hippo4j.core.executor.DynamicThreadPoolWrapper;
import cn.hippo4j.core.executor.manage.GlobalThreadPoolManage;

@ -23,7 +23,7 @@ import cn.hippo4j.common.model.register.DynamicThreadPoolRegisterParameter;
import cn.hippo4j.common.model.register.DynamicThreadPoolRegisterWrapper;
import cn.hippo4j.common.model.register.notify.DynamicThreadPoolRegisterCoreNotifyParameter;
import cn.hippo4j.common.toolkit.BooleanUtil;
import cn.hippo4j.config.springboot.starter.config.ExecutorProperties;
import cn.hippo4j.common.config.ExecutorProperties;
import cn.hippo4j.core.executor.DynamicThreadPoolWrapper;
import cn.hippo4j.core.executor.manage.GlobalThreadPoolManage;
import cn.hippo4j.core.executor.support.service.AbstractDynamicThreadPoolService;

@ -23,8 +23,8 @@ import cn.hippo4j.common.executor.support.RejectedPolicyTypeEnum;
import cn.hippo4j.common.toolkit.ReflectUtil;
import cn.hippo4j.common.toolkit.StringUtil;
import cn.hippo4j.config.springboot.starter.config.BootstrapConfigProperties;
import cn.hippo4j.common.api.ExecutorNotifyProperties;
import cn.hippo4j.config.springboot.starter.config.ExecutorProperties;
import cn.hippo4j.common.config.ExecutorNotifyProperties;
import cn.hippo4j.common.config.ExecutorProperties;
import cn.hippo4j.core.executor.DynamicThreadPool;
import cn.hippo4j.core.executor.DynamicThreadPoolExecutor;
import cn.hippo4j.core.executor.DynamicThreadPoolWrapper;

@ -17,7 +17,7 @@
package cn.hippo4j.config.springboot.starter.support;
import cn.hippo4j.config.springboot.starter.config.ExecutorProperties;
import cn.hippo4j.common.config.ExecutorProperties;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@ -17,10 +17,12 @@
package cn.hippo4j.springboot.starter.monitor.elasticsearch;
import cn.hippo4j.common.constant.Constants;
import cn.hippo4j.monitor.elasticsearch.AdapterThreadPoolElasticSearchMonitorHandler;
import cn.hippo4j.monitor.elasticsearch.DynamicThreadPoolElasticSearchMonitorHandler;
import cn.hippo4j.monitor.elasticsearch.WebThreadPoolElasticSearchMonitorHandler;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -29,6 +31,7 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
@ConditionalOnExpression("'${spring.dynamic.thread-pool.monitor.collect-types:}'.contains('elasticsearch')")
@ConditionalOnProperty(prefix = Constants.CONFIGURATION_PROPERTIES_PREFIX, value = "enable", matchIfMissing = true, havingValue = "true")
public class ElasticSearchMonitorAutoConfiguration {
@Bean

@ -18,11 +18,13 @@
package cn.hippo4j.springboot.starter.monitor.local.log;
import cn.hippo4j.adapter.web.WebThreadPoolService;
import cn.hippo4j.common.constant.Constants;
import cn.hippo4j.monitor.local.log.AdapterThreadPoolLocalLogMonitorHandler;
import cn.hippo4j.monitor.local.log.DynamicThreadPoolLocalLogMonitorHandler;
import cn.hippo4j.monitor.local.log.WebThreadPoolLocalLogMonitorHandler;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -31,6 +33,7 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
@ConditionalOnExpression("'${spring.dynamic.thread-pool.monitor.collect-types:}'.contains('log')")
@ConditionalOnProperty(prefix = Constants.CONFIGURATION_PROPERTIES_PREFIX, value = "enable", matchIfMissing = true, havingValue = "true")
public class LocalLogMonitorAutoConfiguration {
@Bean

@ -18,11 +18,13 @@
package cn.hippo4j.springboot.starter.monitor.micrometer;
import cn.hippo4j.adapter.web.WebThreadPoolService;
import cn.hippo4j.common.constant.Constants;
import cn.hippo4j.monitor.micrometer.AdapterThreadPoolMicrometerMonitorHandler;
import cn.hippo4j.monitor.micrometer.DynamicThreadPoolMicrometerMonitorHandler;
import cn.hippo4j.monitor.micrometer.WebThreadPoolMicrometerMonitorHandler;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -31,6 +33,7 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
@ConditionalOnExpression("'${spring.dynamic.thread-pool.monitor.collect-types:}'.contains('micrometer')")
@ConditionalOnProperty(prefix = Constants.CONFIGURATION_PROPERTIES_PREFIX, value = "enable", matchIfMissing = true, havingValue = "true")
public class MicrometerMonitorAutoConfiguration {
@Bean

@ -17,6 +17,7 @@
package cn.hippo4j.springboot.starter.config;
import cn.hippo4j.common.constant.Constants;
import cn.hippo4j.core.config.BootstrapPropertiesInterface;
import lombok.Getter;
import lombok.Setter;
@ -29,11 +30,9 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
@Slf4j
@Getter
@Setter
@ConfigurationProperties(prefix = BootstrapProperties.PREFIX)
@ConfigurationProperties(prefix = Constants.CONFIGURATION_PROPERTIES_PREFIX)
public class BootstrapProperties implements BootstrapPropertiesInterface {
public static final String PREFIX = "spring.dynamic.thread-pool";
/**
* Username
*/

@ -24,6 +24,7 @@ import cn.hippo4j.common.api.ThreadPoolCheckAlarm;
import cn.hippo4j.common.api.ThreadPoolConfigChange;
import cn.hippo4j.common.api.ThreadPoolDynamicRefresh;
import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hippo4j.common.constant.Constants;
import cn.hippo4j.core.config.UtilAutoConfiguration;
import cn.hippo4j.core.enable.MarkerConfiguration;
import cn.hippo4j.core.executor.state.ThreadPoolRunStateHandler;
@ -90,7 +91,7 @@ import org.springframework.core.env.ConfigurableEnvironment;
@AllArgsConstructor
@ConditionalOnBean(MarkerConfiguration.Marker.class)
@EnableConfigurationProperties(BootstrapProperties.class)
@ConditionalOnProperty(prefix = BootstrapProperties.PREFIX, value = "enable", matchIfMissing = true, havingValue = "true")
@ConditionalOnProperty(prefix = Constants.CONFIGURATION_PROPERTIES_PREFIX, value = "enable", matchIfMissing = true, havingValue = "true")
@ImportAutoConfiguration({WebAdapterConfiguration.class, NettyClientConfiguration.class, DiscoveryConfiguration.class, MessageConfiguration.class, UtilAutoConfiguration.class})
public class DynamicThreadPoolAutoConfiguration {

@ -17,6 +17,7 @@
package cn.hippo4j.springboot.starter.config;
import cn.hippo4j.common.constant.Constants;
import cn.hippo4j.springboot.starter.monitor.send.netty.NettyConnectSender;
import cn.hippo4j.springboot.starter.monitor.send.MessageSender;
import cn.hippo4j.springboot.starter.remote.ServerNettyAgent;
@ -26,7 +27,7 @@ import org.springframework.context.annotation.Bean;
/**
* Netty client configuration.
*/
@ConditionalOnProperty(prefix = BootstrapProperties.PREFIX, name = "report-type", havingValue = "netty")
@ConditionalOnProperty(prefix = Constants.CONFIGURATION_PROPERTIES_PREFIX, name = "report-type", havingValue = "netty")
public class NettyClientConfiguration {
@Bean

Loading…
Cancel
Save