From 6a0d229c3fe2e81f70dc999ce2ed54a31a196a80 Mon Sep 17 00:00:00 2001 From: Li Date: Tue, 22 Nov 2022 17:49:04 +0800 Subject: [PATCH] Support for Consul Configuration Center to dynamically adjust parameters --- .../pom.xml | 45 ++++++++++ .../ConfigConsulExampleApplication.java | 31 +++++++ .../config/DynamicThreadPoolConfig.java | 41 ++++++++++ .../consul/controller/TestController.java | 25 ++++++ .../src/main/resources/bootstrap.yml | 18 ++++ hippo4j-example/pom.xml | 1 + .../pom.xml | 7 ++ .../config/ConfigHandlerConfiguration.java | 13 +++ ...bstractConfigThreadPoolDynamicRefresh.java | 9 ++ .../refresher/ConsulRefresherHandler.java | 82 +++++++++++++++++++ pom.xml | 1 + 11 files changed, 273 insertions(+) create mode 100644 hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/pom.xml create mode 100644 hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/src/main/java/cn/hippo4j/example/config/consul/ConfigConsulExampleApplication.java create mode 100644 hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/src/main/java/cn/hippo4j/example/config/consul/config/DynamicThreadPoolConfig.java create mode 100644 hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/src/main/java/cn/hippo4j/example/config/consul/controller/TestController.java create mode 100644 hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/src/main/resources/bootstrap.yml create mode 100644 hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/ConsulRefresherHandler.java diff --git a/hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/pom.xml b/hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/pom.xml new file mode 100644 index 00000000..e2e5d937 --- /dev/null +++ b/hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + + cn.hippo4j + hippo4j-example + ${revision} + + hippo4j-config-consul-spring-boot-starter-example + + + true + + + + + org.springframework.boot + spring-boot-starter-web + + + cn.hippo4j + hippo4j-example-core + ${revision} + + + cn.hippo4j + hippo4j-config-spring-boot-starter + ${revision} + + + org.springframework.cloud + spring-cloud-starter-consul-config + ${consul.version} + + + io.micrometer + micrometer-registry-prometheus + + + org.springframework.boot + spring-boot-starter-actuator + + + diff --git a/hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/src/main/java/cn/hippo4j/example/config/consul/ConfigConsulExampleApplication.java b/hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/src/main/java/cn/hippo4j/example/config/consul/ConfigConsulExampleApplication.java new file mode 100644 index 00000000..f91081df --- /dev/null +++ b/hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/src/main/java/cn/hippo4j/example/config/consul/ConfigConsulExampleApplication.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.example.config.consul; + +import cn.hippo4j.core.enable.EnableDynamicThreadPool; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@EnableDynamicThreadPool +@SpringBootApplication(scanBasePackages = "cn.hippo4j.example.config.consul") +public class ConfigConsulExampleApplication { + + public static void main(String[] args) { + SpringApplication.run(ConfigConsulExampleApplication.class, args); + } +} diff --git a/hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/src/main/java/cn/hippo4j/example/config/consul/config/DynamicThreadPoolConfig.java b/hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/src/main/java/cn/hippo4j/example/config/consul/config/DynamicThreadPoolConfig.java new file mode 100644 index 00000000..13d57ae4 --- /dev/null +++ b/hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/src/main/java/cn/hippo4j/example/config/consul/config/DynamicThreadPoolConfig.java @@ -0,0 +1,41 @@ +/* + * 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.config.consul.config; + +import cn.hippo4j.core.executor.DynamicThreadPool; +import cn.hippo4j.core.executor.support.ThreadPoolBuilder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.concurrent.ThreadPoolExecutor; + +/** + * Dynamic thread-pool config. + */ +@Slf4j +@Configuration +public class DynamicThreadPoolConfig { + + @Bean + @DynamicThreadPool + public ThreadPoolExecutor messageConsumeDynamicExecutor() { + String threadPoolId = "message-consume"; + return ThreadPoolBuilder.buildDynamicPoolById(threadPoolId); + } +} diff --git a/hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/src/main/java/cn/hippo4j/example/config/consul/controller/TestController.java b/hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/src/main/java/cn/hippo4j/example/config/consul/controller/TestController.java new file mode 100644 index 00000000..df22d43a --- /dev/null +++ b/hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/src/main/java/cn/hippo4j/example/config/consul/controller/TestController.java @@ -0,0 +1,25 @@ +package cn.hippo4j.example.config.consul.controller; + +import cn.hippo4j.config.springboot.starter.config.BootstrapConfigProperties; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.concurrent.ThreadPoolExecutor; + +@Slf4j +@RestController +public class TestController { + + @Resource + private ThreadPoolExecutor messageConsumeDynamicExecutor; + + @GetMapping("/hippo4j-consul/test") + public int test() { + int maximumPoolSize = messageConsumeDynamicExecutor.getMaximumPoolSize(); + int corePoolSize = messageConsumeDynamicExecutor.getCorePoolSize(); + log.info("corePoolSize: {}, maximumPoolSize: {}", corePoolSize, maximumPoolSize); + return corePoolSize + maximumPoolSize; + } +} diff --git a/hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/src/main/resources/bootstrap.yml b/hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/src/main/resources/bootstrap.yml new file mode 100644 index 00000000..adcd25ba --- /dev/null +++ b/hippo4j-example/hippo4j-config-consul-spring-boot-starter-example/src/main/resources/bootstrap.yml @@ -0,0 +1,18 @@ +server: + port: 8091 + +spring: + application: + name: hippo4j-config-consul-spring-boot-starter-example + profiles: + active: dev + cloud: + consul: + host: 127.0.0.1 + port: 8500 + config: + enabled: true + format: yaml + data-key: hippo4j-consul + default-context: application + prefixes: config diff --git a/hippo4j-example/pom.xml b/hippo4j-example/pom.xml index 80999ea3..0a3a623e 100644 --- a/hippo4j-example/pom.xml +++ b/hippo4j-example/pom.xml @@ -21,6 +21,7 @@ hippo4j-config-nacos-spring-boot-starter-example hippo4j-config-apollo-spring-boot-starter-example hippo4j-config-zookeeper-spring-boot-starter-example + hippo4j-config-consul-spring-boot-starter-example hippo4j-spring-boot-starter-adapter-rabbitmq-example hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rabbitmq-example hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rocketmq-example diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/pom.xml b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/pom.xml index 837a1f3b..5302d378 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/pom.xml +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/pom.xml @@ -47,6 +47,13 @@ ${apollo.version} true + + org.springframework.cloud + spring-cloud-starter-consul-config + ${consul.version} + compile + true + org.apache.curator curator-framework diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/ConfigHandlerConfiguration.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/ConfigHandlerConfiguration.java index 21fa48f4..4c1dac08 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/ConfigHandlerConfiguration.java +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/ConfigHandlerConfiguration.java @@ -30,6 +30,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.consul.config.ConsulConfigProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -45,6 +46,8 @@ public class ConfigHandlerConfiguration { private static final String APOLLO_NAMESPACE_KEY = "apollo.namespace"; + private static final String CONSUL_DATA_KEY = "consul.data-key"; + private static final String ZOOKEEPER_CONNECT_STR_KEY = "zookeeper.zk-connect-str"; private static final String ETCD = "etcd.endpoints"; @@ -89,6 +92,16 @@ public class ConfigHandlerConfiguration { } } + @ConditionalOnClass(ConsulConfigProperties.class) + @ConditionalOnProperty(prefix = BootstrapConfigProperties.PREFIX, name = CONSUL_DATA_KEY) + static class EmbeddedConsul { + + @Bean + public ConsulRefresherHandler consulRefresher() { + return new ConsulRefresherHandler(); + } + } + @ConditionalOnClass(CuratorFramework.class) @ConditionalOnProperty(prefix = BootstrapConfigProperties.PREFIX, name = ZOOKEEPER_CONNECT_STR_KEY) static class EmbeddedZookeeper { diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/AbstractConfigThreadPoolDynamicRefresh.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/AbstractConfigThreadPoolDynamicRefresh.java index f78e5873..c0c05cab 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/AbstractConfigThreadPoolDynamicRefresh.java +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/AbstractConfigThreadPoolDynamicRefresh.java @@ -72,4 +72,13 @@ public abstract class AbstractConfigThreadPoolDynamicRefresh implements ThreadPo log.error("Hippo-4J core dynamic refresh failed.", ex); } } + + public void dynamicRefresh(Map configInfo) { + try { + BootstrapConfigProperties binderCoreProperties = bootstrapConfigPropertiesBinderAdapt.bootstrapCorePropertiesBinder(configInfo, bootstrapConfigProperties); + ApplicationContextHolder.getInstance().publishEvent(new Hippo4jConfigDynamicRefreshEvent(this, binderCoreProperties)); + } catch (Exception ex) { + log.error("Hippo-4J core dynamic refresh failed.", ex); + } + } } diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/ConsulRefresherHandler.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/ConsulRefresherHandler.java new file mode 100644 index 00000000..41fe155e --- /dev/null +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/refresher/ConsulRefresherHandler.java @@ -0,0 +1,82 @@ +/* + * 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.config.springboot.starter.refresher; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext; +import org.springframework.cloud.bootstrap.config.BootstrapPropertySource; +import org.springframework.cloud.consul.config.ConsulPropertySource; +import org.springframework.cloud.context.environment.EnvironmentChangeEvent; +import org.springframework.context.event.EventListener; +import org.springframework.core.env.AbstractEnvironment; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * Consul refresher handler. + */ +@Slf4j +public class ConsulRefresherHandler extends AbstractConfigThreadPoolDynamicRefresh { + + private static final String CONSUL_PROPERTY = "${spring.dynamic.thread-pool.consul.data-key}"; + + @Value(CONSUL_PROPERTY) + private String dataKey; + + @EventListener(EnvironmentChangeEvent.class) + public void refreshed(EnvironmentChangeEvent event) { + + + String[] dataKeys = this.dataKey.split(","); + this.dataKey = dataKeys[0]; + + AbstractEnvironment environment = (AbstractEnvironment) ((AnnotationConfigServletWebServerApplicationContext) event.getSource()).getEnvironment(); + List> bootstrapPropertySourceList = environment.getPropertySources().stream() + .filter(propertySource -> propertySource instanceof BootstrapPropertySource) + .map(propertySource -> (BootstrapPropertySource) propertySource).collect(Collectors.toList()); + + Optional> bootstrapPropertySource = bootstrapPropertySourceList.stream() + .filter(source -> source.getName().contains(environment.getActiveProfiles()[0]) + && source.getPropertyNames().length != 0).findFirst(); + + Map configInfo = new HashMap<>(64); + if (bootstrapPropertySource.isPresent()) { + ConsulPropertySource consulPropertySource = (ConsulPropertySource) bootstrapPropertySource.get().getDelegate(); + String[] propertyNames = consulPropertySource.getPropertyNames(); + for (String propertyName : propertyNames) { + configInfo.put(propertyName, consulPropertySource.getProperty(propertyName)); + } + + } + + dynamicRefresh(configInfo); + } + + @Override + public String getProperties() { + return null; + } + + @Override + public void afterPropertiesSet() {} +} diff --git a/pom.xml b/pom.xml index b2de7eed..9b1e8e29 100644 --- a/pom.xml +++ b/pom.xml @@ -61,6 +61,7 @@ 3.4.2 2.3.2.RELEASE 1.9.1 + 2.2.4.RELEASE 0.7.3 1.7.2 2.2.2