fix: Fixed jar package mounting and startup problem in Agent mode

pull/1567/head
Pan-YuJie 12 months ago
parent 92dec458b2
commit 7b8a43175a

@ -18,6 +18,8 @@
package cn.hippo4j.agent.core.conf;
import cn.hippo4j.agent.core.boot.AgentPackagePath;
import cn.hippo4j.agent.core.util.PropertyPlaceholderHelper;
import cn.hippo4j.agent.core.util.StringUtil;
import cn.hippo4j.common.boot.AgentPackageNotFoundException;
import cn.hippo4j.common.conf.Config;
import cn.hippo4j.common.conf.ConfigNotFoundException;
@ -25,9 +27,7 @@ import cn.hippo4j.common.logging.api.ILog;
import cn.hippo4j.common.logging.api.LogManager;
import cn.hippo4j.common.logging.core.JsonLogResolver;
import cn.hippo4j.common.logging.core.PatternLogResolver;
import cn.hippo4j.common.toolkit.StringUtil;
import cn.hippo4j.common.toolkit.agent.ConfigInitializer;
import cn.hippo4j.common.toolkit.agent.PropertyPlaceholderHelper;
import java.io.File;
import java.io.FileInputStream;

@ -17,11 +17,14 @@
package cn.hippo4j.agent.plugin.nacos;
import cn.hippo4j.agent.plugin.spring.common.conf.NacosCloudConfig;
import cn.hippo4j.agent.plugin.spring.common.conf.NacosConfig;
import cn.hippo4j.agent.plugin.spring.common.conf.SpringBootConfig;
import cn.hippo4j.agent.plugin.spring.common.toolkit.SpringPropertyBinder;
import cn.hippo4j.common.executor.ThreadFactoryBuilder;
import cn.hippo4j.common.logging.api.ILog;
import cn.hippo4j.common.logging.api.LogManager;
import cn.hippo4j.common.toolkit.StringUtil;
import cn.hippo4j.threadpool.dynamic.mode.config.parser.ConfigParserHandler;
import cn.hippo4j.threadpool.dynamic.mode.config.properties.BootstrapConfigProperties;
import cn.hippo4j.threadpool.dynamic.mode.config.refresher.AbstractConfigThreadPoolDynamicRefresh;
@ -34,6 +37,7 @@ import org.springframework.boot.context.properties.bind.Binder;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledThreadPoolExecutor;
@ -64,7 +68,13 @@ public class NacosDynamicThreadPoolChangeHandler extends AbstractConfigThreadPoo
public void registerListener() {
// Retrieve necessary configuration properties
String configFileType = SpringBootConfig.Spring.Dynamic.Thread_Pool.CONFIG_FILE_TYPE;
String serverAddr = SpringBootConfig.Spring.Dynamic.Thread_Pool.Nacos.SERVER_ADDR;
String serverAddr = Optional.ofNullable(NacosCloudConfig.Spring.Cloud.Nacos.Config.SERVER_ADDR).filter(s -> !StringUtil.isEmpty(s))
.orElse(Optional.ofNullable(NacosConfig.Nacos.Config.SERVER_ADDR).filter(s -> !StringUtil.isEmpty(s))
.orElse(""));
if (StringUtil.isEmpty(serverAddr)) {
LOGGER.error("[Hippo4j-Agent] add Nacos listener failure. Nacos Registry address not configured");
return;
}
String dataId = SpringBootConfig.Spring.Dynamic.Thread_Pool.Nacos.DATA_ID;
String group = SpringBootConfig.Spring.Dynamic.Thread_Pool.Nacos.GROUP;
String namespace = SpringBootConfig.Spring.Dynamic.Thread_Pool.Nacos.NAMESPACE.get(0);
@ -105,9 +115,9 @@ public class NacosDynamicThreadPoolChangeHandler extends AbstractConfigThreadPoo
};
// Add the listener to the Nacos ConfigService
configService.addListener(dataId, group, configChangeListener);
LOGGER.info("[Hippo4j-Agent] Dynamic thread pool refresher, add Nacos listener successfully. namespace: {} data-id: {} group: {}", namespace, dataId, group);
LOGGER.info("[Hippo4j-Agent] Dynamic thread pool refresher, add Nacos listener successfully. serverAddr: {} namespace: {} data-id: {} group: {}", serverAddr, namespace, dataId, group);
} catch (Exception e) {
LOGGER.error(e, "[Hippo4j-Agent] Dynamic thread pool refresher, add Nacos listener failure. namespace: {} data-id: {} group: {}", namespace, dataId, group);
LOGGER.error(e, "[Hippo4j-Agent] Dynamic thread pool refresher, add Nacos listener failure. serverAddr: {} namespace: {} data-id: {} group: {}", serverAddr, namespace, dataId, group);
}
}

