Feat: Agent mode Adapte SpringBoot 1.x , 2.x , 3.x And Adapte Nacos , Apollo Config-Center Agent Plugin (#1573)

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

* Feat: Agent mode adapte SpringBoot 1.x 2.x 3.x And adapte Nacos、Apollo Config-Center

* Fix: Fix build boot3.x moudle jdk17 project error

* Fix: Fix build moudle error

* Fix: Fix build moudle error

* Fix: Fix build moudle error,Upgrade lombok dependency versions and add jaxb dependencies

* Fix: Fix build moudle error,Upgrade maven.compiler.plugin version

* Fix: Fix build moudle error,Upgrade lombok version
pull/1290/merge
Pan_Yujie 2 months ago committed by GitHub
parent a34539f28b
commit b45ff94c40
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -33,6 +33,7 @@
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<phase>package</phase>

@ -29,6 +29,7 @@
<shade.org.slf4j.source>org.slf4j</shade.org.slf4j.source>
<shade.org.slf4j.target>${shade.package}.${shade.org.slf4j.source}</shade.org.slf4j.target>
<ststem-rules.version>1.18.0</ststem-rules.version>
<jaxb.version>2.3.1</jaxb.version>
</properties>
<dependencies>
@ -78,15 +79,16 @@
<artifactId>hippo4j-threadpool-infra-common</artifactId>
<version>${project.version}</version>
</dependency>
<!--To fix https://github.com/DozerMapper/dozer/issues/865 -->
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-threadpool-dynamic-mode-config</artifactId>
<version>${project.version}</version>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${jaxb.version}</version>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-threadpool-kernel-monitor</artifactId>
<version>${project.version}</version>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>${jaxb.version}</version>
</dependency>
</dependencies>
@ -107,6 +109,7 @@
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<phase>package</phase>

@ -29,7 +29,6 @@ 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.Binder;
import java.util.HashMap;
import java.util.List;
@ -72,7 +71,7 @@ public class ApolloDynamicThreadPoolChangeHandler extends AbstractConfigThreadPo
/**
* 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
* This method uses SpringPropertyBinder to bind the configuration values to an instance
* of {@link BootstrapConfigProperties}, which can then be used to configure the thread pool
* dynamically.
*

@ -26,6 +26,11 @@
<artifactId>hippo4j-threadpool-dynamic-mode-config</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>

@ -32,7 +32,6 @@ 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.Binder;
import java.io.IOException;
import java.util.HashMap;
@ -124,7 +123,7 @@ public class NacosDynamicThreadPoolChangeHandler extends AbstractConfigThreadPoo
/**
* 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
* This method uses SpringPropertyBinder to bind the configuration values to an instance
* of {@link BootstrapConfigProperties}, which can then be used to configure the thread pool
* dynamically.
*

@ -49,7 +49,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,
// This means that when the Nacos plugin 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 Nacos
AbstractSubjectCenter.register(AbstractSubjectCenter.SubjectType.AGENT_SPRING_PROPERTIES_LOADER_COMPLETED, new NacosConfigPropertiesLoaderCompletedListener());

@ -38,6 +38,12 @@
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-agent-core</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
</exclusions>
<scope>provided</scope>
</dependency>
<dependency>

@ -15,6 +15,7 @@
<modules>
<module>spring-boot-1x-plugin</module>
<module>spring-boot-2x-plugin</module>
<module>spring-boot-3x-plugin</module>
<module>spring-plugin-common</module>
</modules>

@ -13,7 +13,6 @@
<properties>
<spring.boot.version>1.5.22.RELEASE</spring.boot.version>
<apollo.version>1.9.1</apollo.version>
</properties>
<dependencyManagement>

@ -0,0 +1,52 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.agent.plugin.spring.boot.v1.boot;
import cn.hippo4j.agent.core.boot.BootService;
import cn.hippo4j.agent.core.boot.DefaultImplementor;
import cn.hippo4j.common.logging.api.ILog;
import cn.hippo4j.common.logging.api.LogManager;
/**
* SpringBoot v1 plugin boot service
*/
@DefaultImplementor
public class SpringBootV1PluginBootService implements BootService {
private static final ILog LOGGER = LogManager.getLogger(SpringBootV1PluginBootService.class);
@Override
public void prepare() throws Throwable {
}
@Override
public void boot() throws Throwable {
LOGGER.info("Loader SpringBootV1PluginBootService...");
}
@Override
public void onComplete() throws Throwable {
}
@Override
public void shutdown() throws Throwable {
}
}

@ -32,13 +32,13 @@ import static cn.hippo4j.agent.core.plugin.match.NameMatch.byName;
import static net.bytebuddy.matcher.ElementMatchers.named;
/**
* Application Context Refresh instrumentation
* SpringBoot v1 EventPublishingRunListener Finished instrumentation
*/
public class ApplicationContextInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
public class EventPublishingRunListenerInstrumentationV1 extends ClassInstanceMethodsEnhancePluginDefine {
private static final String ENHANCE_CLASS = "org.springframework.context.support.AbstractApplicationContext";
private static final String ENHANCE_CLASS = "org.springframework.boot.context.event.EventPublishingRunListener";
private static final String APPLICATION_CONTEXT_REFRESH_INTERCEPTOR = "cn.hippo4j.agent.plugin.spring.boot.v1.interceptor.ApplicationContextInterceptor";
private static final String EVENT_PUBLISHING_FINISHED_INTERCEPTOR_V1 = "cn.hippo4j.agent.plugin.spring.boot.v1.interceptor.EventPublishingRunListenerFinishedInterceptorV1";
@Override
protected ClassMatch enhanceClass() {
@ -56,12 +56,12 @@ public class ApplicationContextInstrumentation extends ClassInstanceMethodsEnhan
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("refresh");
return named("finished");
}
@Override
public String getMethodsInterceptor() {
return APPLICATION_CONTEXT_REFRESH_INTERCEPTOR;
return EVENT_PUBLISHING_FINISHED_INTERCEPTOR_V1;
}
@Override

@ -33,9 +33,9 @@ import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Application Context Refresh interceptor
* EventPublishingRunListener Finished interceptor
*/
public class ApplicationContextInterceptor implements InstanceMethodsAroundInterceptor {
public class EventPublishingRunListenerFinishedInterceptorV1 implements InstanceMethodsAroundInterceptor {
private static final AtomicBoolean isExecuted = new AtomicBoolean(false);
@ -46,10 +46,9 @@ public class ApplicationContextInterceptor implements InstanceMethodsAroundInter
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
// Since the refresh() method is a method of the AbstractApplicationContext class,
// the AbstractApplicationContext itself is an implementation class of the ApplicationContext.
// Therefore, can treat the class instance itself as an ApplicationContext object.
ConfigurableApplicationContext context = (ConfigurableApplicationContext) objInst;
// Since the finished() method is a method of the EventPublishingRunListener class,
// the EventPublishingRunListener the first parameter is ConfigurableApplicationContext
ConfigurableApplicationContext context = (ConfigurableApplicationContext) allArguments[0];
if (context.getParent() != null) {
// After the child container is started, the thread pool registration will be carried out
// IDEA's runtime environment or debugging mechanisms make context refresh speeds different.
@ -70,8 +69,12 @@ public class ApplicationContextInterceptor implements InstanceMethodsAroundInter
if (isExecuted.compareAndSet(false, true)) {
ApplicationContextHolder contextHolder = new ApplicationContextHolder();
contextHolder.setApplicationContext(context);
// Load Spring Properties
SpringPropertiesLoader.loadSpringProperties(context.getEnvironment());
AbstractSubjectCenter.register(AbstractSubjectCenter.SubjectType.THREAD_POOL_DYNAMIC_REFRESH, new DynamicThreadPoolRefreshListener());
// register Dynamic ThreadPool Refresh Listener
if (AbstractSubjectCenter.get(AbstractSubjectCenter.SubjectType.THREAD_POOL_DYNAMIC_REFRESH) == null) {
AbstractSubjectCenter.register(AbstractSubjectCenter.SubjectType.THREAD_POOL_DYNAMIC_REFRESH, new DynamicThreadPoolRefreshListener());
}
}
return ret;
}

@ -0,0 +1,17 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
cn.hippo4j.agent.plugin.spring.boot.v1.boot.SpringBootV1PluginBootService

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

@ -23,7 +23,7 @@ import cn.hippo4j.common.logging.api.ILog;
import cn.hippo4j.common.logging.api.LogManager;
/**
* SpringBoot v1 plugin boot service
* SpringBoot v2 plugin boot service
*/
@DefaultImplementor
public class SpringBootV2PluginBootService implements BootService {

@ -25,20 +25,21 @@ import cn.hippo4j.agent.core.plugin.match.ClassMatch;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import java.util.Collections;
import java.util.Arrays;
import java.util.List;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static cn.hippo4j.agent.core.plugin.match.NameMatch.byName;
import static net.bytebuddy.matcher.ElementMatchers.not;
/**
* Event publishing run listener instrumentation
* SpringBoot v2 Event publishing run listener instrumentation
*/
public class EventPublishingRunListenerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
public class EventPublishingRunListenerInstrumentationV2 extends ClassInstanceMethodsEnhancePluginDefine {
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.interceptor.EventPublishingStartedInterceptor";
private static final String EVENT_PUBLISHING_STARTED_INTERCEPTOR_V2 = "cn.hippo4j.agent.plugin.spring.boot.v2.interceptor.EventPublishingStartedInterceptorV2";
private static final String EVENT_PUBLISHING_ENVIRONMENT_PREPARED_INTERCEPTOR = "cn.hippo4j.agent.plugin.spring.common.interceptor.EventPublishingRunListenerEnvironmentPreparedInterceptor";
@Override
@ -63,7 +64,7 @@ public class EventPublishingRunListenerInstrumentation extends ClassInstanceMeth
@Override
public String getMethodsInterceptor() {
return EVENT_PUBLISHING_FINISHED_INTERCEPTOR;
return EVENT_PUBLISHING_STARTED_INTERCEPTOR_V2;
}
@Override
@ -93,7 +94,17 @@ public class EventPublishingRunListenerInstrumentation extends ClassInstanceMeth
@Override
protected List<WitnessMethod> witnessMethods() {
return Collections.singletonList(new WitnessMethod("org.springframework.boot.context.event.EventPublishingRunListener",
named("started")));
return Arrays.asList(
new WitnessMethod("org.springframework.boot.context.event.EventPublishingRunListener", named("started")),
new WitnessMethod("org.springframework.boot.context.event.EventPublishingRunListener", named("running")),
new WitnessMethod("org.springframework.boot.context.event.EventPublishingRunListener", not(named("ready")))
// new WitnessMethod("org.springframework.boot.context.properties.ConstructorBinding", not(isAnnotatedWith(Deprecated.class)))
);
}
@Override
protected String[] witnessClasses() {
return new String[]{"org.springframework.boot.context.properties.ConstructorBinding"};
}
}

@ -35,11 +35,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
/**
* Event publishing started interceptor
*/
public class EventPublishingStartedInterceptor implements InstanceMethodsAroundInterceptor {
public class EventPublishingStartedInterceptorV2 implements InstanceMethodsAroundInterceptor {
private static final AtomicBoolean isExecuted = new AtomicBoolean(false);
private static final ILog LOGGER = LogManager.getLogger(EventPublishingStartedInterceptor.class);
private static final ILog LOGGER = LogManager.getLogger(EventPublishingStartedInterceptorV2.class);
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
@ -61,7 +61,9 @@ public class EventPublishingStartedInterceptor implements InstanceMethodsAroundI
// Load Spring Properties
SpringPropertiesLoader.loadSpringProperties(context.getEnvironment());
// register Dynamic ThreadPool Refresh Listener
AbstractSubjectCenter.register(AbstractSubjectCenter.SubjectType.THREAD_POOL_DYNAMIC_REFRESH, new DynamicThreadPoolRefreshListener());
if (AbstractSubjectCenter.get(AbstractSubjectCenter.SubjectType.THREAD_POOL_DYNAMIC_REFRESH) == null) {
AbstractSubjectCenter.register(AbstractSubjectCenter.SubjectType.THREAD_POOL_DYNAMIC_REFRESH, new DynamicThreadPoolRefreshListener());
}
}
return ret;

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

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-agent-spring-plugins</artifactId>
<version>${revision}</version>
</parent>
<artifactId>hippo4j-agent-spring-boot-3x-plugin</artifactId>
<properties>
<spring-boot.version>3.0.2</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-agent-spring-plugin-common</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

@ -0,0 +1,52 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.agent.plugin.spring.boot.v3.boot;
import cn.hippo4j.agent.core.boot.BootService;
import cn.hippo4j.agent.core.boot.DefaultImplementor;
import cn.hippo4j.common.logging.api.ILog;
import cn.hippo4j.common.logging.api.LogManager;
/**
* SpringBoot v3 plugin boot service
*/
@DefaultImplementor
public class SpringBootV3PluginBootService implements BootService {
private static final ILog LOGGER = LogManager.getLogger(SpringBootV3PluginBootService.class);
@Override
public void prepare() throws Throwable {
}
@Override
public void boot() throws Throwable {
LOGGER.info("Loader SpringBootV3PluginBootService...");
}
@Override
public void onComplete() throws Throwable {
}
@Override
public void shutdown() throws Throwable {
}
}

@ -0,0 +1,87 @@
/*
* 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.v3.define;
import cn.hippo4j.agent.core.plugin.WitnessMethod;
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 java.util.Collections;
import java.util.List;
import static cn.hippo4j.agent.core.plugin.match.NameMatch.byName;
import static net.bytebuddy.matcher.ElementMatchers.named;
/**
* SpringBoot v3 Event publishing run listener instrumentation
*/
public class EventPublishingRunListenerInstrumentationV3 extends ClassInstanceMethodsEnhancePluginDefine {
private static final String ENHANCE_CLASS = "org.springframework.boot.context.event.EventPublishingRunListener";
private static final String EVENT_PUBLISHING_STARTED_INTERCEPTOR_V3 = "cn.hippo4j.agent.plugin.spring.boot.v3.interceptor.EventPublishingStartedInterceptorV3";
@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("ready");
}
@Override
public String getMethodsInterceptor() {
return EVENT_PUBLISHING_STARTED_INTERCEPTOR_V3;
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
@Override
protected List<WitnessMethod> witnessMethods() {
return Collections.singletonList(new WitnessMethod("org.springframework.boot.context.event.EventPublishingRunListener",
named("ready")));
}
@Override
protected String[] witnessClasses() {
return new String[]{"org.springframework.boot.context.properties.bind.ConstructorBinding"};
}
}

@ -0,0 +1,73 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.agent.plugin.spring.boot.v3.interceptor;
import cn.hippo4j.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import cn.hippo4j.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import cn.hippo4j.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import cn.hippo4j.agent.plugin.spring.common.event.DynamicThreadPoolRefreshListener;
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.common.logging.api.ILog;
import cn.hippo4j.common.logging.api.LogManager;
import cn.hippo4j.core.config.ApplicationContextHolder;
import org.springframework.context.ConfigurableApplicationContext;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Event publishing started interceptor
*/
public class EventPublishingStartedInterceptorV3 implements InstanceMethodsAroundInterceptor {
private static final AtomicBoolean isExecuted = new AtomicBoolean(false);
private static final ILog LOGGER = LogManager.getLogger(EventPublishingStartedInterceptorV3.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];
// This logic will only be executed once
if (isExecuted.compareAndSet(false, true)) {
ApplicationContextHolder contextHolder = new ApplicationContextHolder();
contextHolder.setApplicationContext(context);
// Load Spring Properties
SpringPropertiesLoader.loadSpringProperties(context.getEnvironment());
// the thread pool registration will be carried out
SpringThreadPoolRegisterSupport.registerThreadPoolInstances(context);
// register Dynamic ThreadPool Refresh Listener
if (AbstractSubjectCenter.get(AbstractSubjectCenter.SubjectType.THREAD_POOL_DYNAMIC_REFRESH) == null) {
AbstractSubjectCenter.register(AbstractSubjectCenter.SubjectType.THREAD_POOL_DYNAMIC_REFRESH, new DynamicThreadPoolRefreshListener());
}
}
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
}
}

@ -0,0 +1,17 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
cn.hippo4j.agent.plugin.spring.boot.v3.boot.SpringBootV3PluginBootService

@ -0,0 +1,17 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
spring-boot-3.x=cn.hippo4j.agent.plugin.spring.boot.v3.define.EventPublishingRunListenerInstrumentationV3

@ -45,6 +45,12 @@
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-threadpool-kernel-alarm</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
@ -57,10 +63,27 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-threadpool-dynamic-mode-config</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-threadpool-adapter-web</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>

@ -29,7 +29,6 @@ import cn.hippo4j.threadpool.dynamic.mode.config.properties.WebExecutorPropertie
import cn.hippo4j.threadpool.message.api.NotifyConfigBuilder;
import cn.hippo4j.threadpool.message.api.NotifyConfigDTO;
import cn.hippo4j.threadpool.message.core.service.AlarmControlHandler;
import cn.hippo4j.threadpool.message.core.service.ThreadPoolBaseSendMessageService;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@ -26,12 +26,15 @@ import org.slf4j.LoggerFactory;
import org.springframework.core.env.ConfigurableEnvironment;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Event publishing run listener environment prepared interceptor
*/
public class EventPublishingRunListenerEnvironmentPreparedInterceptor implements InstanceMethodsAroundInterceptor {
private static final AtomicBoolean isExecuted = new AtomicBoolean(false);
private static final Logger LOGGER = LoggerFactory.getLogger(EventPublishingRunListenerEnvironmentPreparedInterceptor.class);
@Override
@ -41,9 +44,16 @@ public class EventPublishingRunListenerEnvironmentPreparedInterceptor implements
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
ConfigurableEnvironment environment = (ConfigurableEnvironment) allArguments[0];
SpringEnvironmentSupport.disableNonAgentSwitch(environment);
LOGGER.info("[Hippo4j-Agent] Switch off in non-Agent mode.");
if (isExecuted.compareAndSet(false, true)) {
ConfigurableEnvironment environment = null;
try {
environment = (ConfigurableEnvironment) allArguments[0];
} catch (Exception e) {
environment = (ConfigurableEnvironment) allArguments[1];
}
SpringEnvironmentSupport.disableNonAgentSwitch(environment);
LOGGER.info("[Hippo4j-Agent] Switch off in non-Agent mode.");
}
return ret;
}

@ -28,11 +28,11 @@ import cn.hippo4j.common.toolkit.StringUtil;
import cn.hippo4j.common.toolkit.ThreadPoolExecutorUtil;
import cn.hippo4j.threadpool.dynamic.mode.config.properties.BootstrapConfigProperties;
import cn.hippo4j.threadpool.message.core.service.GlobalNotifyAlarmManage;
import cn.hippo4j.threadpool.message.core.service.ThreadPoolNotifyAlarm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@ -83,21 +83,27 @@ public class SpringThreadPoolRegisterSupport {
}
Map<String, Executor> beansWithAnnotation = context.getBeansOfType(Executor.class);
for (Map.Entry<String, Executor> entry : beansWithAnnotation.entrySet()) {
String beanName = entry.getKey();
Executor bean = entry.getValue();
ThreadPoolExecutor executor;
beansWithAnnotation.forEach((beanName, bean) -> {
ThreadPoolExecutor executor = null;
// Get ThreadPoolExecutor Instance
if (DynamicThreadPoolAdapterChoose.match(bean)) {
executor = DynamicThreadPoolAdapterChoose.unwrap(bean);
} else {
} else if (bean instanceof ThreadPoolTaskExecutor) {
ThreadPoolTaskExecutor taskExecutor = (ThreadPoolTaskExecutor) bean;
// Get a real instance of ThreadPoolExecutor
executor = taskExecutor.getThreadPoolExecutor();
} else if (bean instanceof ThreadPoolExecutor) {
executor = (ThreadPoolExecutor) bean;
} else {
LOGGER.warn("[Hippo4j-Agent] Thread pool ignore registered beanName={}, Now Unsupported thread pool executor type:{} ", beanName, bean.getClass().getName());
}
if (executor == null) {
LOGGER.warn("[Hippo4j-Agent] Thread pool is null, ignore bean registration. beanName={}, beanClass={}", beanName, bean.getClass().getName());
} else {
register(beanName, executor, Boolean.FALSE);
}
}
});
LOGGER.info("[Hippo4j-Agent] Registered thread pool instances successfully.");
}
@ -105,10 +111,8 @@ public class SpringThreadPoolRegisterSupport {
if (executor == null) {
return;
}
ExecutorProperties executorProperties = SpringPropertiesLoader.BOOTSTRAP_CONFIG_PROPERTIES.getExecutors().stream()
.filter(each -> Objects.equals(threadPoolId, each.getThreadPoolId()))
.findFirst()
.orElse(null);
ExecutorProperties executorProperties =
SpringPropertiesLoader.BOOTSTRAP_CONFIG_PROPERTIES.getExecutors().stream().filter(each -> Objects.equals(threadPoolId, each.getThreadPoolId())).findFirst().orElse(null);
// Determines the thread pool that is currently obtained by bean scanning
if (Objects.isNull(executorProperties)) {
@ -198,16 +202,13 @@ public class SpringThreadPoolRegisterSupport {
.orElseGet(() -> Optional.ofNullable(configProperties.getDefaultExecutor()).map(ExecutorProperties::getRejectedHandler).get()))
.threadNamePrefix(StringUtil.isBlank(executorProperties.getThreadNamePrefix()) ? executorProperties.getThreadPoolId() : executorProperties.getThreadNamePrefix())
.threadPoolId(executorProperties.getThreadPoolId())
.alarm(Optional.ofNullable(executorProperties.getAlarm())
.orElseGet(() -> Optional.ofNullable(configProperties.getDefaultExecutor()).map(ExecutorProperties::getAlarm).orElse(null)))
.alarm(Optional.ofNullable(executorProperties.getAlarm()).orElseGet(() -> Optional.ofNullable(configProperties.getDefaultExecutor()).map(ExecutorProperties::getAlarm).orElse(null)))
.activeAlarm(Optional.ofNullable(executorProperties.getActiveAlarm())
.orElseGet(() -> Optional.ofNullable(configProperties.getDefaultExecutor()).map(ExecutorProperties::getActiveAlarm).orElse(null)))
.capacityAlarm(Optional.ofNullable(executorProperties.getCapacityAlarm())
.orElseGet(() -> Optional.ofNullable(configProperties.getDefaultExecutor()).map(ExecutorProperties::getCapacityAlarm).orElse(null)))
.notify(Optional.ofNullable(executorProperties.getNotify())
.orElseGet(() -> Optional.ofNullable(configProperties.getDefaultExecutor()).map(ExecutorProperties::getNotify).orElse(null)))
.nodes(Optional.ofNullable(executorProperties.getNodes())
.orElseGet(() -> Optional.ofNullable(configProperties.getDefaultExecutor()).map(ExecutorProperties::getNodes).orElse(null)))
.notify(Optional.ofNullable(executorProperties.getNotify()).orElseGet(() -> Optional.ofNullable(configProperties.getDefaultExecutor()).map(ExecutorProperties::getNotify).orElse(null)))
.nodes(Optional.ofNullable(executorProperties.getNodes()).orElseGet(() -> Optional.ofNullable(configProperties.getDefaultExecutor()).map(ExecutorProperties::getNodes).orElse(null)))
.build();
}
@ -220,17 +221,14 @@ public class SpringThreadPoolRegisterSupport {
private static ThreadPoolNotifyAlarm buildThreadPoolNotifyAlarm(ExecutorProperties executorProperties) {
BootstrapConfigProperties configProperties = SpringPropertiesLoader.BOOTSTRAP_CONFIG_PROPERTIES;
ExecutorNotifyProperties notify = Optional.ofNullable(executorProperties).map(ExecutorProperties::getNotify).orElse(null);
boolean isAlarm = Optional.ofNullable(executorProperties.getAlarm())
.orElseGet(() -> Optional.ofNullable(configProperties.getDefaultExecutor()).map(ExecutorProperties::getAlarm).orElse(true));
boolean isAlarm = Optional.ofNullable(executorProperties.getAlarm()).orElseGet(() -> Optional.ofNullable(configProperties.getDefaultExecutor()).map(ExecutorProperties::getAlarm).orElse(true));
int activeAlarm = Optional.ofNullable(executorProperties.getActiveAlarm())
.orElseGet(() -> Optional.ofNullable(configProperties.getDefaultExecutor()).map(ExecutorProperties::getActiveAlarm).orElse(DEFAULT_ACTIVE_ALARM));
int capacityAlarm = Optional.ofNullable(executorProperties.getCapacityAlarm())
.orElseGet(() -> Optional.ofNullable(configProperties.getDefaultExecutor()).map(ExecutorProperties::getCapacityAlarm).orElse(DEFAULT_CAPACITY_ALARM));
int interval = Optional.ofNullable(notify)
.map(ExecutorNotifyProperties::getInterval)
int interval = Optional.ofNullable(notify).map(ExecutorNotifyProperties::getInterval)
.orElseGet(() -> Optional.ofNullable(configProperties.getDefaultExecutor()).map(ExecutorProperties::getNotify).map(ExecutorNotifyProperties::getInterval).orElse(DEFAULT_INTERVAL));
String receive = Optional.ofNullable(notify)
.map(ExecutorNotifyProperties::getReceives)
String receive = Optional.ofNullable(notify).map(ExecutorNotifyProperties::getReceives)
.orElseGet(() -> Optional.ofNullable(configProperties.getDefaultExecutor()).map(ExecutorProperties::getNotify).map(ExecutorNotifyProperties::getReceives).orElse(DEFAULT_RECEIVES));
ThreadPoolNotifyAlarm threadPoolNotifyAlarm = new ThreadPoolNotifyAlarm(isAlarm, activeAlarm, capacityAlarm);
threadPoolNotifyAlarm.setInterval(interval);

@ -93,6 +93,9 @@ public class ThreadPoolCheckAlarmSupport {
// Execute scheduled task to check an alarm
scheduleExecute(threadPoolBaseSendMessageService);
LOGGER.info("[Hippo4j-Agent] Start Check AlarmHandler the running status of dynamic thread pools.");
}
}

@ -23,7 +23,7 @@
<junit.version>4.13.1</junit.version>
<powermock.version>2.0.7</powermock.version>
<mockito-core.version>3.5.13</mockito-core.version>
<lombok.version>1.18.20</lombok.version>
<lombok.version>1.18.34</lombok.version>
<!-- core lib dependency -->
<bytebuddy.version>1.12.13</bytebuddy.version>

@ -6,7 +6,7 @@
<parent>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-threadpool-agent-example</artifactId>
<version>2.0.0-SNAPSHOT</version>
<version>${revision}</version>
</parent>
<artifactId>hippo4j-agent-example-core</artifactId>

@ -6,7 +6,7 @@
<parent>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-threadpool-agent-example</artifactId>
<version>2.0.0-SNAPSHOT</version>
<version>${revision}</version>
</parent>
<artifactId>hippo4j-threadpool-agent-config-apollo-spring-boot-1x</artifactId>

@ -21,7 +21,7 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Agent config Nacos example application.
* Agent config Apollo Spring Boot 1.x example application.
*/
@SpringBootApplication(scanBasePackages = "cn.hippo4j.example.agent.core")
public class AgentConfigApolloSpringBoot1xExampleApplication {

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-threadpool-agent-example</artifactId>
<version>2.0.0-SNAPSHOT</version>
</parent>
<artifactId>hippo4j-threadpool-agent-config-apollo-spring-boot-3x</artifactId>
<properties>
<maven.deploy.skip>true</maven.deploy.skip>
<spring-boot.version>3.0.2</spring-boot.version>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-agent-example-core</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<version>4.1.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.3.4</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,33 @@
/*
* 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.example.agent.config.apollo.v3;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Agent config Apollo boot3 example application.
*/
@SpringBootApplication(scanBasePackages = "cn.hippo4j.example.agent.config.apollo.v3")
public class AgentConfigApolloSpringBoot3xExampleApplication {
public static void main(String[] args) {
SpringApplication.run(AgentConfigApolloSpringBoot3xExampleApplication.class, args);
}
}

@ -0,0 +1,87 @@
/*
* 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.example.agent.config.apollo.v3;
import cn.hippo4j.common.executor.ThreadPoolExecutorHolder;
import cn.hippo4j.common.executor.ThreadPoolExecutorRegistry;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Test alarm send message.
*/
@Slf4j
@Component
public class AlarmSendMessageBootV3Test {
private static final int SLEEP_TIME = 10240124;
private static final int INITIAL_DELAY = 3;
private static final String RUN_MESSAGE_SEND_TASK_EXECUTOR = "runMessageSendTaskExecutor";
private static final String AGENT_RUN_MESSAGE_SEND_TASK_EXECUTOR = "cn.hippo4j.example.agent.config.apollo.v3.ThreadPoolConfigurationBootV3#AGENT_RUN_MESSAGE_SEND_TASK_EXECUTOR";
/**
* Test alarm notification.
* If you need to run this single test, add @PostConstruct to the method.
*/
@SuppressWarnings("all")
// @PostConstruct
public void alarmSendMessageTest() {
ScheduledExecutorService scheduledThreadPool = Executors.newSingleThreadScheduledExecutor();
scheduledThreadPool.scheduleWithFixedDelay(() -> {
ThreadPoolExecutorHolder executorHolder = ThreadPoolExecutorRegistry.getHolder(AGENT_RUN_MESSAGE_SEND_TASK_EXECUTOR);
ThreadPoolExecutor poolExecutor = executorHolder.getExecutor();
try {
poolExecutor.execute(() -> {
try {
Thread.sleep(SLEEP_TIME);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
} catch (Exception ex) {
log.error("Throw reject policy.", ex.getMessage());
}
}, INITIAL_DELAY, 2, TimeUnit.SECONDS);
scheduledThreadPool.scheduleWithFixedDelay(() -> {
ThreadPoolExecutorHolder executorHolder = ThreadPoolExecutorRegistry.getHolder(RUN_MESSAGE_SEND_TASK_EXECUTOR);
ThreadPoolExecutor poolExecutor = executorHolder.getExecutor();
try {
poolExecutor.execute(() -> {
try {
Thread.sleep(SLEEP_TIME);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
} catch (Exception ex) {
log.error("Throw reject policy.", ex.getMessage());
}
}, INITIAL_DELAY, 2, TimeUnit.SECONDS);
}
}

@ -0,0 +1,55 @@
/*
* 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.example.agent.config.apollo.v3;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Configuration
public class ThreadPoolConfigurationBootV3 {
// -------------------------------------------------------------------------
// 未使用 Hippo4j原始定义线程池创建方式
// -------------------------------------------------------------------------
@Bean
public ThreadPoolExecutor runMessageSendTaskExecutor() {
LinkedBlockingQueue<Runnable> linkedBlockingQueue = new LinkedBlockingQueue<>(1024);
return new ThreadPoolExecutor(
1,
10,
1024,
TimeUnit.SECONDS,
linkedBlockingQueue);
}
// -------------------------------------------------------------------------
// 演示 Agent 模式修改线程池
// -------------------------------------------------------------------------
public static final ThreadPoolExecutor AGENT_RUN_MESSAGE_SEND_TASK_EXECUTOR = new ThreadPoolExecutor(
1,
10,
1024,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1024));
}

@ -0,0 +1,66 @@
server.port=8092
server.servlet.context-path=/example
app.id=dynamic-threadpool-example-springboot3-test
apollo.meta=http://127.0.0.1:8080
apollo.autoUpdateInjectedSpringProperties=true
apollo.bootstrap.enabled=true
apollo.bootstrap.namespaces=application
apollo.bootstrap.eagerLoad.enabled=true
# The following parameters are used for testing
env=dev
apollo.configService=http://127.0.0.1:8080
spring.profiles.active=dev
spring.application.name=hippo4j-config-apollo-spring-boot-starter-example
spring.dynamic.thread-pool.enable=true
spring.dynamic.thread-pool.banner=true
spring.dynamic.thread-pool.check-state-interval=10
spring.dynamic.thread-pool.monitor.enable=true
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
#spring.dynamic.thread-pool.notify-platforms[1].platform=WECHAT
#spring.dynamic.thread-pool.notify-platforms[1].token=ac0426a5-c712-474c-9bff-72b8b8f5caff
#spring.dynamic.thread-pool.notify-platforms[2].platform=DING
#spring.dynamic.thread-pool.notify-platforms[2].token=56417ebba6a27ca352f0de77a2ae9da66d01f39610b5ee8a6033c60ef9071c55
spring.dynamic.thread-pool.apollo.namespace=application
spring.dynamic.thread-pool.config-file-type=properties
spring.dynamic.thread-pool.executors[0].thread-name-prefix = DynamicThreadPoolConfig#FIELD1
spring.dynamic.thread-pool.executors[0].core-pool-size = 2
spring.dynamic.thread-pool.executors[0].thread-pool-id = cn.hippo4j.example.agent.config.apollo.v3.ThreadPoolConfigurationBootV3#AGENT_RUN_MESSAGE_SEND_TASK_EXECUTOR
spring.dynamic.thread-pool.executors[0].maximum-pool-size = 20
spring.dynamic.thread-pool.executors[0].queue-capacity = 1024
spring.dynamic.thread-pool.executors[0].blocking-queue = ResizableCapacityLinkedBlockingQueue
spring.dynamic.thread-pool.executors[0].execute-time-out = 800
spring.dynamic.thread-pool.executors[0].rejected-handler = AbortPolicy
spring.dynamic.thread-pool.executors[0].keep-alive-time = 6691
spring.dynamic.thread-pool.executors[0].allow-core-thread-time-out = true
spring.dynamic.thread-pool.executors[0].alarm = true
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

@ -21,7 +21,7 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Agent config apollo example application.
* Agent Apollo Spring Boot 2.x example application.
*/
@SpringBootApplication(scanBasePackages = "cn.hippo4j.example.agent.core")
public class AgentConfigApolloExampleApplication {

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-threadpool-agent-example</artifactId>
<version>2.0.0-SNAPSHOT</version>
</parent>
<artifactId>hippo4j-threadpool-agent-config-nacos-spring-boot-3x</artifactId>
<properties>
<maven.deploy.skip>true</maven.deploy.skip>
<spring-boot.version>3.0.2</spring-boot.version>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-agent-example-core</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2022.0.0.0-RC2</version>
</dependency>
<!-- <dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>nacos-config-spring-boot-starter</artifactId>
<version>0.3.0-RC</version>
</dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>6.0.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.3.4</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.example.agent.config.nacos.v3;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Agent config Nacos boot3 example application.
*/
@SpringBootApplication(scanBasePackages = "cn.hippo4j.example.agent.config.nacos.v3")
public class AgentConfigNacosSpringBoot3xExampleApplication {
public static void main(String[] args) {
SpringApplication.run(AgentConfigNacosSpringBoot3xExampleApplication.class, args);
}
}

@ -0,0 +1,87 @@
/*
* 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.example.agent.config.nacos.v3;
import cn.hippo4j.common.executor.ThreadPoolExecutorHolder;
import cn.hippo4j.common.executor.ThreadPoolExecutorRegistry;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Test alarm send message.
*/
@Slf4j
@Component
public class AlarmSendMessageBootV3Test {
private static final int SLEEP_TIME = 10240124;
private static final int INITIAL_DELAY = 3;
private static final String RUN_MESSAGE_SEND_TASK_EXECUTOR = "runMessageSendTaskExecutor";
private static final String AGENT_RUN_MESSAGE_SEND_TASK_EXECUTOR = "cn.hippo4j.example.agent.config.nacos.v3.ThreadPoolConfigurationBootV3#AGENT_RUN_MESSAGE_SEND_TASK_EXECUTOR";
/**
* Test alarm notification.
* If you need to run this single test, add @PostConstruct to the method.
*/
@SuppressWarnings("all")
//@PostConstruct
public void alarmSendMessageTest() {
ScheduledExecutorService scheduledThreadPool = Executors.newSingleThreadScheduledExecutor();
scheduledThreadPool.scheduleWithFixedDelay(() -> {
ThreadPoolExecutorHolder executorHolder = ThreadPoolExecutorRegistry.getHolder(AGENT_RUN_MESSAGE_SEND_TASK_EXECUTOR);
ThreadPoolExecutor poolExecutor = executorHolder.getExecutor();
try {
poolExecutor.execute(() -> {
try {
Thread.sleep(SLEEP_TIME);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
} catch (Exception ex) {
log.error("Throw reject policy.", ex.getMessage());
}
}, INITIAL_DELAY, 2, TimeUnit.SECONDS);
scheduledThreadPool.scheduleWithFixedDelay(() -> {
ThreadPoolExecutorHolder executorHolder = ThreadPoolExecutorRegistry.getHolder(RUN_MESSAGE_SEND_TASK_EXECUTOR);
ThreadPoolExecutor poolExecutor = executorHolder.getExecutor();
try {
poolExecutor.execute(() -> {
try {
Thread.sleep(SLEEP_TIME);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
} catch (Exception ex) {
log.error("Throw reject policy.", ex.getMessage());
}
}, INITIAL_DELAY, 2, TimeUnit.SECONDS);
}
}

@ -0,0 +1,55 @@
/*
* 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.example.agent.config.nacos.v3;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Configuration
public class ThreadPoolConfigurationBootV3 {
// -------------------------------------------------------------------------
// 未使用 Hippo4j原始定义线程池创建方式
// -------------------------------------------------------------------------
@Bean
public ThreadPoolExecutor runMessageSendTaskExecutor() {
LinkedBlockingQueue<Runnable> linkedBlockingQueue = new LinkedBlockingQueue<>(1024);
return new ThreadPoolExecutor(
1,
10,
1024,
TimeUnit.SECONDS,
linkedBlockingQueue);
}
// -------------------------------------------------------------------------
// 演示 Agent 模式修改线程池
// -------------------------------------------------------------------------
public static final ThreadPoolExecutor AGENT_RUN_MESSAGE_SEND_TASK_EXECUTOR = new ThreadPoolExecutor(
1,
10,
1024,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1024));
}

@ -0,0 +1,76 @@
server.port=8093
server.servlet.context-path=/example
# The following parameters are used for testing
# NacosCloud properties
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
# boot3 version nacosCloud must add , In order to refresh configuration to Env
spring.config.import=nacos:dynamic-threadpool-example-config-boot3?refreshEnabled=true
# NacosBoot properties
#nacos.config.auto-refresh=true
#nacos.config.bootstrap.enable=true
#nacos.config.server-addr=127.0.0.1:8848
#nacos.config.data-id=dynamic-threadpool-example-config-boot3
#nacos.config.group=DEFAULT_GROUP
#nacos.config.type=properties
spring.profiles.active=dev
spring.application.name=hippo4j-config-nacos-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
spring.dynamic.thread-pool.check-state-interval=10
#spring.dynamic.thread-pool.monitor.enable=true
#spring.dynamic.thread-pool.monitor.collect-types=micrometer
#spring.dynamic.thread-pool.monitor.thread-pool-types=dynamic,web
spring.dynamic.thread-pool.monitor.agent-micrometer-port=29999
spring.dynamic.thread-pool.monitor.initial-delay=3000
spring.dynamic.thread-pool.monitor.collect-interval=3000
spring.dynamic.thread-pool.notify-platforms[0].platform=LARK
spring.dynamic.thread-pool.notify-platforms[0].token=6de41bdc-0799-45be-b128-7cddb9e777f0
#spring.dynamic.thread-pool.notify-platforms[1].platform=WECHAT
#spring.dynamic.thread-pool.notify-platforms[1].token=ac0426a5-c712-474c-9bff-72b8b8f5caff
#spring.dynamic.thread-pool.notify-platforms[2].platform=DING
#spring.dynamic.thread-pool.notify-platforms[2].token=56417ebba6a27ca352f0de77a2ae9da66d01f39610b5ee8a6033c60ef9071c55
spring.dynamic.thread-pool.nacos.data-id=dynamic-threadpool-example-config-boot3
spring.dynamic.thread-pool.nacos.group=DEFAULT_GROUP
spring.dynamic.thread-pool.nacos.namespace=public
spring.dynamic.thread-pool.config-file-type=properties
spring.dynamic.thread-pool.executors[0].thread-name-prefix = DynamicThreadPoolConfig#FIELD1
spring.dynamic.thread-pool.executors[0].core-pool-size = 2
spring.dynamic.thread-pool.executors[0].thread-pool-id =cn.hippo4j.example.agent.config.nacos.v3.ThreadPoolConfigurationBootV3#AGENT_RUN_MESSAGE_SEND_TASK_EXECUTOR
spring.dynamic.thread-pool.executors[0].maximum-pool-size = 20
spring.dynamic.thread-pool.executors[0].queue-capacity = 1024
spring.dynamic.thread-pool.executors[0].blocking-queue = ResizableCapacityLinkedBlockingQueue
spring.dynamic.thread-pool.executors[0].execute-time-out = 800
spring.dynamic.thread-pool.executors[0].rejected-handler = AbortPolicy
spring.dynamic.thread-pool.executors[0].keep-alive-time = 6691
spring.dynamic.thread-pool.executors[0].allow-core-thread-time-out = true
spring.dynamic.thread-pool.executors[0].alarm = true
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

@ -22,5 +22,8 @@
<module>agent-example-core</module>
<module>config-nacos-spring-boot-1x</module>
<module>config-apollo-spring-boot-1x</module>
<!--Because SpringBoot3 requires JDK17, if you need to run the boot3x example, you can remove the following comment-->
<!--<module>config-apollo-spring-boot-3x</module>
<module>config-naocs-spring-boot-3x</module>-->
</modules>
</project>

@ -66,7 +66,7 @@
<jacoco-maven-plugin.version>0.8.8</jacoco-maven-plugin.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.plugin.version>3.6.1</maven.compiler.plugin.version>
<maven.compiler.plugin.version>3.12.1</maven.compiler.plugin.version>
<maven.javadoc.plugin.version>3.0.0</maven.javadoc.plugin.version>
<maven.source.plugin.version>3.0.1</maven.source.plugin.version>
<maven.jar.plugin.version>3.0.2</maven.jar.plugin.version>
@ -79,10 +79,16 @@
<maven-checkstyle-plugin.version>3.1.0</maven-checkstyle-plugin.version>
<spring-boot-maven-plugin.version>2.3.2.RELEASE</spring-boot-maven-plugin.version>
<gson.version>2.8.9</gson.version>
<lombok.version>1.18.34</lombok.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-dependencies</artifactId>
@ -126,6 +132,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven.jar.plugin.version}</version>
<configuration>
<archive>
<manifestEntries>

@ -75,7 +75,6 @@ public abstract class AbstractConfigThreadPoolDynamicRefresh implements ThreadPo
ApplicationContextHolder.getInstance().publishEvent(new ThreadPoolConfigDynamicRefreshEvent(this, configProperties));
}
@Override
public void run(ApplicationArguments args) {
try {

Loading…
Cancel
Save