Merge branch 'opengoofy:develop' into develop

pull/1243/head
Sakuragi27 2 years ago committed by GitHub
commit 545052bced
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -42,7 +42,7 @@ import static cn.hippo4j.common.constant.ChangeThreadPoolConstants.CHANGE_DELIMI
@Slf4j @Slf4j
public class AlibabaDubboThreadPoolAdapter implements ThreadPoolAdapter, ApplicationListener<ApplicationStartedEvent> { public class AlibabaDubboThreadPoolAdapter implements ThreadPoolAdapter, ApplicationListener<ApplicationStartedEvent> {
private final Map<String, ThreadPoolExecutor> DUBBO_PROTOCOL_EXECUTOR = new HashMap<>(); private final Map<String, ThreadPoolExecutor> dubboProtocolExecutor = new HashMap<>();
@Override @Override
public String mark() { public String mark() {
@ -52,7 +52,7 @@ public class AlibabaDubboThreadPoolAdapter implements ThreadPoolAdapter, Applica
@Override @Override
public ThreadPoolAdapterState getThreadPoolState(String identify) { public ThreadPoolAdapterState getThreadPoolState(String identify) {
ThreadPoolAdapterState threadPoolAdapterState = new ThreadPoolAdapterState(); ThreadPoolAdapterState threadPoolAdapterState = new ThreadPoolAdapterState();
ThreadPoolExecutor executor = DUBBO_PROTOCOL_EXECUTOR.get(identify); ThreadPoolExecutor executor = dubboProtocolExecutor.get(identify);
if (executor == null) { if (executor == null) {
log.warn("[{}] Alibaba Dubbo consuming thread pool not found.", identify); log.warn("[{}] Alibaba Dubbo consuming thread pool not found.", identify);
return threadPoolAdapterState; return threadPoolAdapterState;
@ -66,14 +66,14 @@ public class AlibabaDubboThreadPoolAdapter implements ThreadPoolAdapter, Applica
@Override @Override
public List<ThreadPoolAdapterState> getThreadPoolStates() { public List<ThreadPoolAdapterState> getThreadPoolStates() {
List<ThreadPoolAdapterState> threadPoolAdapterStates = new ArrayList<>(); List<ThreadPoolAdapterState> threadPoolAdapterStates = new ArrayList<>();
DUBBO_PROTOCOL_EXECUTOR.forEach((key, val) -> threadPoolAdapterStates.add(getThreadPoolState(String.valueOf(key)))); dubboProtocolExecutor.forEach((key, val) -> threadPoolAdapterStates.add(getThreadPoolState(String.valueOf(key))));
return threadPoolAdapterStates; return threadPoolAdapterStates;
} }
@Override @Override
public boolean updateThreadPool(ThreadPoolAdapterParameter threadPoolAdapterParameter) { public boolean updateThreadPool(ThreadPoolAdapterParameter threadPoolAdapterParameter) {
String threadPoolKey = threadPoolAdapterParameter.getThreadPoolKey(); String threadPoolKey = threadPoolAdapterParameter.getThreadPoolKey();
ThreadPoolExecutor executor = DUBBO_PROTOCOL_EXECUTOR.get(threadPoolAdapterParameter.getThreadPoolKey()); ThreadPoolExecutor executor = dubboProtocolExecutor.get(threadPoolAdapterParameter.getThreadPoolKey());
if (executor == null) { if (executor == null) {
log.warn("[{}] Alibaba Dubbo consuming thread pool not found.", threadPoolKey); log.warn("[{}] Alibaba Dubbo consuming thread pool not found.", threadPoolKey);
return false; return false;
@ -94,7 +94,7 @@ public class AlibabaDubboThreadPoolAdapter implements ThreadPoolAdapter, Applica
try { try {
DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension(); DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
Map<String, Object> executors = dataStore.get(poolKey); Map<String, Object> executors = dataStore.get(poolKey);
executors.forEach((key, value) -> DUBBO_PROTOCOL_EXECUTOR.put(key, (ThreadPoolExecutor) value)); executors.forEach((key, value) -> dubboProtocolExecutor.put(key, (ThreadPoolExecutor) value));
} catch (Exception ex) { } catch (Exception ex) {
log.error("Failed to get Alibaba Dubbo protocol thread pool", ex); log.error("Failed to get Alibaba Dubbo protocol thread pool", ex);
} }

@ -46,7 +46,7 @@ import static cn.hippo4j.common.constant.ChangeThreadPoolConstants.CHANGE_DELIMI
@Slf4j @Slf4j
public class DubboThreadPoolAdapter implements ThreadPoolAdapter, ApplicationListener<ApplicationStartedEvent> { public class DubboThreadPoolAdapter implements ThreadPoolAdapter, ApplicationListener<ApplicationStartedEvent> {
private final Map<String, ThreadPoolExecutor> DUBBO_PROTOCOL_EXECUTOR = new HashMap<>(); private final Map<String, ThreadPoolExecutor> dubboProtocolExecutor = new HashMap<>();
@Override @Override
public String mark() { public String mark() {
@ -56,7 +56,7 @@ public class DubboThreadPoolAdapter implements ThreadPoolAdapter, ApplicationLis
@Override @Override
public ThreadPoolAdapterState getThreadPoolState(String identify) { public ThreadPoolAdapterState getThreadPoolState(String identify) {
ThreadPoolAdapterState threadPoolAdapterState = new ThreadPoolAdapterState(); ThreadPoolAdapterState threadPoolAdapterState = new ThreadPoolAdapterState();
ThreadPoolExecutor executor = DUBBO_PROTOCOL_EXECUTOR.get(identify); ThreadPoolExecutor executor = dubboProtocolExecutor.get(identify);
if (executor == null) { if (executor == null) {
log.warn("[{}] Dubbo consuming thread pool not found.", identify); log.warn("[{}] Dubbo consuming thread pool not found.", identify);
return threadPoolAdapterState; return threadPoolAdapterState;
@ -70,14 +70,14 @@ public class DubboThreadPoolAdapter implements ThreadPoolAdapter, ApplicationLis
@Override @Override
public List<ThreadPoolAdapterState> getThreadPoolStates() { public List<ThreadPoolAdapterState> getThreadPoolStates() {
List<ThreadPoolAdapterState> threadPoolAdapterStates = new ArrayList<>(); List<ThreadPoolAdapterState> threadPoolAdapterStates = new ArrayList<>();
DUBBO_PROTOCOL_EXECUTOR.forEach((key, val) -> threadPoolAdapterStates.add(getThreadPoolState(String.valueOf(key)))); dubboProtocolExecutor.forEach((key, val) -> threadPoolAdapterStates.add(getThreadPoolState(String.valueOf(key))));
return threadPoolAdapterStates; return threadPoolAdapterStates;
} }
@Override @Override
public boolean updateThreadPool(ThreadPoolAdapterParameter threadPoolAdapterParameter) { public boolean updateThreadPool(ThreadPoolAdapterParameter threadPoolAdapterParameter) {
String threadPoolKey = threadPoolAdapterParameter.getThreadPoolKey(); String threadPoolKey = threadPoolAdapterParameter.getThreadPoolKey();
ThreadPoolExecutor executor = DUBBO_PROTOCOL_EXECUTOR.get(threadPoolAdapterParameter.getThreadPoolKey()); ThreadPoolExecutor executor = dubboProtocolExecutor.get(threadPoolAdapterParameter.getThreadPoolKey());
if (executor == null) { if (executor == null) {
log.warn("[{}] Dubbo consuming thread pool not found.", threadPoolKey); log.warn("[{}] Dubbo consuming thread pool not found.", threadPoolKey);
return false; return false;
@ -105,14 +105,14 @@ public class DubboThreadPoolAdapter implements ThreadPoolAdapter, ApplicationLis
if (isLegacyVersion) { if (isLegacyVersion) {
DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension(); DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
Map<String, Object> executors = dataStore.get(poolKey); Map<String, Object> executors = dataStore.get(poolKey);
executors.forEach((key, value) -> DUBBO_PROTOCOL_EXECUTOR.put(key, (ThreadPoolExecutor) value)); executors.forEach((key, value) -> dubboProtocolExecutor.put(key, (ThreadPoolExecutor) value));
return; return;
} }
ExecutorRepository executorRepository = ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension(); ExecutorRepository executorRepository = ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension();
ConcurrentMap<String, ConcurrentMap<Integer, ExecutorService>> data = ConcurrentMap<String, ConcurrentMap<Integer, ExecutorService>> data =
(ConcurrentMap<String, ConcurrentMap<Integer, ExecutorService>>) ReflectUtil.getFieldValue(executorRepository, "data"); (ConcurrentMap<String, ConcurrentMap<Integer, ExecutorService>>) ReflectUtil.getFieldValue(executorRepository, "data");
ConcurrentMap<Integer, ExecutorService> executorServiceMap = data.get(poolKey); ConcurrentMap<Integer, ExecutorService> executorServiceMap = data.get(poolKey);
executorServiceMap.forEach((key, value) -> DUBBO_PROTOCOL_EXECUTOR.put(String.valueOf(key), (ThreadPoolExecutor) value)); executorServiceMap.forEach((key, value) -> dubboProtocolExecutor.put(String.valueOf(key), (ThreadPoolExecutor) value));
} catch (Exception ex) { } catch (Exception ex) {
log.error("Failed to get Dubbo {} protocol thread pool", Version.getVersion(), ex); log.error("Failed to get Dubbo {} protocol thread pool", Version.getVersion(), ex);
} }

@ -113,6 +113,9 @@ public abstract class AbstractHystrixThreadPoolAdapter implements ThreadPoolAdap
scheduler.schedule(hystrixThreadPoolRefreshTask, taskIntervalSeconds, TimeUnit.SECONDS); scheduler.schedule(hystrixThreadPoolRefreshTask, taskIntervalSeconds, TimeUnit.SECONDS);
} }
/**
* hystrix thread-pool refresh task
*/
class HystrixThreadPoolRefreshTask implements Runnable { class HystrixThreadPoolRefreshTask implements Runnable {
private final ScheduledExecutorService scheduler; private final ScheduledExecutorService scheduler;

@ -111,11 +111,11 @@ collector.is_resolve_dns_periodically=${SW_AGENT_COLLECTOR_IS_RESOLVE_DNS_PERIOD
# Logging level # Logging level
logging.level=${SW_LOGGING_LEVEL:INFO} logging.level=${SW_LOGGING_LEVEL:INFO}
# Logging file_name # Logging file_name
logging.file_name=${SW_LOGGING_FILE_NAME:skywalking-api.log} logging.file_name=${SW_LOGGING_FILE_NAME:hippo4j-api.log}
# Log output. Default is FILE. Use CONSOLE means output to stdout. # Log output. Default is FILE. Use CONSOLE means output to stdout.
logging.output=${SW_LOGGING_OUTPUT:FILE} logging.output=${SW_LOGGING_OUTPUT:FILE}
# Log files directory. Default is blank string, meaning use "{theSkywalkingAgentJarDir}/logs " to output logs. # Log files directory. Default is blank string, meaning use "{theHippo4jAgentJarDir}/logs " to output logs.
# {theSkywalkingAgentJarDir} is the directory where the skywalking agent jar file is located # {theHippo4jAgentJarDir} is the directory where the hippo4j agent jar file is located
logging.dir=${SW_LOGGING_DIR:} logging.dir=${SW_LOGGING_DIR:}
# Logger resolver: PATTERN or JSON. The default is PATTERN, which uses logging.pattern to print traditional text logs. # Logger resolver: PATTERN or JSON. The default is PATTERN, which uses logging.pattern to print traditional text logs.
# JSON resolver prints logs in JSON format. # JSON resolver prints logs in JSON format.

@ -96,7 +96,7 @@
</goals> </goals>
<configuration> <configuration>
<target> <target>
<delete dir="${project.basedir}/../skywalking-agent" /> <delete dir="${project.basedir}/../hippo4j-agent" />
</target> </target>
</configuration> </configuration>
</execution> </execution>

@ -48,7 +48,7 @@ public class SpringBootConfigInitializer {
return SPRING_PROPERTIES == null || SPRING_PROPERTIES.isEmpty(); return SPRING_PROPERTIES == null || SPRING_PROPERTIES.isEmpty();
} }
public static synchronized void initializeConfig(SpringBootConfig springBootConfig) { public static synchronized void initializeConfig(SpringBootConfigNode springBootConfig) {
if (SPRING_PROPERTIES != null) { if (SPRING_PROPERTIES != null) {
try { try {
LOG.info("initialize Spring Config Class {}.", springBootConfig.root()); LOG.info("initialize Spring Config Class {}.", springBootConfig.root());

@ -24,7 +24,7 @@ import java.lang.annotation.Target;
@Target({ElementType.TYPE}) @Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface SpringBootConfig { public @interface SpringBootConfigNode {
/** /**
* @return Class as the root to do config initialization. * @return Class as the root to do config initialization.

@ -20,7 +20,7 @@ package cn.hippo4j.agent.core.plugin.loader;
import cn.hippo4j.agent.core.boot.AgentPackageNotFoundException; import cn.hippo4j.agent.core.boot.AgentPackageNotFoundException;
import cn.hippo4j.agent.core.boot.AgentPackagePath; import cn.hippo4j.agent.core.boot.AgentPackagePath;
import cn.hippo4j.agent.core.boot.PluginConfig; import cn.hippo4j.agent.core.boot.PluginConfig;
import cn.hippo4j.agent.core.boot.SpringBootConfig; import cn.hippo4j.agent.core.boot.SpringBootConfigNode;
import cn.hippo4j.agent.core.boot.SpringBootConfigInitializer; import cn.hippo4j.agent.core.boot.SpringBootConfigInitializer;
import cn.hippo4j.agent.core.conf.Config; import cn.hippo4j.agent.core.conf.Config;
import cn.hippo4j.agent.core.conf.SnifferConfigInitializer; import cn.hippo4j.agent.core.conf.SnifferConfigInitializer;
@ -171,7 +171,7 @@ public class AgentClassLoader extends ClassLoader {
SnifferConfigInitializer.initializeConfig(pluginConfig.root()); SnifferConfigInitializer.initializeConfig(pluginConfig.root());
} }
final SpringBootConfig springBootConfig = loadedClass.getAnnotation(SpringBootConfig.class); final SpringBootConfigNode springBootConfig = loadedClass.getAnnotation(SpringBootConfigNode.class);
if (springBootConfig != null) { if (springBootConfig != null) {
// Set up the plugin config when loaded by spring environment is prepared, just scan in here. // Set up the plugin config when loaded by spring environment is prepared, just scan in here.
// Agent class loader just loaded limited classes in the plugin jar(s), so the cost of this // Agent class loader just loaded limited classes in the plugin jar(s), so the cost of this

@ -31,7 +31,7 @@ public class ApolloInstrumentation extends ClassInstanceMethodsEnhancePluginDefi
private static final String ENHANCE_CLASS = "com.ctrip.framework.apollo.internals.DefaultConfig"; 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"; private static final String CONSTRUCTOR_INTERCEPT_CLASS = "cn.hippo4j.agent.plugin.apollo.interceptor.DefaultConfigConstructorInterceptor";
@Override @Override
protected ClassMatch enhanceClass() { protected ClassMatch enhanceClass() {

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
package cn.hippo4j.agent.plugin.apollo; package cn.hippo4j.agent.plugin.apollo.interceptor;
import cn.hippo4j.agent.core.plugin.interceptor.enhance.EnhancedInstance; import cn.hippo4j.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import cn.hippo4j.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; import cn.hippo4j.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;

@ -42,19 +42,6 @@
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>${apollo.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>cn.hippo4j</groupId> <groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-config-spring-boot-1x-starter</artifactId> <artifactId>hippo4j-config-spring-boot-1x-starter</artifactId>

@ -0,0 +1,69 @@
/*
* 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.plugin.spring.common.support.AbstractDynamicThreadPoolChangeHandlerSpring;
import cn.hippo4j.common.toolkit.MapUtil;
import cn.hippo4j.config.springboot.starter.config.BootstrapConfigProperties;
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.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static cn.hippo4j.config.springboot1x.starter.refresher.SpringBoot1xBootstrapConfigPropertiesBinderAdapt.getNames;
public class DynamicThreadPoolChangeHandlerSpring1x extends AbstractDynamicThreadPoolChangeHandlerSpring {
public DynamicThreadPoolChangeHandlerSpring1x(ConfigurableApplicationContext context) {
super(context);
}
protected BootstrapConfigProperties bindProperties(Map<Object, Object> configInfo, ApplicationContext applicationContext) {
BootstrapConfigProperties bindableCoreProperties = new BootstrapConfigProperties();
if (MapUtil.isEmpty(configInfo)) {
return bindableCoreProperties;
}
RelaxedNames relaxedNames = new RelaxedNames(BootstrapConfigProperties.PREFIX);
Set<String> names = getNames(bindableCoreProperties, relaxedNames);
Map<String, Object> stringConfigInfo = new HashMap<>(configInfo.size());
configInfo.forEach((key, value) -> stringConfigInfo.put(key.toString(), value));
MapPropertySource test = new MapPropertySource("Hippo4j", stringConfigInfo);
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(test);
PropertyValues propertyValues = CustomPropertyNamePatternsMatcher.getPropertySourcesPropertyValues(names, propertySources);
RelaxedDataBinder dataBinder = new RelaxedDataBinder(bindableCoreProperties, BootstrapConfigProperties.PREFIX);
dataBinder.setAutoGrowCollectionLimit(Integer.MAX_VALUE);
dataBinder.setIgnoreNestedProperties(false);
dataBinder.setIgnoreInvalidFields(false);
dataBinder.setIgnoreUnknownFields(true);
ResourceEditorRegistrar resourceEditorRegistrar = new ResourceEditorRegistrar(applicationContext, applicationContext.getEnvironment());
resourceEditorRegistrar.registerCustomEditors(dataBinder);
dataBinder.bind(propertyValues);
return bindableCoreProperties;
}
}

@ -31,8 +31,8 @@ public class EventPublishingRunListenerInstrumentation extends ClassInstanceMeth
private static final String ENHANCE_CLASS = "org.springframework.boot.context.event.EventPublishingRunListener"; 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_FINISHED_INTERCEPTOR = "cn.hippo4j.agent.plugin.spring.boot.v1.interceptor.EventPublishingFinishedInterceptor";
private static final String EVENT_PUBLISHING_ENVIRONMENT_PREPARED_INTERCEPTOR = "cn.hippo4j.agent.plugin.spring.boot.v1.EventPublishingRunListenerEnvironmentPreparedInterceptor"; private static final String EVENT_PUBLISHING_ENVIRONMENT_PREPARED_INTERCEPTOR = "cn.hippo4j.agent.plugin.spring.common.interceptor.EventPublishingRunListenerEnvironmentPreparedInterceptor";
@Override @Override
protected ClassMatch enhanceClass() { protected ClassMatch enhanceClass() {

@ -1,68 +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.v1.define;
import cn.hippo4j.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import cn.hippo4j.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import cn.hippo4j.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import cn.hippo4j.agent.core.plugin.match.ClassMatch;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import static cn.hippo4j.agent.core.plugin.match.NameMatch.byName;
import static net.bytebuddy.matcher.ElementMatchers.named;
public class SpringApplicationRunInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final String ENHANCE_CLASS = "org.springframework.boot.SpringApplication";
private static final String SPRING_APPLICATION_RUN_INTERCEPTOR = "cn.hippo4j.agent.plugin.spring.boot.v1.SpringApplicationRunInterceptor";
@Override
protected ClassMatch enhanceClass() {
return byName(ENHANCE_CLASS);
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("run");
}
@Override
public String getMethodsInterceptor() {
return SPRING_APPLICATION_RUN_INTERCEPTOR;
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}

@ -0,0 +1,64 @@
/*
* 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.interceptor;
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.plugin.spring.boot.v1.DynamicThreadPoolChangeHandlerSpring1x;
import cn.hippo4j.agent.plugin.spring.common.support.SpringPropertiesLoader;
import cn.hippo4j.agent.plugin.spring.common.support.IDynamicThreadPoolChangeHandlerSpring;
import cn.hippo4j.agent.plugin.spring.common.support.SpringThreadPoolRegisterSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import java.lang.reflect.Method;
public class EventPublishingFinishedInterceptor implements InstanceMethodsAroundInterceptor {
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 {
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
ConfigurableApplicationContext context = (ConfigurableApplicationContext) allArguments[0];
if (context.getParent() != null) {
// After the child container is started, the thread pool registration will be carried out
SpringThreadPoolRegisterSupport.registerThreadPoolInstances();
return ret;
}
SpringPropertiesLoader.loadSpringProperties(context.getEnvironment());
IDynamicThreadPoolChangeHandlerSpring handlerSpring1x = new DynamicThreadPoolChangeHandlerSpring1x(context);
handlerSpring1x.registerApolloConfigHandler();
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
}
}

@ -14,5 +14,4 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
spring-boot-1.x=cn.hippo4j.agent.plugin.spring.boot.v1.define.EventPublishingRunListenerInstrumentation spring-boot-1.x=cn.hippo4j.agent.plugin.spring.boot.v1.define.EventPublishingRunListenerInstrumentation
spring-boot-1.x=cn.hippo4j.agent.plugin.spring.boot.v1.define.SpringApplicationRunInstrumentation

@ -25,9 +25,15 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId> <artifactId>spring-boot-starter</artifactId>
<version>${spring.boot.version}</version> <version>${spring.boot.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-config-spring-boot-starter</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

@ -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.plugin.spring.boot.v2;
import cn.hippo4j.agent.plugin.spring.common.support.AbstractDynamicThreadPoolChangeHandlerSpring;
import cn.hippo4j.config.springboot.starter.config.BootstrapConfigProperties;
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 org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.Map;
public class DynamicThreadPoolChangeHandlerSpring2x extends AbstractDynamicThreadPoolChangeHandlerSpring {
public DynamicThreadPoolChangeHandlerSpring2x(ConfigurableApplicationContext context) {
super(context);
}
@Override
protected BootstrapConfigProperties bindProperties(Map<Object, Object> configInfo, ApplicationContext applicationContext) {
BootstrapConfigProperties bindableBootstrapConfigProperties = new BootstrapConfigProperties();
ConfigurationPropertySource sources = new MapConfigurationPropertySource(configInfo);
Binder binder = new Binder(sources);
return binder.bind(BootstrapConfigProperties.PREFIX, Bindable.ofInstance(bindableBootstrapConfigProperties)).get();
}
}

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

@ -15,14 +15,17 @@
* limitations under the License. * limitations under the License.
*/ */
package cn.hippo4j.agent.plugin.spring.boot.v2; package cn.hippo4j.agent.plugin.spring.boot.v2.interceptor;
import cn.hippo4j.agent.core.logging.api.ILog; import cn.hippo4j.agent.core.logging.api.ILog;
import cn.hippo4j.agent.core.logging.api.LogManager; 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.EnhancedInstance;
import cn.hippo4j.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; import cn.hippo4j.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import cn.hippo4j.agent.core.plugin.interceptor.enhance.MethodInterceptResult; import cn.hippo4j.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import cn.hippo4j.agent.plugin.spring.common.SpringPropertiesLoader; import cn.hippo4j.agent.plugin.spring.boot.v2.DynamicThreadPoolChangeHandlerSpring2x;
import cn.hippo4j.agent.plugin.spring.common.support.SpringPropertiesLoader;
import cn.hippo4j.agent.plugin.spring.common.support.IDynamicThreadPoolChangeHandlerSpring;
import cn.hippo4j.agent.plugin.spring.common.support.SpringThreadPoolRegisterSupport;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -39,7 +42,15 @@ public class EventPublishingStartedInterceptor implements InstanceMethodsAroundI
@Override @Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable { public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
ConfigurableApplicationContext context = (ConfigurableApplicationContext) allArguments[0]; ConfigurableApplicationContext context = (ConfigurableApplicationContext) allArguments[0];
if (context.getParent() != null) {
// After the child container is started, the thread pool registration will be carried out
SpringThreadPoolRegisterSupport.registerThreadPoolInstances();
return ret;
}
SpringPropertiesLoader.loadSpringProperties(context.getEnvironment()); SpringPropertiesLoader.loadSpringProperties(context.getEnvironment());
IDynamicThreadPoolChangeHandlerSpring handler = new DynamicThreadPoolChangeHandlerSpring2x(context);
handler.registerApolloConfigHandler();
return ret; return ret;
} }

@ -17,6 +17,31 @@
<artifactId>spring-core</artifactId> <artifactId>spring-core</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>${apollo.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-config-spring-boot-starter</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

@ -15,23 +15,23 @@
* limitations under the License. * limitations under the License.
*/ */
package cn.hippo4j.agent.plugin.spring.boot.v1; package cn.hippo4j.agent.plugin.spring.common.conf;
import cn.hippo4j.agent.core.boot.SpringBootConfig; import cn.hippo4j.agent.core.boot.SpringBootConfigNode;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
public class ApolloSpringBootProperties { public class SpringBootConfig {
public static class Spring { public static class Spring {
public static class Dynamic { public static class Dynamic {
@SpringBootConfig(root = ApolloSpringBootProperties.class) @SpringBootConfigNode(root = SpringBootConfig.class)
public static class Thread_Pool { public static class Thread_Pool {
@SpringBootConfig(root = ApolloSpringBootProperties.class) @SpringBootConfigNode(root = SpringBootConfig.class)
public static class Apollo { public static class Apollo {
public static List<String> NAMESPACE = Arrays.asList("application"); public static List<String> NAMESPACE = Arrays.asList("application");

@ -15,12 +15,12 @@
* limitations under the License. * limitations under the License.
*/ */
package cn.hippo4j.agent.plugin.spring.boot.v1; package cn.hippo4j.agent.plugin.spring.common.interceptor;
import cn.hippo4j.agent.core.plugin.interceptor.enhance.EnhancedInstance; 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.InstanceMethodsAroundInterceptor;
import cn.hippo4j.agent.core.plugin.interceptor.enhance.MethodInterceptResult; import cn.hippo4j.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import cn.hippo4j.agent.plugin.spring.common.SpringEnvironmentSupport; import cn.hippo4j.agent.plugin.spring.common.support.SpringEnvironmentSupport;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;

@ -15,25 +15,19 @@
* limitations under the License. * limitations under the License.
*/ */
package cn.hippo4j.agent.plugin.spring.boot.v1; package cn.hippo4j.agent.plugin.spring.common.support;
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.AgentThreadPoolExecutorHolder;
import cn.hippo4j.agent.core.registry.AgentThreadPoolInstanceRegistry; import cn.hippo4j.agent.core.registry.AgentThreadPoolInstanceRegistry;
import cn.hippo4j.agent.core.util.ThreadPoolPropertyKey; import cn.hippo4j.agent.core.util.ThreadPoolPropertyKey;
import cn.hippo4j.agent.plugin.spring.common.SpringPropertiesLoader; import cn.hippo4j.agent.plugin.spring.common.conf.SpringBootConfig;
import cn.hippo4j.common.config.ExecutorProperties;
import cn.hippo4j.common.executor.support.BlockingQueueTypeEnum; import cn.hippo4j.common.executor.support.BlockingQueueTypeEnum;
import cn.hippo4j.common.executor.support.RejectedPolicyTypeEnum; import cn.hippo4j.common.executor.support.RejectedPolicyTypeEnum;
import cn.hippo4j.common.executor.support.ResizableCapacityLinkedBlockingQueue; import cn.hippo4j.common.executor.support.ResizableCapacityLinkedBlockingQueue;
import cn.hippo4j.common.toolkit.CollectionUtil; import cn.hippo4j.common.toolkit.CollectionUtil;
import cn.hippo4j.common.toolkit.MapUtil;
import cn.hippo4j.common.toolkit.ThreadPoolExecutorUtil; import cn.hippo4j.common.toolkit.ThreadPoolExecutorUtil;
import cn.hippo4j.config.springboot.starter.config.BootstrapConfigProperties; 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.ConfigFileTypeEnum;
import cn.hippo4j.config.springboot.starter.parser.ConfigParserHandler; import cn.hippo4j.config.springboot.starter.parser.ConfigParserHandler;
import cn.hippo4j.core.executor.DynamicThreadPoolExecutor; import cn.hippo4j.core.executor.DynamicThreadPoolExecutor;
@ -45,24 +39,15 @@ import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import com.ctrip.framework.apollo.model.ConfigChange; import com.ctrip.framework.apollo.model.ConfigChange;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import java.lang.reflect.Method;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Properties; import java.util.Properties;
import java.util.Set;
import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -70,27 +55,23 @@ import java.util.concurrent.TimeUnit;
import static cn.hippo4j.agent.core.conf.Constants.SPRING_BOOT_CONFIG_PREFIX; 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_DELIMITER;
import static cn.hippo4j.common.constant.ChangeThreadPoolConstants.CHANGE_THREAD_POOL_TEXT; 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 { public abstract class AbstractDynamicThreadPoolChangeHandlerSpring implements IDynamicThreadPoolChangeHandlerSpring {
private static final ILog FILE_LOGGER = LogManager.getLogger(EventPublishingFinishedInterceptor.class); private static final Logger LOGGER = LoggerFactory.getLogger(AbstractDynamicThreadPoolChangeHandlerSpring.class);
private static final Logger LOGGER = LoggerFactory.getLogger(EventPublishingFinishedInterceptor.class);
@Override private final ConfigurableApplicationContext applicationContext;
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
public AbstractDynamicThreadPoolChangeHandlerSpring(ConfigurableApplicationContext context) {
this.applicationContext = context;
} }
@Override public void registerApolloConfigHandler() {
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
ConfigurableApplicationContext context = (ConfigurableApplicationContext) allArguments[0];
SpringPropertiesLoader.loadSpringProperties(context.getEnvironment());
List<String> apolloNamespaces = ApolloSpringBootProperties.Spring.Dynamic.Thread_Pool.Apollo.NAMESPACE;
List<String> apolloNamespaces = SpringBootConfig.Spring.Dynamic.Thread_Pool.Apollo.NAMESPACE;
String namespace = apolloNamespaces.get(0); String namespace = apolloNamespaces.get(0);
String configFileType = ApolloSpringBootProperties.Spring.Dynamic.Thread_Pool.CONFIG_FILE_TYPE; String configFileType = SpringBootConfig.Spring.Dynamic.Thread_Pool.CONFIG_FILE_TYPE;
com.ctrip.framework.apollo.Config config = ConfigService.getConfig(String.format("%s.%s", namespace, configFileType)); com.ctrip.framework.apollo.Config config = ConfigService.getConfig(String.format("%s.%s", namespace, configFileType));
ConfigChangeListener configChangeListener = configChangeEvent -> { ConfigChangeListener configChangeListener = configChangeEvent -> {
String replacedNamespace = namespace.replaceAll("." + configFileType, ""); String replacedNamespace = namespace.replaceAll("." + configFileType, "");
@ -102,40 +83,17 @@ public class EventPublishingFinishedInterceptor implements InstanceMethodsAround
String newValue = change.getNewValue(); String newValue = change.getNewValue();
newChangeValueMap.put(each, newValue); newChangeValueMap.put(each, newValue);
}); });
dynamicRefresh(configFile.getContent(), newChangeValueMap, context); dynamicRefresh(configFile.getContent(), newChangeValueMap, applicationContext);
}; };
config.addChangeListener(configChangeListener); config.addChangeListener(configChangeListener);
LOGGER.info("Dynamic thread pool refresher, add apollo listener success. namespace: {}", namespace); LOGGER.info("[Hippo4j-Agent] Dynamic thread pool refresher, add apollo listener success. namespace: {}", namespace);
return ret;
} }
public BootstrapConfigProperties bindProperties(Map<Object, Object> configInfo, ApplicationContext applicationContext) { protected abstract BootstrapConfigProperties bindProperties(Map<Object, Object> configInfo, ApplicationContext applicationContext);
BootstrapConfigProperties bindableCoreProperties = new BootstrapConfigProperties();
if (MapUtil.isEmpty(configInfo)) {
return bindableCoreProperties;
}
RelaxedNames relaxedNames = new RelaxedNames(BootstrapConfigProperties.PREFIX);
Set<String> names = getNames(bindableCoreProperties, relaxedNames);
Map<String, Object> stringConfigInfo = new HashMap<>(configInfo.size());
configInfo.forEach((key, value) -> stringConfigInfo.put(key.toString(), value));
MapPropertySource test = new MapPropertySource("Hippo4j", stringConfigInfo);
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(test);
PropertyValues propertyValues = CustomPropertyNamePatternsMatcher.getPropertySourcesPropertyValues(names, propertySources);
RelaxedDataBinder dataBinder = new RelaxedDataBinder(bindableCoreProperties, BootstrapConfigProperties.PREFIX);
dataBinder.setAutoGrowCollectionLimit(Integer.MAX_VALUE);
dataBinder.setIgnoreNestedProperties(false);
dataBinder.setIgnoreInvalidFields(false);
dataBinder.setIgnoreUnknownFields(true);
ResourceEditorRegistrar resourceEditorRegistrar = new ResourceEditorRegistrar(applicationContext, applicationContext.getEnvironment());
resourceEditorRegistrar.registerCustomEditors(dataBinder);
dataBinder.bind(propertyValues);
return bindableCoreProperties;
}
public void dynamicRefresh(String configContent, Map<String, Object> newValueChangeMap, ApplicationContext context) { private void dynamicRefresh(String configContent, Map<String, Object> newValueChangeMap, ApplicationContext context) {
try { try {
String configFileType = ApolloSpringBootProperties.Spring.Dynamic.Thread_Pool.CONFIG_FILE_TYPE; String configFileType = SpringBootConfig.Spring.Dynamic.Thread_Pool.CONFIG_FILE_TYPE;
Map<Object, Object> afterConfigMap = ConfigParserHandler.getInstance().parseConfig(configContent, Map<Object, Object> afterConfigMap = ConfigParserHandler.getInstance().parseConfig(configContent,
ConfigFileTypeEnum.of(configFileType)); ConfigFileTypeEnum.of(configFileType));
@ -319,8 +277,4 @@ public class EventPublishingFinishedInterceptor implements InstanceMethodsAround
&& Objects.equals(BlockingQueueTypeEnum.RESIZABLE_LINKED_BLOCKING_QUEUE.getName(), executor.getQueue().getClass().getSimpleName()))); && Objects.equals(BlockingQueueTypeEnum.RESIZABLE_LINKED_BLOCKING_QUEUE.getName(), executor.getQueue().getClass().getSimpleName())));
} }
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
}
} }

@ -0,0 +1,24 @@
/*
* 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.support;
public interface IDynamicThreadPoolChangeHandlerSpring {
void registerApolloConfigHandler();
}

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
package cn.hippo4j.agent.plugin.spring.common; package cn.hippo4j.agent.plugin.spring.common.support;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.MapPropertySource;

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
package cn.hippo4j.agent.plugin.spring.common; package cn.hippo4j.agent.plugin.spring.common.support;
import cn.hippo4j.agent.core.boot.SpringBootConfigInitializer; import cn.hippo4j.agent.core.boot.SpringBootConfigInitializer;
import cn.hippo4j.agent.core.logging.api.ILog; import cn.hippo4j.agent.core.logging.api.ILog;

@ -15,11 +15,8 @@
* limitations under the License. * limitations under the License.
*/ */
package cn.hippo4j.agent.plugin.spring.boot.v1; package cn.hippo4j.agent.plugin.spring.common.support;
import cn.hippo4j.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import cn.hippo4j.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import cn.hippo4j.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import cn.hippo4j.agent.core.registry.AgentThreadPoolInstanceRegistry; import cn.hippo4j.agent.core.registry.AgentThreadPoolInstanceRegistry;
import cn.hippo4j.agent.core.util.ReflectUtil; import cn.hippo4j.agent.core.util.ReflectUtil;
import cn.hippo4j.agent.core.util.ThreadPoolPropertyKey; import cn.hippo4j.agent.core.util.ThreadPoolPropertyKey;
@ -30,30 +27,17 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class SpringApplicationRunInterceptor implements InstanceMethodsAroundInterceptor { public class SpringThreadPoolRegisterSupport {
private static final Logger LOGGER = LoggerFactory.getLogger(SpringApplicationRunInterceptor.class); private static final Logger LOGGER = LoggerFactory.getLogger(SpringThreadPoolRegisterSupport.class);
@Override public static void registerThreadPoolInstances() {
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
registerThreadPoolInstances();
LOGGER.info("[Hippo4j-Agent] Registered thread pool instances successfully.");
return ret;
}
private void registerThreadPoolInstances() {
Map<ThreadPoolExecutor, Class<?>> earlyConstructMap = AgentThreadPoolInstanceRegistry.getInstance().earlyConstructMap; Map<ThreadPoolExecutor, Class<?>> earlyConstructMap = AgentThreadPoolInstanceRegistry.getInstance().earlyConstructMap;
for (Map.Entry<ThreadPoolExecutor, Class<?>> entry : earlyConstructMap.entrySet()) { for (Map.Entry<ThreadPoolExecutor, Class<?>> entry : earlyConstructMap.entrySet()) {
ThreadPoolExecutor enhancedInstance = entry.getKey(); ThreadPoolExecutor enhancedInstance = entry.getKey();
@ -72,9 +56,10 @@ public class SpringApplicationRunInterceptor implements InstanceMethodsAroundInt
} }
} }
} }
LOGGER.info("[Hippo4j-Agent] Registered thread pool instances successfully.");
} }
private void register(String threadPoolId, ThreadPoolExecutor executor) { public static void register(String threadPoolId, ThreadPoolExecutor executor) {
// build parameter properties. // build parameter properties.
Properties properties = new Properties(); Properties properties = new Properties();
properties.put(ThreadPoolPropertyKey.THREAD_POOL_ID, threadPoolId); properties.put(ThreadPoolPropertyKey.THREAD_POOL_ID, threadPoolId);
@ -92,9 +77,4 @@ public class SpringApplicationRunInterceptor implements InstanceMethodsAroundInt
AgentThreadPoolInstanceRegistry.getInstance().putHolder(threadPoolId, executor, properties); AgentThreadPoolInstanceRegistry.getInstance().putHolder(threadPoolId, executor, properties);
} }
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
}
} }

@ -31,7 +31,7 @@ public class ThreadPoolExecutorInstrumentation extends ClassInstanceMethodsEnhan
private static final String ENHANCE_CLASS = "java.util.concurrent.ThreadPoolExecutor"; 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 String CONSTRUCTOR_INTERCEPT_CLASS = "cn.hippo4j.agent.plugin.thread.pool.interceptor.ThreadPoolExecutorConstructorMethodInterceptor";
private static final int CONSTRUCTOR_INTERCEPT_PARAMETER_LENGTH = 7; private static final int CONSTRUCTOR_INTERCEPT_PARAMETER_LENGTH = 7;

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
package cn.hippo4j.agent.plugin.thread.pool; package cn.hippo4j.agent.plugin.thread.pool.interceptor;
import cn.hippo4j.agent.core.conf.Config; import cn.hippo4j.agent.core.conf.Config;
import cn.hippo4j.agent.core.logging.api.ILog; import cn.hippo4j.agent.core.logging.api.ILog;

@ -77,5 +77,10 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId> <artifactId>spring-boot-configuration-processor</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

@ -102,6 +102,22 @@ public class Constants {
public static final int HEALTH_CHECK_INTERVAL = 5; public static final int HEALTH_CHECK_INTERVAL = 5;
public static final int MAX_CHECK_FAILURE_COUNT = 4;
public static final int INITIAL_CAPACITY = 3;
public static final int DATA_GROUP_TENANT_SIZE = 3;
public static final int ACTIVE_ALARM = 80;
public static final int CAPACITY_ALARM = 80;
public static final long EXECUTE_TIME_OUT = 10000L;
public static final int SECONDS_IN_MILLISECONDS = 1000;
public static final long FAILURE_SLEEP_INTERVAL = 25000L;
public static final int AVAILABLE_PROCESSORS = Runtime.getRuntime().availableProcessors(); public static final int AVAILABLE_PROCESSORS = Runtime.getRuntime().availableProcessors();
public static final String DEFAULT_GROUP = "default group"; public static final String DEFAULT_GROUP = "default group";
@ -110,7 +126,7 @@ public class Constants {
public static final String EXECUTE_TIMEOUT_TRACE = "executeTimeoutTrace"; public static final String EXECUTE_TIMEOUT_TRACE = "executeTimeoutTrace";
public static final int HTTP_EXECUTE_TIMEOUT = 5000; public static final long HTTP_EXECUTE_TIMEOUT = 5000L;
public static final String CLIENT_VERSION = "Client-Version"; public static final String CLIENT_VERSION = "Client-Version";

@ -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.common.toolkit.http;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* Implement HttpServlet and receive post and get requests<br>
* This HttpServlet represents the home page
*/
public class HomeServlet extends HttpServlet {
int status = 200;
String result = "success";
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.setStatus(status);
PrintWriter writer = resp.getWriter();
writer.println(result);
}
}

@ -20,36 +20,111 @@ package cn.hippo4j.common.toolkit.http;
import cn.hippo4j.common.toolkit.JSONUtil; import cn.hippo4j.common.toolkit.JSONUtil;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;
import org.junit.AfterClass;
import org.junit.Assert; import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class HttpUtilsTest { public class HttpUtilsTest {
/** static int PORT = 8080;
* test post url static Tomcat tomcat;
*/ static final String PROTOCOL = "org.apache.coyote.http11.Http11NioProtocol";
static String postUrl = "http://console.hippo4j.cn/hippo4j/v1/cs/"; static final String HOME_PAGE_URL = "/home";
static final String HOME_PAGE_NAME = "homeServlet";
static final String LOGIN_URL = "/login";
static final String LOGIN_NAME = "loginServlet";
static final String CONTEXT_PATH = "/";
static final String PATH_NAME = ".";
static final String USER_DIR = "user.dir";
static final String PREFIX = "\\tomcat.";
@BeforeClass
public static void startWeb() throws IOException, LifecycleException {
tomcat = new Tomcat();
// get a random port
ServerSocket socket = new ServerSocket(0);
PORT = socket.getLocalPort();
socket.close();
tomcat.setPort(PORT);
Connector connector = new Connector(PROTOCOL);
connector.setThrowOnFailure(true);
connector.setPort(PORT);
tomcat.setConnector(connector);
String absolutePath = new File(PATH_NAME).getAbsolutePath();
Context context = tomcat.addContext(CONTEXT_PATH, absolutePath);
Tomcat.addServlet(context, HOME_PAGE_NAME, new HomeServlet()).setAsyncSupported(true);
context.addServletMappingDecoded(HOME_PAGE_URL, HOME_PAGE_NAME);
Tomcat.addServlet(context, LOGIN_NAME, new LoginServlet()).setAsyncSupported(true);
context.addServletMappingDecoded(LOGIN_URL, LOGIN_NAME);
tomcat.start();
}
@AfterClass
public static void stopWeb() throws LifecycleException, IOException {
// stop tomcat
tomcat.stop();
// del dir
String userUrl = System.getProperty(USER_DIR);
File file = new File(userUrl + PREFIX + PORT);
if (!file.exists()) {
return;
}
Files.walkFileTree(file.toPath(), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
}
/** /**
* test get url * test url
*/ */
static String getUrl = "https://hippo4j.cn/"; String url = "http://localhost:";
String passwordValue = "hippo4jtest";
String usernameValue = "hippo4j";
String password = "password";
String username = "username";
String suffix = "?password=hippo4jtest&username=hippo4j";
@Test @Test
public void get() { public void get() {
String s = HttpUtil.get(getUrl); String s = HttpUtil.get(url + PORT + HOME_PAGE_URL);
Assert.assertNotNull(s); Assert.assertNotNull(s);
} }
@Test @Test
public void restApiPost() { public void restApiPost() {
String loginUrl = postUrl + "auth/login"; String loginUrl = url + PORT + LOGIN_URL;
LoginInfo loginInfo = new LoginInfo(); LoginInfo loginInfo = new LoginInfo();
loginInfo.setPassword("hippo4jtest"); loginInfo.setPassword(passwordValue);
loginInfo.setUsername("hippo4j"); loginInfo.setUsername(usernameValue);
loginInfo.setRememberMe(1); loginInfo.setRememberMe(1);
String s = HttpUtil.post(loginUrl, loginInfo); String s = HttpUtil.post(loginUrl, loginInfo);
Result result = JSONUtil.parseObject(s, Result.class); Result result = JSONUtil.parseObject(s, Result.class);
@ -60,10 +135,10 @@ public class HttpUtilsTest {
@Test @Test
public void testRestApiPost() { public void testRestApiPost() {
String loginUrl = postUrl + "auth/login"; String loginUrl = url + PORT + LOGIN_URL;
LoginInfo loginInfo = new LoginInfo(); LoginInfo loginInfo = new LoginInfo();
loginInfo.setPassword("hippo4jtest"); loginInfo.setPassword(passwordValue);
loginInfo.setUsername("hippo4j"); loginInfo.setUsername(usernameValue);
loginInfo.setRememberMe(1); loginInfo.setRememberMe(1);
Result result = HttpUtil.post(loginUrl, loginInfo, Result.class); Result result = HttpUtil.post(loginUrl, loginInfo, Result.class);
Assert.assertNotNull(result); Assert.assertNotNull(result);
@ -73,10 +148,10 @@ public class HttpUtilsTest {
// @Test(expected = SocketTimeoutException.class) // @Test(expected = SocketTimeoutException.class)
public void testRestApiPostTimeout() { public void testRestApiPostTimeout() {
String loginUrl = postUrl + "auth/login"; String loginUrl = url + PORT + LOGIN_URL;
LoginInfo loginInfo = new LoginInfo(); LoginInfo loginInfo = new LoginInfo();
loginInfo.setPassword("hippo4jtest"); loginInfo.setPassword(passwordValue);
loginInfo.setUsername("hippo4j"); loginInfo.setUsername(usernameValue);
loginInfo.setRememberMe(1); loginInfo.setRememberMe(1);
HttpUtil.post(loginUrl, loginInfo, 1, Result.class); HttpUtil.post(loginUrl, loginInfo, 1, Result.class);
} }
@ -84,15 +159,15 @@ public class HttpUtilsTest {
@Test @Test
public void buildUrl() { public void buildUrl() {
Map<String, String> map = new HashMap<>(); Map<String, String> map = new HashMap<>();
map.put("password", "hippo4jtest"); map.put(password, passwordValue);
map.put("username", "hippo4j"); map.put(username, usernameValue);
String s = HttpUtil.buildUrl(getUrl, map); String s = HttpUtil.buildUrl(url + PORT, map);
Assert.assertEquals(getUrl + "?password=hippo4jtest&username=hippo4j", s); Assert.assertEquals(url + PORT + suffix, s);
} }
@Getter @Getter
@Setter @Setter
private static class LoginInfo { protected static class LoginInfo {
private String username; private String username;
@ -103,7 +178,7 @@ public class HttpUtilsTest {
@Getter @Getter
@Setter @Setter
private static class Result { protected static class Result {
private String code; private String code;
@ -112,7 +187,7 @@ public class HttpUtilsTest {
@Getter @Getter
@Setter @Setter
private static class ResultData { protected static class ResultData {
private String data; private String data;

@ -0,0 +1,50 @@
/*
* 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.common.toolkit.http;
import cn.hippo4j.common.toolkit.JSONUtil;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* his HttpServlet represents the login request
*/
public class LoginServlet extends HttpServlet {
String passwordAttr = "password";
String usernameAttr = "username";
String status = "200";
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String password = (String) req.getAttribute(passwordAttr);
String username = (String) req.getAttribute(usernameAttr);
HttpUtilsTest.ResultData resultData = new HttpUtilsTest.ResultData();
resultData.setData(username + password);
HttpUtilsTest.Result result = new HttpUtilsTest.Result();
result.setCode(status);
result.setData(resultData);
String s = JSONUtil.toJSONString(result);
PrintWriter writer = resp.getWriter();
writer.println(s);
}
}

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

@ -38,6 +38,7 @@ public class MicrometerMonitorAutoConfiguration {
@Bean @Bean
@ConditionalOnExpression("'${spring.dynamic.thread-pool.monitor.thread-pool-types:}'.contains('dynamic')") @ConditionalOnExpression("'${spring.dynamic.thread-pool.monitor.thread-pool-types:}'.contains('dynamic')")
@ConditionalOnProperty(prefix = Constants.CONFIGURATION_PROPERTIES_PREFIX, value = "enable", matchIfMissing = true, havingValue = "true")
public DynamicThreadPoolMicrometerMonitorHandler dynamicThreadPoolMicrometerMonitorHandler() { public DynamicThreadPoolMicrometerMonitorHandler dynamicThreadPoolMicrometerMonitorHandler() {
return new DynamicThreadPoolMicrometerMonitorHandler(); return new DynamicThreadPoolMicrometerMonitorHandler();
} }

@ -38,9 +38,9 @@ import java.util.concurrent.ThreadPoolExecutor;
@Slf4j @Slf4j
public class BaseThreadDetailStateHandler implements ThreadDetailState { public class BaseThreadDetailStateHandler implements ThreadDetailState {
private final String WORKERS = "workers"; private final String workersName = "workers";
private final String THREAD = "thread"; private final String threadName = "thread";
@Override @Override
public List<ThreadDetailStateInfo> getThreadDetailStateInfo(String threadPoolId) { public List<ThreadDetailStateInfo> getThreadDetailStateInfo(String threadPoolId) {
@ -53,14 +53,14 @@ public class BaseThreadDetailStateHandler implements ThreadDetailState {
public List<ThreadDetailStateInfo> getThreadDetailStateInfo(ThreadPoolExecutor threadPoolExecutor) { public List<ThreadDetailStateInfo> getThreadDetailStateInfo(ThreadPoolExecutor threadPoolExecutor) {
List<ThreadDetailStateInfo> resultThreadStates = new ArrayList(); List<ThreadDetailStateInfo> resultThreadStates = new ArrayList();
try { try {
HashSet<Object> workers = (HashSet<Object>) ReflectUtil.getFieldValue(threadPoolExecutor, WORKERS); HashSet<Object> workers = (HashSet<Object>) ReflectUtil.getFieldValue(threadPoolExecutor, workersName);
if (CollectionUtil.isEmpty(workers)) { if (CollectionUtil.isEmpty(workers)) {
return resultThreadStates; return resultThreadStates;
} }
for (Object worker : workers) { for (Object worker : workers) {
Thread thread; Thread thread;
try { try {
thread = (Thread) ReflectUtil.getFieldValue(worker, THREAD); thread = (Thread) ReflectUtil.getFieldValue(worker, threadName);
if (thread == null) { if (thread == null) {
log.warn("Reflection get worker thread is null. Worker: {}", worker); log.warn("Reflection get worker thread is null. Worker: {}", worker);
continue; continue;

@ -35,15 +35,18 @@ import java.util.concurrent.CopyOnWriteArrayList;
public class CacheData { public class CacheData {
@Getter @Getter
public volatile String md5; private volatile String md5;
public volatile String content; private volatile String content;
public final String tenantId; @Getter
private final String tenantId;
public final String itemId; @Getter
private final String itemId;
public final String threadPoolId; @Getter
private final String threadPoolId;
@Setter @Setter
private volatile boolean isInitializing = true; private volatile boolean isInitializing = true;
@ -56,7 +59,7 @@ public class CacheData {
this.threadPoolId = threadPoolId; this.threadPoolId = threadPoolId;
this.content = ContentUtil.getPoolContent(GlobalThreadPoolManage.getPoolParameter(threadPoolId)); this.content = ContentUtil.getPoolContent(GlobalThreadPoolManage.getPoolParameter(threadPoolId));
this.md5 = getMd5String(content); this.md5 = getMd5String(content);
this.listeners = new CopyOnWriteArrayList(); this.listeners = new CopyOnWriteArrayList<>();
} }
public void addListener(Listener listener) { public void addListener(Listener listener) {

@ -33,7 +33,7 @@ public class ClientShutdown {
@Getter @Getter
private volatile boolean prepareClose = false; private volatile boolean prepareClose = false;
private final static Long TIME_OUT_SECOND = 1L; private static final Long TIME_OUT_SECOND = 1L;
private static final int DEFAULT_COUNT = 1; private static final int DEFAULT_COUNT = 1;
private final CountDownLatch countDownLatch = new CountDownLatch(DEFAULT_COUNT); private final CountDownLatch countDownLatch = new CountDownLatch(DEFAULT_COUNT);

@ -30,7 +30,6 @@ import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.DisposableBean;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -43,20 +42,21 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static cn.hippo4j.common.constant.Constants.CLIENT_VERSION;
import static cn.hippo4j.common.constant.Constants.CONFIG_CONTROLLER_PATH;
import static cn.hippo4j.common.constant.Constants.CONFIG_LONG_POLL_TIMEOUT; import static cn.hippo4j.common.constant.Constants.CONFIG_LONG_POLL_TIMEOUT;
import static cn.hippo4j.common.constant.Constants.GROUP_KEY_DELIMITER_TRANSLATION; import static cn.hippo4j.common.constant.Constants.GROUP_KEY_DELIMITER_TRANSLATION;
import static cn.hippo4j.common.constant.Constants.WORD_SEPARATOR;
import static cn.hippo4j.common.constant.Constants.LINE_SEPARATOR; import static cn.hippo4j.common.constant.Constants.LINE_SEPARATOR;
import static cn.hippo4j.common.constant.Constants.LISTENER_PATH; import static cn.hippo4j.common.constant.Constants.PROBE_MODIFY_REQUEST;
import static cn.hippo4j.common.constant.Constants.LONG_PULLING_CLIENT_IDENTIFICATION; import static cn.hippo4j.common.constant.Constants.WEIGHT_CONFIGS;
import static cn.hippo4j.common.constant.Constants.LONG_PULLING_TIMEOUT; import static cn.hippo4j.common.constant.Constants.LONG_PULLING_TIMEOUT;
import static cn.hippo4j.common.constant.Constants.LONG_PULLING_CLIENT_IDENTIFICATION;
import static cn.hippo4j.common.constant.Constants.LONG_PULLING_TIMEOUT_NO_HANGUP; import static cn.hippo4j.common.constant.Constants.LONG_PULLING_TIMEOUT_NO_HANGUP;
import static cn.hippo4j.common.constant.Constants.CLIENT_VERSION;
import static cn.hippo4j.common.constant.Constants.LISTENER_PATH;
import static cn.hippo4j.common.constant.Constants.INITIAL_CAPACITY;
import static cn.hippo4j.common.constant.Constants.DATA_GROUP_TENANT_SIZE;
import static cn.hippo4j.common.constant.Constants.CONFIG_CONTROLLER_PATH;
import static cn.hippo4j.common.constant.Constants.NULL; import static cn.hippo4j.common.constant.Constants.NULL;
import static cn.hippo4j.common.constant.Constants.PROBE_MODIFY_REQUEST;
import static cn.hippo4j.common.constant.Constants.WEIGHT_CONFIGS;
import static cn.hippo4j.common.constant.Constants.WORD_SEPARATOR;
/** /**
* Client worker. * Client worker.
@ -77,6 +77,8 @@ public class ClientWorker implements DisposableBean {
private final CountDownLatch cacheCondition = new CountDownLatch(1); private final CountDownLatch cacheCondition = new CountDownLatch(1);
private final ConcurrentHashMap<String, CacheData> cacheMap = new ConcurrentHashMap<>(16); private final ConcurrentHashMap<String, CacheData> cacheMap = new ConcurrentHashMap<>(16);
private final long defaultTimedOut = 3000L;
@SuppressWarnings("all") @SuppressWarnings("all")
public ClientWorker(HttpAgent httpAgent, public ClientWorker(HttpAgent httpAgent,
String identify, String identify,
@ -113,13 +115,16 @@ public class ClientWorker implements DisposableBean {
executorService.shutdownNow(); executorService.shutdownNow();
} }
/**
* LongPollingRunnable
*/
class LongPollingRunnable implements Runnable { class LongPollingRunnable implements Runnable {
private boolean cacheMapInitEmptyFlag; private boolean cacheMapInitEmptyFlag;
private final CountDownLatch cacheCondition; private final CountDownLatch cacheCondition;
public LongPollingRunnable(boolean cacheMapInitEmptyFlag, CountDownLatch cacheCondition) { LongPollingRunnable(boolean cacheMapInitEmptyFlag, CountDownLatch cacheCondition) {
this.cacheMapInitEmptyFlag = cacheMapInitEmptyFlag; this.cacheMapInitEmptyFlag = cacheMapInitEmptyFlag;
this.cacheCondition = cacheCondition; this.cacheCondition = cacheCondition;
} }
@ -147,7 +152,7 @@ public class ClientWorker implements DisposableBean {
String itemId = keys[1]; String itemId = keys[1];
String namespace = keys[2]; String namespace = keys[2];
try { try {
String content = getServerConfig(namespace, itemId, tpId, 3000L); String content = getServerConfig(namespace, itemId, tpId, defaultTimedOut);
CacheData cacheData = cacheMap.get(tpId); CacheData cacheData = cacheMap.get(tpId);
String poolContent = ContentUtil.getPoolContent(JSONUtil.parseObject(content, ThreadPoolParameterInfo.class)); String poolContent = ContentUtil.getPoolContent(JSONUtil.parseObject(content, ThreadPoolParameterInfo.class));
cacheData.setContent(poolContent); cacheData.setContent(poolContent);
@ -157,7 +162,7 @@ public class ClientWorker implements DisposableBean {
} }
for (CacheData cacheData : cacheDataList) { for (CacheData cacheData : cacheDataList) {
if (!cacheData.isInitializing() || inInitializingCacheList if (!cacheData.isInitializing() || inInitializingCacheList
.contains(GroupKey.getKeyTenant(cacheData.threadPoolId, cacheData.itemId, cacheData.tenantId))) { .contains(GroupKey.getKeyTenant(cacheData.getThreadPoolId(), cacheData.getItemId(), cacheData.getTenantId()))) {
cacheData.checkListenerMd5(); cacheData.checkListenerMd5();
cacheData.setInitializing(false); cacheData.setInitializing(false);
} }
@ -170,13 +175,13 @@ public class ClientWorker implements DisposableBean {
private List<String> checkUpdateDataIds(List<CacheData> cacheDataList, List<String> inInitializingCacheList) { private List<String> checkUpdateDataIds(List<CacheData> cacheDataList, List<String> inInitializingCacheList) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (CacheData cacheData : cacheDataList) { for (CacheData cacheData : cacheDataList) {
sb.append(cacheData.threadPoolId).append(WORD_SEPARATOR); sb.append(cacheData.getThreadPoolId()).append(WORD_SEPARATOR);
sb.append(cacheData.itemId).append(WORD_SEPARATOR); sb.append(cacheData.getItemId()).append(WORD_SEPARATOR);
sb.append(cacheData.tenantId).append(WORD_SEPARATOR); sb.append(cacheData.getTenantId()).append(WORD_SEPARATOR);
sb.append(identify).append(WORD_SEPARATOR); sb.append(identify).append(WORD_SEPARATOR);
sb.append(cacheData.getMd5()).append(LINE_SEPARATOR); sb.append(cacheData.getMd5()).append(LINE_SEPARATOR);
if (cacheData.isInitializing()) { if (cacheData.isInitializing()) {
inInitializingCacheList.add(GroupKey.getKeyTenant(cacheData.threadPoolId, cacheData.itemId, cacheData.tenantId)); inInitializingCacheList.add(GroupKey.getKeyTenant(cacheData.getThreadPoolId(), cacheData.getItemId(), cacheData.getTenantId()));
} }
} }
boolean isInitializingCacheList = !inInitializingCacheList.isEmpty(); boolean isInitializingCacheList = !inInitializingCacheList.isEmpty();
@ -213,7 +218,7 @@ public class ClientWorker implements DisposableBean {
} }
public String getServerConfig(String namespace, String itemId, String threadPoolId, long readTimeout) { public String getServerConfig(String namespace, String itemId, String threadPoolId, long readTimeout) {
Map<String, String> params = new HashMap<>(3); Map<String, String> params = new HashMap<>(INITIAL_CAPACITY);
params.put("namespace", namespace); params.put("namespace", namespace);
params.put("itemId", itemId); params.put("itemId", itemId);
params.put("tpId", threadPoolId); params.put("tpId", threadPoolId);
@ -241,7 +246,7 @@ public class ClientWorker implements DisposableBean {
String[] keyArr = dataIdAndGroup.split(WORD_SEPARATOR); String[] keyArr = dataIdAndGroup.split(WORD_SEPARATOR);
String dataId = keyArr[0]; String dataId = keyArr[0];
String group = keyArr[1]; String group = keyArr[1];
if (keyArr.length == 3) { if (keyArr.length == DATA_GROUP_TENANT_SIZE) {
String tenant = keyArr[2]; String tenant = keyArr[2];
updateList.add(GroupKey.getKeyTenant(dataId, group, tenant)); updateList.add(GroupKey.getKeyTenant(dataId, group, tenant));
log.info("[{}] Refresh thread pool changed.", dataId); log.info("[{}] Refresh thread pool changed.", dataId);
@ -274,7 +279,7 @@ public class ClientWorker implements DisposableBean {
if (lastCacheData == null) { if (lastCacheData == null) {
String serverConfig; String serverConfig;
try { try {
serverConfig = getServerConfig(namespace, itemId, threadPoolId, 3000L); serverConfig = getServerConfig(namespace, itemId, threadPoolId, defaultTimedOut);
ThreadPoolParameterInfo poolInfo = JSONUtil.parseObject(serverConfig, ThreadPoolParameterInfo.class); ThreadPoolParameterInfo poolInfo = JSONUtil.parseObject(serverConfig, ThreadPoolParameterInfo.class);
cacheData.setContent(ContentUtil.getPoolContent(poolInfo)); cacheData.setContent(ContentUtil.getPoolContent(poolInfo));
} catch (Exception ex) { } catch (Exception ex) {

@ -51,6 +51,8 @@ public class DiscoveryClient implements DisposableBean {
private static final String PREFIX = "DiscoveryClient_"; private static final String PREFIX = "DiscoveryClient_";
private final String appPathIdentifier; private final String appPathIdentifier;
private final int delayTime = 30;
public DiscoveryClient(HttpAgent httpAgent, InstanceInfo instanceInfo, ClientShutdown hippo4jClientShutdown) { public DiscoveryClient(HttpAgent httpAgent, InstanceInfo instanceInfo, ClientShutdown hippo4jClientShutdown) {
this.httpAgent = httpAgent; this.httpAgent = httpAgent;
this.instanceInfo = instanceInfo; this.instanceInfo = instanceInfo;
@ -65,7 +67,7 @@ public class DiscoveryClient implements DisposableBean {
} }
private void initScheduledTasks() { private void initScheduledTasks() {
scheduler.scheduleWithFixedDelay(new HeartbeatThread(), 30, 30, TimeUnit.SECONDS); scheduler.scheduleWithFixedDelay(new HeartbeatThread(), delayTime, delayTime, TimeUnit.SECONDS);
} }
boolean register() { boolean register() {
@ -118,6 +120,9 @@ public class DiscoveryClient implements DisposableBean {
hippo4jClientShutdown.prepareDestroy(); hippo4jClientShutdown.prepareDestroy();
} }
/**
* HeartbeatThread
*/
public class HeartbeatThread implements Runnable { public class HeartbeatThread implements Runnable {
@Override @Override

@ -41,10 +41,12 @@ public class DynamicThreadPoolSubscribeConfig {
private final BootstrapProperties properties; private final BootstrapProperties properties;
private final int defaultAliveTime = 2000;
private final ExecutorService configRefreshExecutorService = ThreadPoolBuilder.builder() private final ExecutorService configRefreshExecutorService = ThreadPoolBuilder.builder()
.corePoolSize(1) .corePoolSize(1)
.maximumPoolSize(2) .maximumPoolSize(2)
.keepAliveTime(2000) .keepAliveTime(defaultAliveTime)
.timeUnit(TimeUnit.MILLISECONDS) .timeUnit(TimeUnit.MILLISECONDS)
.workQueue(BlockingQueueTypeEnum.SYNCHRONOUS_QUEUE) .workQueue(BlockingQueueTypeEnum.SYNCHRONOUS_QUEUE)
.allowCoreThreadTimeOut(true) .allowCoreThreadTimeOut(true)

@ -31,8 +31,10 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import static cn.hippo4j.common.constant.Constants.MAX_CHECK_FAILURE_COUNT;
import static cn.hippo4j.common.constant.Constants.SECONDS_IN_MILLISECONDS;
import static cn.hippo4j.common.constant.Constants.HEALTH_CHECK_INTERVAL; import static cn.hippo4j.common.constant.Constants.HEALTH_CHECK_INTERVAL;
import static cn.hippo4j.common.constant.Constants.FAILURE_SLEEP_INTERVAL;
/** /**
* Abstract health check. * Abstract health check.
@ -99,10 +101,10 @@ public abstract class AbstractHealthCheck implements ServerHealthCheck, Initiali
} else { } else {
healthStatus = false; healthStatus = false;
checkFailureCount++; checkFailureCount++;
if (checkFailureCount > 1 && checkFailureCount < 4) { if (checkFailureCount > 1 && checkFailureCount < MAX_CHECK_FAILURE_COUNT) {
ThreadUtil.sleep(HEALTH_CHECK_INTERVAL * 1000 * (checkFailureCount - 1)); ThreadUtil.sleep((long) HEALTH_CHECK_INTERVAL * SECONDS_IN_MILLISECONDS * (checkFailureCount - 1));
} else if (checkFailureCount >= 4) { } else if (checkFailureCount >= MAX_CHECK_FAILURE_COUNT) {
ThreadUtil.sleep(25000L); ThreadUtil.sleep(FAILURE_SLEEP_INTERVAL);
} }
} }
} }

@ -88,13 +88,16 @@ public class ServerListManager {
return new ServerAddressIterator(serverUrls); return new ServerAddressIterator(serverUrls);
} }
/**
* Server Address Iterator
*/
private static class ServerAddressIterator implements Iterator<String> { private static class ServerAddressIterator implements Iterator<String> {
final List<RandomizedServerAddress> sorted; final List<RandomizedServerAddress> sorted;
final Iterator<RandomizedServerAddress> iter; final Iterator<RandomizedServerAddress> iter;
public ServerAddressIterator(List<String> source) { ServerAddressIterator(List<String> source) {
sorted = new ArrayList(); sorted = new ArrayList();
for (String address : source) { for (String address : source) {
sorted.add(new RandomizedServerAddress(address)); sorted.add(new RandomizedServerAddress(address));
@ -113,6 +116,9 @@ public class ServerListManager {
return null; return null;
} }
/**
* Randomized Server Address
*/
static class RandomizedServerAddress implements Comparable<RandomizedServerAddress> { static class RandomizedServerAddress implements Comparable<RandomizedServerAddress> {
static Random random = new Random(); static Random random = new Random();
@ -123,7 +129,7 @@ public class ServerListManager {
int seed; int seed;
public RandomizedServerAddress(String ip) { RandomizedServerAddress(String ip) {
try { try {
this.serverIp = ip; this.serverIp = ip;
/* /*

@ -39,6 +39,8 @@ public class SecurityProxy {
private static final String APPLY_TOKEN_URL = Constants.BASE_PATH + "/auth/users/apply/token"; private static final String APPLY_TOKEN_URL = Constants.BASE_PATH + "/auth/users/apply/token";
private final int refreshWindowDuration = 10;
private final String username; private final String username;
private final String password; private final String password;
@ -88,7 +90,7 @@ public class SecurityProxy {
TokenInfo tokenInfo = JSONUtil.parseObject(tokenJsonStr, TokenInfo.class); TokenInfo tokenInfo = JSONUtil.parseObject(tokenJsonStr, TokenInfo.class);
accessToken = tokenInfo.getAccessToken(); accessToken = tokenInfo.getAccessToken();
tokenTtl = tokenInfo.getTokenTtl(); tokenTtl = tokenInfo.getTokenTtl();
tokenRefreshWindow = tokenTtl / 10; tokenRefreshWindow = tokenTtl / refreshWindowDuration;
} catch (Throwable ex) { } catch (Throwable ex) {
log.error("Failed to apply for token. message: {}", ex.getMessage()); log.error("Failed to apply for token. message: {}", ex.getMessage());
return false; return false;

@ -53,10 +53,14 @@ import java.util.Optional;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static cn.hippo4j.common.constant.Constants.INITIAL_CAPACITY;
import static cn.hippo4j.common.constant.Constants.TP_ID;
import static cn.hippo4j.common.constant.Constants.ITEM_ID; import static cn.hippo4j.common.constant.Constants.ITEM_ID;
import static cn.hippo4j.common.constant.Constants.NAMESPACE; import static cn.hippo4j.common.constant.Constants.NAMESPACE;
import static cn.hippo4j.common.constant.Constants.TP_ID; import static cn.hippo4j.common.constant.Constants.ACTIVE_ALARM;
import static cn.hippo4j.common.constant.Constants.CAPACITY_ALARM;
import static cn.hippo4j.common.constant.Constants.EXECUTE_TIME_OUT;
import static cn.hippo4j.common.constant.Constants.HTTP_EXECUTE_TIMEOUT;
/** /**
* Dynamic thread-pool post processor. * Dynamic thread-pool post processor.
@ -94,7 +98,8 @@ public final class DynamicThreadPoolPostProcessor implements BeanPostProcessor {
return bean; return bean;
} }
DynamicThreadPoolExecutor dynamicThreadPoolExecutor; DynamicThreadPoolExecutor dynamicThreadPoolExecutor;
if ((dynamicThreadPoolExecutor = DynamicThreadPoolAdapterChoose.unwrap(bean)) == null) { dynamicThreadPoolExecutor = DynamicThreadPoolAdapterChoose.unwrap(bean);
if ((dynamicThreadPoolExecutor) == null) {
dynamicThreadPoolExecutor = (DynamicThreadPoolExecutor) bean; dynamicThreadPoolExecutor = (DynamicThreadPoolExecutor) bean;
} }
DynamicThreadPoolWrapper dynamicThreadPoolWrapper = new DynamicThreadPoolWrapper(dynamicThreadPoolExecutor.getThreadPoolId(), dynamicThreadPoolExecutor); DynamicThreadPoolWrapper dynamicThreadPoolWrapper = new DynamicThreadPoolWrapper(dynamicThreadPoolExecutor.getThreadPoolId(), dynamicThreadPoolExecutor);
@ -128,16 +133,17 @@ public final class DynamicThreadPoolPostProcessor implements BeanPostProcessor {
protected ThreadPoolExecutor fillPoolAndRegister(DynamicThreadPoolWrapper dynamicThreadPoolWrapper) { protected ThreadPoolExecutor fillPoolAndRegister(DynamicThreadPoolWrapper dynamicThreadPoolWrapper) {
String threadPoolId = dynamicThreadPoolWrapper.getThreadPoolId(); String threadPoolId = dynamicThreadPoolWrapper.getThreadPoolId();
ThreadPoolExecutor executor = dynamicThreadPoolWrapper.getExecutor(); ThreadPoolExecutor executor = dynamicThreadPoolWrapper.getExecutor();
Map<String, String> queryStrMap = new HashMap(3); Map<String, String> queryStrMap = new HashMap<>(INITIAL_CAPACITY);
queryStrMap.put(TP_ID, threadPoolId); queryStrMap.put(TP_ID, threadPoolId);
queryStrMap.put(ITEM_ID, properties.getItemId()); queryStrMap.put(ITEM_ID, properties.getItemId());
queryStrMap.put(NAMESPACE, properties.getNamespace()); queryStrMap.put(NAMESPACE, properties.getNamespace());
ThreadPoolParameterInfo threadPoolParameterInfo = new ThreadPoolParameterInfo(); ThreadPoolParameterInfo threadPoolParameterInfo = new ThreadPoolParameterInfo();
try { try {
Result result = httpAgent.httpGetByConfig(Constants.CONFIG_CONTROLLER_PATH, null, queryStrMap, 5000L); Result result = httpAgent.httpGetByConfig(Constants.CONFIG_CONTROLLER_PATH, null, queryStrMap, HTTP_EXECUTE_TIMEOUT);
if (result.isSuccess() && result.getData() != null) { if (result.isSuccess() && result.getData() != null) {
String resultJsonStr = JSONUtil.toJSONString(result.getData()); String resultJsonStr = JSONUtil.toJSONString(result.getData());
if ((threadPoolParameterInfo = JSONUtil.parseObject(resultJsonStr, ThreadPoolParameterInfo.class)) != null) { threadPoolParameterInfo = JSONUtil.parseObject(resultJsonStr, ThreadPoolParameterInfo.class);
if (threadPoolParameterInfo != null) {
threadPoolParamReplace(executor, threadPoolParameterInfo); threadPoolParamReplace(executor, threadPoolParameterInfo);
registerNotifyAlarm(threadPoolParameterInfo); registerNotifyAlarm(threadPoolParameterInfo);
} }
@ -153,9 +159,9 @@ public final class DynamicThreadPoolPostProcessor implements BeanPostProcessor {
.allowCoreThreadTimeOut(executor.allowsCoreThreadTimeOut()) .allowCoreThreadTimeOut(executor.allowsCoreThreadTimeOut())
.keepAliveTime(executor.getKeepAliveTime(TimeUnit.MILLISECONDS)) .keepAliveTime(executor.getKeepAliveTime(TimeUnit.MILLISECONDS))
.isAlarm(false) .isAlarm(false)
.activeAlarm(80) .activeAlarm(ACTIVE_ALARM)
.capacityAlarm(80) .capacityAlarm(CAPACITY_ALARM)
.executeTimeOut(10000L) .executeTimeOut(EXECUTE_TIME_OUT)
.rejectedPolicyType(RejectedPolicyTypeEnum.getRejectedPolicyTypeEnumByName(executor.getRejectedExecutionHandler().getClass().getSimpleName())) .rejectedPolicyType(RejectedPolicyTypeEnum.getRejectedPolicyTypeEnumByName(executor.getRejectedExecutionHandler().getClass().getSimpleName()))
.build(); .build();
DynamicThreadPoolRegisterWrapper registerWrapper = DynamicThreadPoolRegisterWrapper.builder() DynamicThreadPoolRegisterWrapper registerWrapper = DynamicThreadPoolRegisterWrapper.builder()

Loading…
Cancel
Save