@ -41,9 +41,6 @@ public class NacosCloudAdapterConfigInstanceMethodInterceptor implements Instanc
}
/**
*
*/
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
// This logic will only be executed once

@ -38,7 +38,7 @@ public class NacosConfigConstructorInterceptor implements InstanceConstructorInt
// This logic will only be executed once
if (isExecuted.compareAndSet(false, true)) {
// 判断 SpringPropertiesLoader 是否初始化
// Determine whether SpringPropertiesLoader is initialized
AtomicBoolean active = SpringPropertiesLoader.getActive();
// For Nacos-Cloud, the SpringPropertiesLoader environment initialization is triggered first, and then the logic to register listeners is triggered
@ -51,7 +51,7 @@ public class NacosConfigConstructorInterceptor implements InstanceConstructorInt
// The Nacos plugin triggers before the Spring configuration plug-in.
// This means that when the Apollo plug-in executes, Spring's Environment is not yet ready,
// so the configuration cannot be read
// After listening to the AGENT_SPRING_PROPERTIES_LOADER_COMPLETED event, register the listener for Apollo
// After listening to the AGENT_SPRING_PROPERTIES_LOADER_COMPLETED event, register the listener for Nacos
AbstractSubjectCenter.register(AbstractSubjectCenter.SubjectType.AGENT_SPRING_PROPERTIES_LOADER_COMPLETED, new NacosConfigPropertiesLoaderCompletedListener());
}
}

@ -29,13 +29,6 @@
</dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-agent-spring-plugin-common</artifactId>
<scope>provided</scope>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
@ -45,9 +38,8 @@
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-threadpool-config-spring-boot-1x-starter</artifactId>
<artifactId>hippo4j-agent-spring-plugin-common</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>

@ -25,7 +25,9 @@ import cn.hippo4j.agent.plugin.spring.common.support.SpringPropertiesLoader;
import cn.hippo4j.agent.plugin.spring.common.support.SpringThreadPoolRegisterSupport;
import cn.hippo4j.common.extension.design.AbstractSubjectCenter;
import cn.hippo4j.core.config.ApplicationContextHolder;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.ContextRefreshedEvent;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicBoolean;
@ -50,7 +52,18 @@ public class ApplicationContextInterceptor implements InstanceMethodsAroundInter
ConfigurableApplicationContext context = (ConfigurableApplicationContext) objInst;
if (context.getParent() != null) {
// After the child container is started, the thread pool registration will be carried out
SpringThreadPoolRegisterSupport.registerThreadPoolInstances(context);
// IDEA's runtime environment or debugging mechanisms make context refresh speeds different.
// Ensure that thread pool registration logic is executed only after the context is fully started
if (context.isActive()) {
SpringThreadPoolRegisterSupport.registerThreadPoolInstances(context);
return ret;
}
// However, the packaged JAR runtime may refresh the context faster
// resulting in the context not being refreshed yet when registerThreadPoolInstances is called
// Register listener to handle the registration after the context has been fully refreshed
context.addApplicationListener((ApplicationListener<ContextRefreshedEvent>) event -> {
SpringThreadPoolRegisterSupport.registerThreadPoolInstances(event.getApplicationContext());
});
return ret;
}
// This logic will only be executed once

@ -17,13 +17,6 @@
</properties>
<dependencies>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-agent-spring-plugin-common</artifactId>
<scope>provided</scope>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
@ -33,28 +26,15 @@
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-threadpool-dynamic-mode-config</artifactId>
<artifactId>hippo4j-agent-spring-plugin-common</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-threadpool-core</artifactId>
<artifactId>hippo4j-threadpool-dynamic-mode-config</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>2.2.1</version>
</dependency>
</dependencies>
</project>

