diff --git a/hippo4j-agent/hippo4j-agent-core/pom.xml b/hippo4j-agent/hippo4j-agent-core/pom.xml index e158237c..e5d711ec 100644 --- a/hippo4j-agent/hippo4j-agent-core/pom.xml +++ b/hippo4j-agent/hippo4j-agent-core/pom.xml @@ -79,6 +79,12 @@ jmh-generator-annprocess test + + cn.hippo4j + hippo4j-common + ${project.version} + provided + diff --git a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/boot/SpringBootConfigInitializer.java b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/boot/SpringBootConfigInitializer.java index 66d148a8..3fe8d1e0 100644 --- a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/boot/SpringBootConfigInitializer.java +++ b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/boot/SpringBootConfigInitializer.java @@ -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()); } diff --git a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/conf/Config.java b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/conf/Config.java index ee8d3d0b..0321ea43 100755 --- a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/conf/Config.java +++ b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/conf/Config.java @@ -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 MOUNT = Arrays.asList("plugins", "activations"); + + public static class ThreadPool { + + public static List 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 NAMESPACES; + } + } } public static class Correlation { diff --git a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/conf/Constants.java b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/conf/Constants.java index 26433f2e..25f3d7bb 100644 --- a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/conf/Constants.java +++ b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/conf/Constants.java @@ -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"; + } diff --git a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/conf/SnifferConfigInitializer.java b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/conf/SnifferConfigInitializer.java index b71ed425..6db4e6b4 100644 --- a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/conf/SnifferConfigInitializer.java +++ b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/conf/SnifferConfigInitializer.java @@ -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.", diff --git a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/registry/AgentThreadPoolExecutorHolder.java b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/registry/AgentThreadPoolExecutorHolder.java new file mode 100644 index 00000000..deccaa59 --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/registry/AgentThreadPoolExecutorHolder.java @@ -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; + } +} diff --git a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/registry/AgentThreadPoolInstanceRegistry.java b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/registry/AgentThreadPoolInstanceRegistry.java new file mode 100644 index 00000000..b70228c3 --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/registry/AgentThreadPoolInstanceRegistry.java @@ -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 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 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); + } +} diff --git a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/AgentThreadPoolConstants.java b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/AgentThreadPoolConstants.java new file mode 100644 index 00000000..bdfbdaac --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/AgentThreadPoolConstants.java @@ -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"; + +} diff --git a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/CollectionUtil.java b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/CollectionUtil.java index 0037ae76..587c84f8 100644 --- a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/CollectionUtil.java +++ b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/CollectionUtil.java @@ -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); + } } diff --git a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/ConfigInitializer.java b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/ConfigInitializer.java index 3bb87ccd..8ebb4c81 100644 --- a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/ConfigInitializer.java +++ b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/ConfigInitializer.java @@ -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(); } } diff --git a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/ExecutorNameUtil.java b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/ExecutorNameUtil.java new file mode 100644 index 00000000..7a597187 --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/ExecutorNameUtil.java @@ -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; + } +} diff --git a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/ReflectUtil.java b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/ReflectUtil.java new file mode 100644 index 00000000..3a59b535 --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/ReflectUtil.java @@ -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 getStaticFieldsFromType(Class clazz, Class declaredType) { + Field[] fields = clazz.getFields(); + List result = new ArrayList<>(); + for (Field field : fields) { + if (field.getType().isAssignableFrom(declaredType) && + Modifier.isStatic(field.getModifiers())) { + result.add(field); + } + } + return result; + } +} diff --git a/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/RegexUtil.java b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/RegexUtil.java new file mode 100644 index 00000000..7d01353b --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-core/src/main/java/cn/hippo4j/agent/core/util/RegexUtil.java @@ -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(); + } +} diff --git a/hippo4j-agent/hippo4j-agent-plugin/apollo-plugin/pom.xml b/hippo4j-agent/hippo4j-agent-plugin/apollo-plugin/pom.xml new file mode 100644 index 00000000..c50abc5e --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-plugin/apollo-plugin/pom.xml @@ -0,0 +1,27 @@ + + + 4.0.0 + + cn.hippo4j + hippo4j-agent-plugin + ${revision} + + + apollo-plugin + + + 1.9.1 + + + + + com.ctrip.framework.apollo + apollo-client + ${apollo.version} + provided + + + + \ No newline at end of file diff --git a/hippo4j-agent/hippo4j-agent-plugin/apollo-plugin/src/main/java/cn/hippo4j/agent/plugin/apollo/DefaultConfigConstructorInterceptor.java b/hippo4j-agent/hippo4j-agent-plugin/apollo-plugin/src/main/java/cn/hippo4j/agent/plugin/apollo/DefaultConfigConstructorInterceptor.java new file mode 100644 index 00000000..4936a383 --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-plugin/apollo-plugin/src/main/java/cn/hippo4j/agent/plugin/apollo/DefaultConfigConstructorInterceptor.java @@ -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.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 { + // DefaultConfig config = (DefaultConfig) objInst; + // ConfigChangeListener configChangeListener = configChangeEvent -> { + // String namespace = this.namespace.replaceAll("." + bootstrapConfigProperties.getConfigFileType().getValue(), ""); + // ConfigFileFormat configFileFormat = ConfigFileFormat.fromString(bootstrapConfigProperties.getConfigFileType().getValue()); + // ConfigFile configFile = ConfigService.getConfigFile(namespace, configFileFormat); + // Map newChangeValueMap = new HashMap<>(); + // configChangeEvent.changedKeys().stream().filter(each -> each.contains(BootstrapConfigProperties.PREFIX)).forEach(each -> { + // ConfigChange change = configChangeEvent.getChange(each); + // String newValue = change.getNewValue(); + // newChangeValueMap.put(each, newValue); + // }); + // dynamicRefresh(configFile.getContent(), newChangeValueMap); + // }; + // config.addChangeListener(configChangeListener); + } +} diff --git a/hippo4j-agent/hippo4j-agent-plugin/apollo-plugin/src/main/java/cn/hippo4j/agent/plugin/apollo/boot/ApolloPluginBootService.java b/hippo4j-agent/hippo4j-agent-plugin/apollo-plugin/src/main/java/cn/hippo4j/agent/plugin/apollo/boot/ApolloPluginBootService.java new file mode 100644 index 00000000..9ad1dd0f --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-plugin/apollo-plugin/src/main/java/cn/hippo4j/agent/plugin/apollo/boot/ApolloPluginBootService.java @@ -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 { + + } +} diff --git a/hippo4j-agent/hippo4j-agent-plugin/apollo-plugin/src/main/java/cn/hippo4j/agent/plugin/apollo/define/ApolloInstrumentation.java b/hippo4j-agent/hippo4j-agent-plugin/apollo-plugin/src/main/java/cn/hippo4j/agent/plugin/apollo/define/ApolloInstrumentation.java new file mode 100644 index 00000000..6ae9d63c --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-plugin/apollo-plugin/src/main/java/cn/hippo4j/agent/plugin/apollo/define/ApolloInstrumentation.java @@ -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 getConstructorMatcher() { + return any(); + } + + @Override + public String getConstructorInterceptor() { + return CONSTRUCTOR_INTERCEPT_CLASS; + } + } + }; + } + + @Override + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[0]; + } +} diff --git a/hippo4j-agent/hippo4j-agent-plugin/apollo-plugin/src/main/resources/META-INF/services/cn.hippo4j.agent.core.boot.BootService b/hippo4j-agent/hippo4j-agent-plugin/apollo-plugin/src/main/resources/META-INF/services/cn.hippo4j.agent.core.boot.BootService new file mode 100644 index 00000000..8832c467 --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-plugin/apollo-plugin/src/main/resources/META-INF/services/cn.hippo4j.agent.core.boot.BootService @@ -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 \ No newline at end of file diff --git a/hippo4j-agent/hippo4j-agent-plugin/apollo-plugin/src/main/resources/hippo4j-plugin.def b/hippo4j-agent/hippo4j-agent-plugin/apollo-plugin/src/main/resources/hippo4j-plugin.def new file mode 100644 index 00000000..ede6239b --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-plugin/apollo-plugin/src/main/resources/hippo4j-plugin.def @@ -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 \ No newline at end of file diff --git a/hippo4j-agent/hippo4j-agent-plugin/pom.xml b/hippo4j-agent/hippo4j-agent-plugin/pom.xml index dc1770b1..1a3db451 100644 --- a/hippo4j-agent/hippo4j-agent-plugin/pom.xml +++ b/hippo4j-agent/hippo4j-agent-plugin/pom.xml @@ -13,6 +13,8 @@ pom spring-plugins + thread-pool-plugin + apollo-plugin @@ -29,6 +31,21 @@ 1.8.1 + + + cn.hippo4j + hippo4j-agent-core + ${project.version} + provided + + + net.bytebuddy + byte-buddy + ${bytebuddy.version} + provided + + + diff --git a/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/pom.xml b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/pom.xml index 1d85f539..200bfd2a 100644 --- a/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/pom.xml +++ b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/pom.xml @@ -32,19 +32,4 @@ - - - cn.hippo4j - hippo4j-agent-core - ${project.version} - provided - - - net.bytebuddy - byte-buddy - ${bytebuddy.version} - provided - - - \ No newline at end of file diff --git a/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/pom.xml b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/pom.xml index d52b781c..e144cf35 100644 --- a/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/pom.xml +++ b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/pom.xml @@ -13,8 +13,21 @@ 1.5.22.RELEASE + 1.9.1 + + + + org.springframework.boot + spring-boot-dependencies + ${spring.boot.version} + pom + import + + + + cn.hippo4j @@ -24,10 +37,30 @@ org.springframework.boot - spring-boot-autoconfigure + spring-boot-starter ${spring.boot.version} provided + + + com.ctrip.framework.apollo + apollo-client + ${apollo.version} + provided + + + + org.projectlombok + lombok + provided + + + + cn.hippo4j + hippo4j-config-spring-boot-1x-starter + ${project.version} + provided + \ No newline at end of file diff --git a/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/ApolloSpringBootProperties.java b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/ApolloSpringBootProperties.java new file mode 100644 index 00000000..1bf70dc3 --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/ApolloSpringBootProperties.java @@ -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 NAMESPACE = Arrays.asList("application"); + } + + public static String CONFIG_FILE_TYPE; + } + } + } +} diff --git a/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/EventPublishingFinishedInterceptor.java b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/EventPublishingFinishedInterceptor.java index c7dc072f..688ae0bf 100644 --- a/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/EventPublishingFinishedInterceptor.java +++ b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/EventPublishingFinishedInterceptor.java @@ -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 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 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 configInfo, ApplicationContext applicationContext) { + BootstrapConfigProperties bindableCoreProperties = new BootstrapConfigProperties(); + if (MapUtil.isEmpty(configInfo)) { + return bindableCoreProperties; + } + RelaxedNames relaxedNames = new RelaxedNames(BootstrapConfigProperties.PREFIX); + Set names = getNames(bindableCoreProperties, relaxedNames); + Map 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 newValueChangeMap, ApplicationContext context) { + try { + String configFileType = ApolloSpringBootProperties.Spring.Dynamic.Thread_Pool.CONFIG_FILE_TYPE; + + Map 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 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) { diff --git a/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/EventPublishingRunListenerEnvironmentPreparedInterceptor.java b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/EventPublishingRunListenerEnvironmentPreparedInterceptor.java new file mode 100644 index 00000000..1ac06ade --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/EventPublishingRunListenerEnvironmentPreparedInterceptor.java @@ -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) { + + } +} diff --git a/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/define/EventPublishingRunListenerInstrumentation.java b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/define/EventPublishingRunListenerInstrumentation.java index 7a0e7953..c4b5cc31 100644 --- a/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/define/EventPublishingRunListenerInstrumentation.java +++ b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-boot-1.x-plugin/src/main/java/cn/hippo4j/agent/plugin/spring/boot/v1/define/EventPublishingRunListenerInstrumentation.java @@ -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 getMethodsMatcher() { + return named("environmentPrepared"); + } + + @Override + public String getMethodsInterceptor() { + return EVENT_PUBLISHING_ENVIRONMENT_PREPARED_INTERCEPTOR; + } + @Override public boolean isOverrideArgs() { return false; diff --git a/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-plugin-common/src/main/java/cn/hippo4j/agent/plugin/spring/common/SpringEnvironmentSupport.java b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-plugin-common/src/main/java/cn/hippo4j/agent/plugin/spring/common/SpringEnvironmentSupport.java new file mode 100644 index 00000000..0d93bae3 --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-plugin/spring-plugins/spring-plugin-common/src/main/java/cn/hippo4j/agent/plugin/spring/common/SpringEnvironmentSupport.java @@ -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 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); + } +} diff --git a/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/pom.xml b/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/pom.xml new file mode 100644 index 00000000..019cb64c --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + + cn.hippo4j + hippo4j-agent-plugin + ${revision} + + + thread-pool-plugin + + + + cn.hippo4j + hippo4j-core + ${project.version} + + + \ No newline at end of file diff --git a/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/src/main/java/cn/hippo4j/agent/plugin/thread/pool/ThreadPoolExecutorConstructorMethodInterceptor.java b/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/src/main/java/cn/hippo4j/agent/plugin/thread/pool/ThreadPoolExecutorConstructorMethodInterceptor.java new file mode 100644 index 00000000..41c4e813 --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/src/main/java/cn/hippo4j/agent/plugin/thread/pool/ThreadPoolExecutorConstructorMethodInterceptor.java @@ -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 EXCLUDE_STACK_TRACE_ELEMENT_CLASS_PREFIX = Arrays.asList("java", "cn.hippo4j.agent"); + + @Override + public void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable { + + List stackTraceElements = getStackTraceElements(); + if (CollectionUtil.isEmpty(stackTraceElements)) { + return; + } + StackTraceElement declaredClassStackTraceElement = stackTraceElements.get(0); + String declaredClassName = declaredClassStackTraceElement.getClassName(); + List staticFieldsFromType = ReflectUtil.getStaticFieldsFromType(Class.forName(declaredClassName), + ThreadPoolExecutor.class); + for (Field field : staticFieldsFromType) { + try { + Object value = field.get(null); + if (value != null) { + String threadPoolId = declaredClassName + "#" + field.getName(); + ThreadPoolExecutor executor = (ThreadPoolExecutor) field.get(null); + register(threadPoolId, executor); + } + } catch (IllegalAccessException e) { + LOGGER.error(String.format("ExecutorNameUtil, register thread pool error. ClassName=[%s], ThreadPoolFieldName=[%s]", + objInst.getClass().getName(), field.getName()), e); + } + } + } + + private void register(String threadPoolId, ThreadPoolExecutor executor) { + // build parameter info. + ExecutorProperties executorProperties = ExecutorProperties.builder() + .threadPoolId(threadPoolId) + .corePoolSize(executor.getCorePoolSize()) + .maximumPoolSize(executor.getMaximumPoolSize()) + .allowCoreThreadTimeOut(BooleanUtil.toBoolean(String.valueOf(executor.allowsCoreThreadTimeOut()))) + .keepAliveTime(executor.getKeepAliveTime(TimeUnit.MILLISECONDS)) + .blockingQueue(BlockingQueueTypeEnum.getBlockingQueueTypeEnumByName(executor.getQueue().getClass().getSimpleName()).getName()) + .queueCapacity(executor.getQueue().remainingCapacity()) + .threadNamePrefix(threadPoolId) + .rejectedHandler(RejectedPolicyTypeEnum.getRejectedPolicyTypeEnumByName(executor.getRejectedExecutionHandler().getClass().getSimpleName()).getName()) + .executeTimeOut(10000L) + .build(); + + // register executor. + AgentThreadPoolInstanceRegistry.getInstance().putHolder(threadPoolId, executor, executorProperties); + + } + + private List 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 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 excludePackagePrefix = Config.Plugin.ThreadPool.EXCLUDE_PACKAGE_PREFIX; + for (String excludePrefix : excludePackagePrefix) { + if (className.startsWith(excludePrefix)) { + return true; + } + } + return false; + } +} diff --git a/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/src/main/java/cn/hippo4j/agent/plugin/thread/pool/define/ThreadPoolExecutorInstrumentation.java b/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/src/main/java/cn/hippo4j/agent/plugin/thread/pool/define/ThreadPoolExecutorInstrumentation.java new file mode 100644 index 00000000..d437e0d5 --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/src/main/java/cn/hippo4j/agent/plugin/thread/pool/define/ThreadPoolExecutorInstrumentation.java @@ -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 getConstructorMatcher() { + return takesArguments(CONSTRUCTOR_INTERCEPT_PARAMETER_LENGTH); + } + + @Override + public String getConstructorInterceptor() { + return CONSTRUCTOR_INTERCEPT_CLASS; + } + } + }; + } + + @Override + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[0]; + } +} diff --git a/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/src/main/resources/hippo4j-plugin.def b/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/src/main/resources/hippo4j-plugin.def new file mode 100644 index 00000000..d84d9489 --- /dev/null +++ b/hippo4j-agent/hippo4j-agent-plugin/thread-pool-plugin/src/main/resources/hippo4j-plugin.def @@ -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 \ No newline at end of file diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/api/IExecutorProperties.java b/hippo4j-common/src/main/java/cn/hippo4j/common/api/IExecutorProperties.java index 7df4dd8c..6fb60f45 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/api/IExecutorProperties.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/api/IExecutorProperties.java @@ -17,6 +17,8 @@ package cn.hippo4j.common.api; +import cn.hippo4j.common.config.ExecutorNotifyProperties; + /** * Interface for thread pool configuration. */ diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/api/ThreadPoolCheckAlarm.java b/hippo4j-common/src/main/java/cn/hippo4j/common/api/ThreadPoolCheckAlarm.java index 4b3a3f2a..5c07bd98 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/api/ThreadPoolCheckAlarm.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/api/ThreadPoolCheckAlarm.java @@ -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 diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/api/ExecutorNotifyProperties.java b/hippo4j-common/src/main/java/cn/hippo4j/common/config/ExecutorNotifyProperties.java similarity index 97% rename from hippo4j-common/src/main/java/cn/hippo4j/common/api/ExecutorNotifyProperties.java rename to hippo4j-common/src/main/java/cn/hippo4j/common/config/ExecutorNotifyProperties.java index 9334e9db..647c6d9b 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/api/ExecutorNotifyProperties.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/config/ExecutorNotifyProperties.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package cn.hippo4j.common.api; +package cn.hippo4j.common.config; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/ExecutorProperties.java b/hippo4j-common/src/main/java/cn/hippo4j/common/config/ExecutorProperties.java similarity index 95% rename from hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/ExecutorProperties.java rename to hippo4j-common/src/main/java/cn/hippo4j/common/config/ExecutorProperties.java index 9d179d22..fb33a0dd 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/ExecutorProperties.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/config/ExecutorProperties.java @@ -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; diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/constant/Constants.java b/hippo4j-common/src/main/java/cn/hippo4j/common/constant/Constants.java index 32b79cce..2b651ffc 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/constant/Constants.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/constant/Constants.java @@ -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"; } diff --git a/hippo4j-core/src/test/java/cn/hippo4j/core/proxy/RejectedProxyInvocationHandlerTest.java b/hippo4j-core/src/test/java/cn/hippo4j/core/proxy/RejectedProxyInvocationHandlerTest.java index fecd2ad0..54f36bc4 100644 --- a/hippo4j-core/src/test/java/cn/hippo4j/core/proxy/RejectedProxyInvocationHandlerTest.java +++ b/hippo4j-core/src/test/java/cn/hippo4j/core/proxy/RejectedProxyInvocationHandlerTest.java @@ -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 mockedStatic = Mockito.mockStatic(ApplicationContextHolder.class); mockedStatic.when(ApplicationContextHolder::getInstance).thenReturn(applicationContext); mockedStatic.when(() -> ApplicationContextHolder.getBean(ThreadPoolCheckAlarm.class)).thenReturn(mockAlarmHandler); diff --git a/hippo4j-example/hippo4j-config-apollo-spring-boot-starter-example/src/main/resources/apollo-config.properties b/hippo4j-example/hippo4j-config-apollo-spring-boot-starter-example/src/main/resources/apollo-config.properties index 2c83a611..5cdf82ce 100644 --- a/hippo4j-example/hippo4j-config-apollo-spring-boot-starter-example/src/main/resources/apollo-config.properties +++ b/hippo4j-example/hippo4j-config-apollo-spring-boot-starter-example/src/main/resources/apollo-config.properties @@ -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 diff --git a/hippo4j-example/hippo4j-example-core/src/main/java/cn/hippo4j/example/core/config/DynamicThreadPoolConfig.java b/hippo4j-example/hippo4j-example-core/src/main/java/cn/hippo4j/example/core/config/DynamicThreadPoolConfig.java index 517a190b..879ea928 100644 --- a/hippo4j-example/hippo4j-example-core/src/main/java/cn/hippo4j/example/core/config/DynamicThreadPoolConfig.java +++ b/hippo4j-example/hippo4j-example-core/src/main/java/cn/hippo4j/example/core/config/DynamicThreadPoolConfig.java @@ -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() { diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-1x-starter/src/main/java/cn/hippo4j/config/springboot1x/starter/config/WebThreadPoolHandlerConfiguration1x.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-1x-starter/src/main/java/cn/hippo4j/config/springboot1x/starter/config/WebThreadPoolHandlerConfiguration1x.java index 7ba71536..4746b675 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-1x-starter/src/main/java/cn/hippo4j/config/springboot1x/starter/config/WebThreadPoolHandlerConfiguration1x.java +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-1x-starter/src/main/java/cn/hippo4j/config/springboot1x/starter/config/WebThreadPoolHandlerConfiguration1x.java @@ -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 { diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-1x-starter/src/main/java/cn/hippo4j/config/springboot1x/starter/refresher/SpringBoot1xBootstrapConfigPropertiesBinderAdapt.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-1x-starter/src/main/java/cn/hippo4j/config/springboot1x/starter/refresher/SpringBoot1xBootstrapConfigPropertiesBinderAdapt.java index 26a35088..4e4cf009 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-1x-starter/src/main/java/cn/hippo4j/config/springboot1x/starter/refresher/SpringBoot1xBootstrapConfigPropertiesBinderAdapt.java +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-1x-starter/src/main/java/cn/hippo4j/config/springboot1x/starter/refresher/SpringBoot1xBootstrapConfigPropertiesBinderAdapt.java @@ -73,7 +73,7 @@ public class SpringBoot1xBootstrapConfigPropertiesBinderAdapt implements Applica return bindableCoreProperties; } - private static Set getNames(Object target, Iterable prefixes) { + public static Set getNames(Object target, Iterable prefixes) { Set names = new LinkedHashSet<>(); if (target != null) { PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(target.getClass()); diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/BootstrapConfigProperties.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/BootstrapConfigProperties.java index 9f5664dd..04cd9033 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/BootstrapConfigProperties.java +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/BootstrapConfigProperties.java @@ -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; diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/WebExecutorProperties.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/WebExecutorProperties.java index 95569405..c0a31472 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/WebExecutorProperties.java +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/WebExecutorProperties.java @@ -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; diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/notify/ConfigModeNotifyConfigBuilder.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/notify/ConfigModeNotifyConfigBuilder.java index f765ada5..bebf1dc3 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/notify/ConfigModeNotifyConfigBuilder.java +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/notify/ConfigModeNotifyConfigBuilder.java @@ -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.*; diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/event/DynamicThreadPoolRefreshListener.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/event/DynamicThreadPoolRefreshListener.java index f802c27b..99f97ca0 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/event/DynamicThreadPoolRefreshListener.java +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/event/DynamicThreadPoolRefreshListener.java @@ -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; diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/event/PlatformsRefreshListener.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/event/PlatformsRefreshListener.java index f117082f..8191b0b5 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/event/PlatformsRefreshListener.java +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/event/PlatformsRefreshListener.java @@ -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; diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/support/DynamicThreadPoolConfigService.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/support/DynamicThreadPoolConfigService.java index 4a997d77..df9a265e 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/support/DynamicThreadPoolConfigService.java +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/support/DynamicThreadPoolConfigService.java @@ -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; diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/support/DynamicThreadPoolPostProcessor.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/support/DynamicThreadPoolPostProcessor.java index 70137141..98db66ce 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/support/DynamicThreadPoolPostProcessor.java +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/support/DynamicThreadPoolPostProcessor.java @@ -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; diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/support/GlobalCoreThreadPoolManage.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/support/GlobalCoreThreadPoolManage.java index bef01cac..7a8cacf2 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/support/GlobalCoreThreadPoolManage.java +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/support/GlobalCoreThreadPoolManage.java @@ -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; diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter-monitor/hippo4j-spring-boot-starter-monitor-elasticsearch/src/main/java/cn/hippo4j/springboot/starter/monitor/elasticsearch/ElasticSearchMonitorAutoConfiguration.java b/hippo4j-spring-boot/hippo4j-spring-boot-starter-monitor/hippo4j-spring-boot-starter-monitor-elasticsearch/src/main/java/cn/hippo4j/springboot/starter/monitor/elasticsearch/ElasticSearchMonitorAutoConfiguration.java index b9d73921..73954005 100644 --- a/hippo4j-spring-boot/hippo4j-spring-boot-starter-monitor/hippo4j-spring-boot-starter-monitor-elasticsearch/src/main/java/cn/hippo4j/springboot/starter/monitor/elasticsearch/ElasticSearchMonitorAutoConfiguration.java +++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter-monitor/hippo4j-spring-boot-starter-monitor-elasticsearch/src/main/java/cn/hippo4j/springboot/starter/monitor/elasticsearch/ElasticSearchMonitorAutoConfiguration.java @@ -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 diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter-monitor/hippo4j-spring-boot-starter-monitor-local-log/src/main/java/cn/hippo4j/springboot/starter/monitor/local/log/LocalLogMonitorAutoConfiguration.java b/hippo4j-spring-boot/hippo4j-spring-boot-starter-monitor/hippo4j-spring-boot-starter-monitor-local-log/src/main/java/cn/hippo4j/springboot/starter/monitor/local/log/LocalLogMonitorAutoConfiguration.java index d59c8912..ae6e50d3 100644 --- a/hippo4j-spring-boot/hippo4j-spring-boot-starter-monitor/hippo4j-spring-boot-starter-monitor-local-log/src/main/java/cn/hippo4j/springboot/starter/monitor/local/log/LocalLogMonitorAutoConfiguration.java +++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter-monitor/hippo4j-spring-boot-starter-monitor-local-log/src/main/java/cn/hippo4j/springboot/starter/monitor/local/log/LocalLogMonitorAutoConfiguration.java @@ -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 diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter-monitor/hippo4j-spring-boot-starter-monitor-micrometer/src/main/java/cn/hippo4j/springboot/starter/monitor/micrometer/MicrometerMonitorAutoConfiguration.java b/hippo4j-spring-boot/hippo4j-spring-boot-starter-monitor/hippo4j-spring-boot-starter-monitor-micrometer/src/main/java/cn/hippo4j/springboot/starter/monitor/micrometer/MicrometerMonitorAutoConfiguration.java index d523575f..1ae9406e 100644 --- a/hippo4j-spring-boot/hippo4j-spring-boot-starter-monitor/hippo4j-spring-boot-starter-monitor-micrometer/src/main/java/cn/hippo4j/springboot/starter/monitor/micrometer/MicrometerMonitorAutoConfiguration.java +++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter-monitor/hippo4j-spring-boot-starter-monitor-micrometer/src/main/java/cn/hippo4j/springboot/starter/monitor/micrometer/MicrometerMonitorAutoConfiguration.java @@ -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 diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/config/BootstrapProperties.java b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/config/BootstrapProperties.java index 8faf4dcc..ba348c75 100644 --- a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/config/BootstrapProperties.java +++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/config/BootstrapProperties.java @@ -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 */ diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/config/DynamicThreadPoolAutoConfiguration.java b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/config/DynamicThreadPoolAutoConfiguration.java index 124f9810..5b9ee75a 100644 --- a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/config/DynamicThreadPoolAutoConfiguration.java +++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/config/DynamicThreadPoolAutoConfiguration.java @@ -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 { diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/config/NettyClientConfiguration.java b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/config/NettyClientConfiguration.java index 0eb02844..e628a831 100644 --- a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/config/NettyClientConfiguration.java +++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/config/NettyClientConfiguration.java @@ -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