@ -1,78 +0,0 @@
/*
* 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.v2;
import cn.hippo4j.common.logging.api.ILog;
import cn.hippo4j.common.logging.api.LogManager;
import cn.hippo4j.agent.plugin.spring.common.conf.SpringBootConfig;
import cn.hippo4j.threadpool.dynamic.mode.config.properties.BootstrapConfigProperties;
import cn.hippo4j.threadpool.dynamic.mode.config.refresher.AbstractConfigThreadPoolDynamicRefresh;
import com.ctrip.framework.apollo.Config;
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.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static cn.hippo4j.agent.core.conf.Constants.SPRING_BOOT_CONFIG_PREFIX;
/**
* Dynamic thread pool change handler spring 2x
*/
public class DynamicThreadPoolChangeHandlerSpring2x extends AbstractConfigThreadPoolDynamicRefresh {
private static ILog LOGGER = LogManager.getLogger(DynamicThreadPoolChangeHandlerSpring2x.class);
@Override
public void registerListener() {
List<String> apolloNamespaces = SpringBootConfig.Spring.Dynamic.Thread_Pool.Apollo.NAMESPACE;
String namespace = apolloNamespaces.get(0);
String configFileType = SpringBootConfig.Spring.Dynamic.Thread_Pool.CONFIG_FILE_TYPE;
Config config = ConfigService.getConfig(String.format("%s.%s", namespace, configFileType));
ConfigChangeListener configChangeListener = configChangeEvent -> {
String replacedNamespace = namespace.replaceAll("." + configFileType, "");
ConfigFileFormat configFileFormat = ConfigFileFormat.fromString(configFileType);
ConfigFile configFile = ConfigService.getConfigFile(replacedNamespace, configFileFormat);
Map<String, Object> newChangeValueMap = new HashMap<>();
configChangeEvent.changedKeys().stream().filter(each -> each.contains(SPRING_BOOT_CONFIG_PREFIX)).forEach(each -> {
ConfigChange change = configChangeEvent.getChange(each);
String newValue = change.getNewValue();
newChangeValueMap.put(each, newValue);
});
dynamicRefresh(configFileType, configFile.getContent(), newChangeValueMap);
};
config.addChangeListener(configChangeListener);
LOGGER.info("[Hippo4j-Agent] Dynamic thread pool refresher, add apollo listener success. namespace: {}", namespace);
}
@Override
public BootstrapConfigProperties buildBootstrapProperties(Map<Object, Object> configInfo) {
BootstrapConfigProperties bindableBootstrapConfigProperties = new BootstrapConfigProperties();
ConfigurationPropertySource sources = new MapConfigurationPropertySource(configInfo);
Binder binder = new Binder(sources);
return binder.bind(BootstrapConfigProperties.PREFIX, Bindable.ofInstance(bindableBootstrapConfigProperties)).get();
}
}

@ -1,139 +0,0 @@
/*
* 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.v2;
import cn.hippo4j.agent.plugin.spring.common.conf.SpringBootConfig;
import cn.hippo4j.common.executor.ThreadFactoryBuilder;
import cn.hippo4j.common.logging.api.ILog;
import cn.hippo4j.common.logging.api.LogManager;
import cn.hippo4j.threadpool.dynamic.mode.config.parser.ConfigParserHandler;
import cn.hippo4j.threadpool.dynamic.mode.config.properties.BootstrapConfigProperties;
import cn.hippo4j.threadpool.dynamic.mode.config.refresher.AbstractConfigThreadPoolDynamicRefresh;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import static cn.hippo4j.common.constant.Constants.DEFAULT_NAMESPACE_ID;
/**
* NacosDynamicThreadPoolChangeHandlerSpring2x is responsible for handling dynamic thread pool
* configuration changes in a Spring environment by listening to configuration updates from Nacos.
* <p>
* This class extends {@link AbstractConfigThreadPoolDynamicRefresh} and implements the logic
* to register a Nacos listener, handle configuration changes, and dynamically refresh the thread pool
* properties based on the new configuration.
* <p>
* The handler is specifically tailored for use with Spring 2.x and integrates with Hippo4j's
* dynamic thread pool management system.
*
*/
public class NacosDynamicThreadPoolChangeHandlerSpring2x extends AbstractConfigThreadPoolDynamicRefresh {
private static final ILog LOGGER = LogManager.getLogger(NacosDynamicThreadPoolChangeHandlerSpring2x.class);
/**
* Registers a listener with Nacos to monitor for changes in the thread pool configuration.
* <p>
* This method sets up the Nacos {@link ConfigService} with the server address and namespace
* from the Spring Boot configuration. It then adds a listener that will receive and process
* configuration updates, triggering a dynamic refresh of thread pool settings.
*/
@Override
public void registerListener() {
// Retrieve necessary configuration properties
String configFileType = SpringBootConfig.Spring.Dynamic.Thread_Pool.CONFIG_FILE_TYPE;
String serverAddr = SpringBootConfig.Spring.Dynamic.Thread_Pool.Nacos.SERVER_ADDR;
String dataId = SpringBootConfig.Spring.Dynamic.Thread_Pool.Nacos.DATA_ID;
String namespace = SpringBootConfig.Spring.Dynamic.Thread_Pool.Nacos.NAMESPACE.get(0);
namespace = namespace.equals(DEFAULT_NAMESPACE_ID) ? "" : namespace;
String group = SpringBootConfig.Spring.Dynamic.Thread_Pool.Nacos.GROUP;
try {
// Initialize Nacos ConfigService with the provided properties
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
properties.put(PropertyKeyConst.NAMESPACE, namespace);
ConfigService configService = NacosFactory.createConfigService(properties);
// Define the listener to handle configuration changes
Listener configChangeListener = new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
LOGGER.debug("Received configuration: " + configInfo);
Map<String, Object> changeValueMap = new HashMap<>();
try {
// Parse the configuration and map the values to the appropriate keys
Map<Object, Object> configInfoMap = ConfigParserHandler.getInstance().parseConfig(configInfo, configFileType);
configInfoMap.forEach((key, value) -> {
if (key instanceof String) {
changeValueMap.put((String) key, value);
}
});
} catch (IOException e) {
LOGGER.error(e, "[Hippo4j-Agent] Dynamic thread pool refresher, Failed to resolve configuration. configFileType: {} configInfo: {} ", configFileType, configInfo);
}
// Trigger the dynamic refresh with the parsed configuration
dynamicRefresh(configFileType, configInfo, changeValueMap);
}
@Override
public Executor getExecutor() {
return new ScheduledThreadPoolExecutor(
1,
ThreadFactoryBuilder.builder().daemon(true).prefix("client.dynamic.refresh.agent").build());
}
};
// Add the listener to the Nacos ConfigService
configService.addListener(dataId, group, configChangeListener);
LOGGER.info("[Hippo4j-Agent] Dynamic thread pool refresher, add Nacos listener successfully. namespace: {} data-id: {} group: {}", namespace, dataId, group);
} catch (Exception e) {
LOGGER.error(e, "[Hippo4j-Agent] Dynamic thread pool refresher, add Nacos listener failure. namespace: {} data-id: {} group: {}", namespace, dataId, group);
}
LOGGER.info("[Hippo4j-Agent] Dynamic thread pool refresher, added Nacos listener successfully. namespace: {} data-id: {} group: {}", namespace, dataId, group);
}
/**
* Builds and binds the {@link BootstrapConfigProperties} from the given configuration map.
* <p>
* This method uses Spring's {@link Binder} to bind the configuration values to an instance
* of {@link BootstrapConfigProperties}, which can then be used to configure the thread pool
* dynamically.
*
* @param configInfo the configuration map containing properties to bind.
* @return the bound {@link BootstrapConfigProperties} instance.
*/
@Override
public BootstrapConfigProperties buildBootstrapProperties(Map<Object, Object> configInfo) {
BootstrapConfigProperties bindableBootstrapConfigProperties = new BootstrapConfigProperties();
ConfigurationPropertySource sources = new MapConfigurationPropertySource(configInfo);
Binder binder = new Binder(sources);
return binder.bind(BootstrapConfigProperties.PREFIX, Bindable.ofInstance(bindableBootstrapConfigProperties)).get();
}
}

@ -35,25 +35,32 @@
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-threadpool-dynamic-api</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-threadpool-dynamic-core</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-threadpool-kernel-alarm</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-threadpool-core</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-threadpool-adapter-web</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>

@ -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.common.conf;
import cn.hippo4j.agent.core.boot.SpringBootConfigNode;
/**
* Nacos Cloud config
*/
public class NacosCloudConfig {
public static class Spring {
/**
* Cloud
*/
public static class Cloud {
/**
* Nacos
*/
public static class Nacos {
/**
* Config
*/
@SpringBootConfigNode(root = NacosConfig.class)
public static class Config {
public static String SERVER_ADDR = "";
}
}
}
}
}

@ -0,0 +1,42 @@
/*
* 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.conf;
import cn.hippo4j.agent.core.boot.SpringBootConfigNode;
/**
* nacos config
*/
public class NacosConfig {
/**
* Nacos
*/
public static class Nacos {
/**
* Config
*/
@SpringBootConfigNode(root = NacosCloudConfig.class)
public static class Config {
public static String SERVER_ADDR = "";
}
}
}

@ -17,14 +17,13 @@
package cn.hippo4j.agent.plugin.spring.common.monitor;
import cn.hippo4j.agent.plugin.spring.common.support.SpringPropertiesLoader;
import cn.hippo4j.common.extension.spi.ServiceLoaderRegistry;
import cn.hippo4j.common.logging.api.ILog;
import cn.hippo4j.common.logging.api.LogManager;
import cn.hippo4j.common.monitor.MonitorCollectTypeEnum;
import cn.hippo4j.common.monitor.MonitorHandlerTypeEnum;
import cn.hippo4j.core.executor.state.ThreadPoolRunStateHandler;
import cn.hippo4j.core.toolkit.inet.InetUtils;
import cn.hippo4j.core.toolkit.inet.InetUtilsProperties;
import cn.hippo4j.monitor.elasticsearch.AdapterThreadPoolElasticSearchMonitorHandler;
import cn.hippo4j.monitor.elasticsearch.DynamicThreadPoolElasticSearchMonitorHandler;
import cn.hippo4j.monitor.elasticsearch.WebThreadPoolElasticSearchMonitorHandler;
@ -45,8 +44,6 @@ import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import static cn.hippo4j.agent.plugin.spring.common.support.SpringPropertiesLoader.INET_UTILS_PROPERTIES;
/**
* This class is responsible for configuring and initializing monitoring handlers
* for various types of thread pools. It maps specific monitoring types (e.g., Micrometer,
@ -88,7 +85,7 @@ public class MonitorHandlersConfigurator {
List<String> collectTypes = Arrays.asList(monitor.getCollectTypes().split(","));
List<String> threadPoolTypes = Arrays.asList(monitor.getThreadPoolTypes().split(","));
ThreadPoolRunStateHandler threadPoolRunStateHandler = new ThreadPoolRunStateHandler(
new InetUtils(INET_UTILS_PROPERTIES), environment);
SpringPropertiesLoader.inetUtils, environment);
MonitorHandlerContext context = new MonitorHandlerContext(threadPoolMonitors, threadPoolRunStateHandler);

@ -67,7 +67,7 @@ public class MonitorMetricEndpoint {
Integer port = SpringBootConfig.Spring.Dynamic.Thread_Pool.Monitor.AGENT_MICROMETER_PORT;
if (port == null) {
LOGGER.error(
"[Hippo4j-Agent] Failed to start Prometheus metrics endpoint server. Please configure the exposed endpoint by adding: spring.dynamic.thread-pool.monitor.port=xxx to the configuration file");
"[Hippo4j-Agent] Failed to start Prometheus metrics endpoint server. Please configure the exposed endpoint by adding: spring.dynamic.thread-pool.monitor.agent-micrometer-port=xxx to the configuration file");
return;
}

@ -22,6 +22,7 @@ import cn.hippo4j.agent.plugin.spring.common.toolkit.SpringPropertyBinder;
import cn.hippo4j.common.extension.design.AbstractSubjectCenter;
import cn.hippo4j.common.logging.api.ILog;
import cn.hippo4j.common.logging.api.LogManager;
import cn.hippo4j.core.toolkit.inet.InetUtils;
import cn.hippo4j.core.toolkit.inet.InetUtilsProperties;
import cn.hippo4j.threadpool.dynamic.mode.config.properties.BootstrapConfigProperties;
import lombok.Getter;
@ -57,6 +58,8 @@ public class SpringPropertiesLoader {
public static InetUtilsProperties INET_UTILS_PROPERTIES = new InetUtilsProperties();
public static InetUtils inetUtils;
public static void loadSpringProperties(ConfigurableEnvironment environment) {
Iterator<PropertySource<?>> iterator = environment.getPropertySources().iterator();
Properties properties = new Properties();

@ -108,8 +108,8 @@ public class ThreadPoolCheckAlarmSupport {
EnvironmentProperties.active = SpringBootConfig.Spring.Profiles.active;
ConfigurableEnvironment environment = ApplicationContextHolder.getBean(ConfigurableEnvironment.class);
InetUtilsProperties inetUtilsProperties = SpringPropertyBinder.bindProperties(environment, InetUtilsProperties.PREFIX, InetUtilsProperties.class);
InetUtils inetUtils = new InetUtils(inetUtilsProperties);
IdentifyUtil.generate(environment, inetUtils);
SpringPropertiesLoader.inetUtils = new InetUtils(inetUtilsProperties);
IdentifyUtil.generate(environment, SpringPropertiesLoader.inetUtils);
}
/**

@ -98,7 +98,8 @@ public class ThreadPoolMonitorSupport {
// Determine whether the task is successfully enabled
// return directly if it has been enabled, and do not start the thread pool repeatedly
if (Boolean.TRUE.equals(active.get())) return;
if (Boolean.TRUE.equals(active.get()))
return;
// Expose metric endpoints based on the configured collect types
List<String> collectTypes = Arrays.asList(monitor.getCollectTypes().split(","));
@ -107,7 +108,8 @@ public class ThreadPoolMonitorSupport {
}
// Schedule periodic collection of metrics from the thread pools
collectScheduledExecutor.scheduleWithFixedDelay(scheduleRunnable(), monitor.getInitialDelay(), monitor.getCollectInterval(), TimeUnit.MILLISECONDS);
Runnable scheduledTask = scheduleRunnable();
collectScheduledExecutor.scheduleWithFixedDelay(scheduledTask, monitor.getInitialDelay(), monitor.getCollectInterval(), TimeUnit.MILLISECONDS);
active.set(true);
if (ThreadPoolExecutorRegistry.getThreadPoolExecutorSize() > 0) {
@ -130,7 +132,7 @@ public class ThreadPoolMonitorSupport {
for (ThreadPoolMonitor each : threadPoolMonitors) {
try {
each.collect();
} catch (Exception ex) {
} catch (Throwable ex) {
LOGGER.error("[Hippo4j-Agent] Error monitoring the running status of dynamic thread pool. Type: {}", each.getType(), ex);
}
}

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

@ -52,7 +52,16 @@ public class ThreadPoolExecutorConstructorMethodInterceptor implements InstanceC
}
StackTraceElement declaredClassStackTraceElement = stackTraceElements.get(0);
String declaredClassName = declaredClassStackTraceElement.getClassName();
Class<?> declaredClass = Thread.currentThread().getContextClassLoader().loadClass(declaredClassName);
Class<?> declaredClass = null;
try {
declaredClass = Thread.currentThread().getContextClassLoader().loadClass(declaredClassName);
} catch (ClassNotFoundException e) {
// The thread pool in the Agent plug-in is loaded by AgentclassLodaer.
// Due to the delegation model, it can only be searched upwards, so searching here will result in ClassNotFount.
// Because the parent of AgentClassLoader is AppclassLoder, it is ignored here ,skip the enhancement logic
LOGGER.debug("searching {} result in ClassNotFount , so skip the enhancement logic", declaredClassName);
return;
}
ThreadPoolExecutorRegistry.REFERENCED_CLASS_MAP.put((ThreadPoolExecutor) objInst, declaredClass);
}

@ -140,7 +140,6 @@
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>${objenesis.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>

@ -13,9 +13,6 @@ env=dev
apollo.configService=http://127.0.0.1:8080
spring.profiles.active=dev
spring.application.name=hippo4j-config-apollo-spring-boot-starter-example
management.metrics.export.prometheus.enabled=true
management.server.port=29998
management.endpoints.web.exposure.include=*
spring.dynamic.thread-pool.enable=true
spring.dynamic.thread-pool.banner=true
@ -25,6 +22,7 @@ spring.dynamic.thread-pool.monitor.collect-types=micrometer
spring.dynamic.thread-pool.monitor.thread-pool-types=dynamic
spring.dynamic.thread-pool.monitor.initial-delay=3000
spring.dynamic.thread-pool.monitor.collect-interval=3000
spring.dynamic.thread-pool.monitor.agent-micrometer-port=29999
spring.dynamic.thread-pool.notify-platforms[0].platform=LARK
spring.dynamic.thread-pool.notify-platforms[0].token=6de41bdc-0799-45be-b128-7cddb9e777f0
@ -51,3 +49,17 @@ spring.dynamic.thread-pool.executors[0].active-alarm = 80
spring.dynamic.thread-pool.executors[0].capacity-alarm = 80
spring.dynamic.thread-pool.executors[0].notify.interval = 8
spring.dynamic.thread-pool.executors[0].notify.receives = nobodyiam
spring.dynamic.thread-pool.executors[1].thread-pool-id = runMessageSendTaskExecutor
spring.dynamic.thread-pool.executors[1].thread-name-prefix = runMessageSendTaskExecutor
spring.dynamic.thread-pool.executors[1].core-pool-size = 3
spring.dynamic.thread-pool.executors[1].maximum-pool-size = 4
spring.dynamic.thread-pool.executors[1].queue-capacity = 1024
spring.dynamic.thread-pool.executors[1].blocking-queue = ResizableCapacityLinkedBlockingQueue
spring.dynamic.thread-pool.executors[1].execute-time-out = 800
spring.dynamic.thread-pool.executors[1].rejected-handler = AbortPolicy
spring.dynamic.thread-pool.executors[1].keep-alive-time = 6691
spring.dynamic.thread-pool.executors[1].allow-core-thread-time-out = true
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 = nobodyiam

@ -13,9 +13,6 @@ env=dev
apollo.configService=http://127.0.0.1:8080
spring.profiles.active=dev
spring.application.name=hippo4j-config-apollo-spring-boot-starter-example
management.metrics.export.prometheus.enabled=true
management.server.port=29998
management.endpoints.web.exposure.include=*
spring.dynamic.thread-pool.enable=true
spring.dynamic.thread-pool.banner=true
@ -25,6 +22,7 @@ spring.dynamic.thread-pool.monitor.collect-types=micrometer
spring.dynamic.thread-pool.monitor.thread-pool-types=dynamic
spring.dynamic.thread-pool.monitor.initial-delay=3000
spring.dynamic.thread-pool.monitor.collect-interval=3000
spring.dynamic.thread-pool.monitor.agent-micrometer-port=29999
spring.dynamic.thread-pool.notify-platforms[0].platform=LARK
spring.dynamic.thread-pool.notify-platforms[0].token=6de41bdc-0799-45be-b128-7cddb9e777f0
@ -51,3 +49,18 @@ spring.dynamic.thread-pool.executors[0].active-alarm = 80
spring.dynamic.thread-pool.executors[0].capacity-alarm = 80
spring.dynamic.thread-pool.executors[0].notify.interval = 8
spring.dynamic.thread-pool.executors[0].notify.receives = nobodyiam
spring.dynamic.thread-pool.executors[1].thread-pool-id = runMessageSendTaskExecutor
spring.dynamic.thread-pool.executors[1].thread-name-prefix = runMessageSendTaskExecutor
spring.dynamic.thread-pool.executors[1].core-pool-size = 3
spring.dynamic.thread-pool.executors[1].maximum-pool-size = 4
spring.dynamic.thread-pool.executors[1].queue-capacity = 1024
spring.dynamic.thread-pool.executors[1].blocking-queue = ResizableCapacityLinkedBlockingQueue
spring.dynamic.thread-pool.executors[1].execute-time-out = 800
spring.dynamic.thread-pool.executors[1].rejected-handler = AbortPolicy
spring.dynamic.thread-pool.executors[1].keep-alive-time = 6691
spring.dynamic.thread-pool.executors[1].allow-core-thread-time-out = true
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 = nobodyiam

@ -11,7 +11,7 @@ spring.cloud.nacos.config.refresh.enabled=true
spring.dynamic.thread-pool.enable=true
spring.dynamic.thread-pool.banner=true
spring.dynamic.thread-pool.check-state-interval=10
spring.dynamic.thread-pool.check-state-interval=3
spring.dynamic.thread-pool.monitor.enable=true
spring.dynamic.thread-pool.monitor.collect-types=micrometer
spring.dynamic.thread-pool.monitor.thread-pool-types=dynamic
@ -26,7 +26,6 @@ spring.dynamic.thread-pool.notify-platforms[0].token=6de41bdc-0799-45be-b128-7cd
#spring.dynamic.thread-pool.notify-platforms[2].platform=DING
#spring.dynamic.thread-pool.notify-platforms[2].token=56417ebba6a27ca352f0de77a2ae9da66d01f39610b5ee8a6033c60ef9071c55
spring.dynamic.thread-pool.nacos.server-addr=127.0.0.1:8848
spring.dynamic.thread-pool.nacos.data-id=dynamic-threadpool-example-config
spring.dynamic.thread-pool.nacos.group=DEFAULT_GROUP
spring.dynamic.thread-pool.nacos.namespace=public
@ -58,3 +57,7 @@ spring.dynamic.thread-pool.executors[1].execute-time-out = 800
spring.dynamic.thread-pool.executors[1].rejected-handler = AbortPolicy
spring.dynamic.thread-pool.executors[1].keep-alive-time = 6691
spring.dynamic.thread-pool.executors[1].allow-core-thread-time-out = true
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 = nobodyiam

@ -32,7 +32,6 @@ spring.dynamic.thread-pool.notify-platforms[0].token=6de41bdc-0799-45be-b128-7cd
#spring.dynamic.thread-pool.notify-platforms[2].platform=DING
#spring.dynamic.thread-pool.notify-platforms[2].token=56417ebba6a27ca352f0de77a2ae9da66d01f39610b5ee8a6033c60ef9071c55
spring.dynamic.thread-pool.nacos.server-addr=127.0.0.1:8848
spring.dynamic.thread-pool.nacos.data-id=dynamic-threadpool-example-config
spring.dynamic.thread-pool.nacos.group=DEFAULT_GROUP
spring.dynamic.thread-pool.nacos.namespace=public
@ -54,6 +53,7 @@ spring.dynamic.thread-pool.executors[0].active-alarm = 80
spring.dynamic.thread-pool.executors[0].capacity-alarm = 80
spring.dynamic.thread-pool.executors[0].notify.interval = 8
spring.dynamic.thread-pool.executors[0].notify.receives = nobodyiam
spring.dynamic.thread-pool.executors[1].thread-pool-id = runMessageSendTaskExecutor
spring.dynamic.thread-pool.executors[1].thread-name-prefix = runMessageSendTaskExecutor
spring.dynamic.thread-pool.executors[1].core-pool-size = 3
@ -64,3 +64,7 @@ spring.dynamic.thread-pool.executors[1].execute-time-out = 800
spring.dynamic.thread-pool.executors[1].rejected-handler = AbortPolicy
spring.dynamic.thread-pool.executors[1].keep-alive-time = 6691
spring.dynamic.thread-pool.executors[1].allow-core-thread-time-out = true
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 = nobodyiam

@ -31,10 +31,13 @@ import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.io.BufferedWriter;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Optional;
@ -198,6 +201,18 @@ public class HttpUtil {
return executeJson(url, HttpMethod.POST, json, null);
}
/**
* Send a post network request.
*
* @param url target url
* @param json json data
* @param headers headers
* @return
*/
public static String postJson(String url, String json, Map<String, String> headers) {
return executeJson(url, HttpMethod.POST, json, headers);
}
/**
* Send a put network request.
*
@ -310,8 +325,10 @@ public class HttpUtil {
byte[] b = bodyString.getBytes();
connection.setRequestProperty(CONTENT_LENGTH, String.valueOf(b.length));
OutputStream outputStream = connection.getOutputStream();
outputStream.write(b, 0, b.length);
outputStream.flush();
OutputStreamWriter osw = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
BufferedWriter writer = new BufferedWriter(osw);
writer.write(bodyString);
writer.flush();
IoUtil.closeQuietly(outputStream);
}
connection.connect();

@ -239,9 +239,6 @@ public class DefaultThreadPoolCheckAlarmHandler implements Runnable, ThreadPoolC
/**
* Terminates the scheduled tasks and asynchronous alarm notifications by
* forcefully shutting down the respective thread pools.
*
* @see alarmNotifyExecutor
* @see asyncAlarmNotifyExecutor
*/
public void destroyScheduleExecute() {
alarmNotifyExecutor.shutdownNow();

@ -34,6 +34,7 @@ import java.util.List;
* Json config parser.
*/
public class JsonConfigParser extends AbstractConfigParser {
private static final ObjectMapper MAPPER;
private static final String DOT = ".";
private static final String LEFT_BRACE = "{";
@ -91,7 +92,7 @@ public class JsonConfigParser extends AbstractConfigParser {
return new HashMap<>(1);
}
return doParse(content,"");
return doParse(content, "");
}
@Override

@ -43,6 +43,8 @@ import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@ -154,7 +156,9 @@ public class LarkSendMessageHandler implements SendMessageHandler {
private void execute(String secretKey, String text) {
String serverUrl = LarkAlarmConstants.LARK_BOT_URL + secretKey;
try {
String responseBody = HttpUtil.postJson(serverUrl, text);
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json; charset=UTF-8");
String responseBody = HttpUtil.postJson(serverUrl, text, headers);
LarkRobotResponse response = JSONUtil.parseObject(responseBody, LarkRobotResponse.class);
Assert.isTrue(response != null, "Response is null.");
if (response.getCode() != 0) {

@ -17,12 +17,11 @@
package cn.hippo4j.threadpool.message.core.service;
import cn.hippo4j.threadpool.message.api.NotifyConfigDTO;
import cn.hippo4j.threadpool.message.core.request.AlarmNotifyRequest;
import cn.hippo4j.threadpool.message.core.request.ChangeParameterNotifyRequest;
import cn.hippo4j.threadpool.message.core.request.WebChangeParameterNotifyRequest;
import cn.hippo4j.threadpool.message.api.NotifyConfigDTO;
import lombok.SneakyThrows;
import org.springframework.core.io.ClassPathResource;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
@ -70,9 +69,9 @@ public interface SendMessageHandler {
default String readUtf8String(String path) {
int endFlagCode = -1;
String resultReadStr;
ClassPathResource classPathResource = new ClassPathResource(path);
ClassLoader classLoader = this.getClass().getClassLoader();
try (
InputStream inputStream = classPathResource.getInputStream();
InputStream inputStream = classLoader.getResourceAsStream(path);
BufferedInputStream bis = new BufferedInputStream(inputStream);
ByteArrayOutputStream buf = new ByteArrayOutputStream()) {
int result = bis.read();

@ -68,7 +68,7 @@ public class ZipkinExecutorAdapterTest {
@Test
public void testReplace() {
Object executor = new CustomWrappingExecutorService(Executors.newCachedThreadPool());
CustomWrappingExecutorService executorChange = (CustomWrappingExecutorService)executor;
CustomWrappingExecutorService executorChange = (CustomWrappingExecutorService) executor;
ExecutorService beforeReplace = executorChange.delegate();
zipkinExecutorAdapter.replace(executor, dynamicThreadPool);
ExecutorService afterReplace = executorChange.delegate();

Loading…
Cancel
Save