From eb1f0b250c20045bb665826cdd341343007d90f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E5=B8=88=E5=85=84?= <102774648+gywanghai@users.noreply.github.com> Date: Wed, 31 Aug 2022 08:16:55 +0800 Subject: [PATCH 1/6] Update README.md (#615) Update README.md: update the second "[good first issue]" to "[good pro issue]" --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 80a6bb4a..4319d233 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Hippo-4J 获得了一些宝贵的荣誉,肯定了 Hippo-4J 作为一款开源 Hippo-4J 获得的成就属于每一位对 Hippo-4J 做出过贡献的成员,感谢各位的贡献。 -如果屏幕前的同学有意提交 Hippo-4J,请参考 [good first issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) 或者 [good first issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+pro+issue%22) 任务列表。 +如果屏幕前的同学有意提交 Hippo-4J,请参考 [good first issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) 或者 [good pro issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+pro+issue%22) 任务列表。 From da9e48785df21d79f1240ecdc5ede6bcc3f294f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?bug=E6=90=AC=E8=BF=90=E5=B7=A5?= <15618796966@163.com> Date: Wed, 31 Aug 2022 09:37:18 +0800 Subject: [PATCH 2/6] test: add ut (#616) --- .../hippo4j/common/toolkit/ArrayUtilTest.java | 25 +++++++- .../common/toolkit/CalculateUtilTest.java | 4 +- .../common/toolkit/CollectionUtilTest.java | 59 +++++++++++++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/hippo4j-common/src/test/java/cn/hippo4j/common/toolkit/ArrayUtilTest.java b/hippo4j-common/src/test/java/cn/hippo4j/common/toolkit/ArrayUtilTest.java index c237c461..358dfd9f 100644 --- a/hippo4j-common/src/test/java/cn/hippo4j/common/toolkit/ArrayUtilTest.java +++ b/hippo4j-common/src/test/java/cn/hippo4j/common/toolkit/ArrayUtilTest.java @@ -17,8 +17,13 @@ package cn.hippo4j.common.toolkit; +import cn.hippo4j.common.function.Matcher; +import com.google.common.base.Strings; +import org.checkerframework.checker.units.qual.A; import org.junit.Test; +import java.lang.reflect.Array; + public class ArrayUtilTest { @Test @@ -29,21 +34,39 @@ public class ArrayUtilTest { @Test public void assertIsNotEmpty() { - + String[] array = new String[0]; + Assert.isTrue(!ArrayUtil.isNotEmpty(array)); } @Test public void assertFirstMatch() { + Matcher matcher = (str) -> "1".equalsIgnoreCase(str); + String[] array = new String[0]; + Assert.isTrue(Strings.isNullOrEmpty(ArrayUtil.firstMatch(matcher, array))); + + array = new String[]{"0"}; + Assert.isTrue(Strings.isNullOrEmpty(ArrayUtil.firstMatch(matcher, array))); + + array = new String[]{"1"}; + Assert.isTrue(!Strings.isNullOrEmpty(ArrayUtil.firstMatch(matcher, array))); } @Test public void assertAddAll() { + String[] array = new String[]{"1"}; + Assert.isTrue(ArrayUtil.addAll(array, null).length == 1); + Assert.isTrue(ArrayUtil.addAll(null, array).length == 1); + Assert.isTrue(ArrayUtil.addAll(array, new String[]{"1"}).length == 2); } @Test public void assertClone() { + Assert.isNull(ArrayUtil.clone(null)); + String[] array = new String[0]; + Assert.isTrue(array != ArrayUtil.clone(array)); + Assert.isTrue(array.length == ArrayUtil.clone(array).length); } } diff --git a/hippo4j-common/src/test/java/cn/hippo4j/common/toolkit/CalculateUtilTest.java b/hippo4j-common/src/test/java/cn/hippo4j/common/toolkit/CalculateUtilTest.java index 55ca885b..715c71c6 100644 --- a/hippo4j-common/src/test/java/cn/hippo4j/common/toolkit/CalculateUtilTest.java +++ b/hippo4j-common/src/test/java/cn/hippo4j/common/toolkit/CalculateUtilTest.java @@ -23,6 +23,8 @@ public class CalculateUtilTest { @Test public void assertDivide() { - + Assert.isTrue(CalculateUtil.divide(200, 100) == 200); + Assert.isTrue(CalculateUtil.divide(100, 200) == 50); + Assert.isTrue(CalculateUtil.divide(100, 100) == 100); } } diff --git a/hippo4j-common/src/test/java/cn/hippo4j/common/toolkit/CollectionUtilTest.java b/hippo4j-common/src/test/java/cn/hippo4j/common/toolkit/CollectionUtilTest.java index f2e47338..b0be6add 100644 --- a/hippo4j-common/src/test/java/cn/hippo4j/common/toolkit/CollectionUtilTest.java +++ b/hippo4j-common/src/test/java/cn/hippo4j/common/toolkit/CollectionUtilTest.java @@ -17,22 +17,81 @@ package cn.hippo4j.common.toolkit; +import com.google.common.collect.Maps; +import org.assertj.core.util.Lists; import org.junit.Test; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + public class CollectionUtilTest { @Test public void assertGetFirst() { + Assert.isNull(CollectionUtil.getFirst(null)); + String first = CollectionUtil.getFirst(Lists.newArrayList("1", "2")); + Assert.notEmpty(first); } @Test public void assertIsEmpty() { + List list = null; + Assert.isTrue(CollectionUtil.isEmpty(list)); + + list = Lists.newArrayList(); + Assert.isTrue(CollectionUtil.isEmpty(list)); + + list = Lists.newArrayList("1"); + Assert.isTrue(!CollectionUtil.isEmpty(list)); + + Map map = null; + Assert.isTrue(CollectionUtil.isEmpty(map)); + + map = Maps.newHashMap(); + Assert.isTrue(CollectionUtil.isEmpty(map)); + + map.put("key", "value"); + Assert.isTrue(!CollectionUtil.isEmpty(map)); + + Iterator iterator = null; + Assert.isTrue(CollectionUtil.isEmpty(iterator)); + + iterator = Lists.emptyList().iterator(); + Assert.isTrue(CollectionUtil.isEmpty(iterator)); + iterator = Lists.newArrayList("1").iterator(); + Assert.isTrue(!CollectionUtil.isEmpty(iterator)); } @Test public void assertIsNotEmpty() { + List list = null; + Assert.isTrue(!CollectionUtil.isNotEmpty(list)); + + list = Lists.newArrayList(); + Assert.isTrue(!CollectionUtil.isNotEmpty(list)); + + list = Lists.newArrayList("1"); + Assert.isTrue(CollectionUtil.isNotEmpty(list)); + + Map map = null; + Assert.isTrue(!CollectionUtil.isNotEmpty(map)); + + map = Maps.newHashMap(); + Assert.isTrue(!CollectionUtil.isNotEmpty(map)); + + map.put("key", "value"); + Assert.isTrue(CollectionUtil.isNotEmpty(map)); + + Iterator iterator = null; + Assert.isTrue(!CollectionUtil.isNotEmpty(iterator)); + + iterator = Lists.emptyList().iterator(); + Assert.isTrue(!CollectionUtil.isNotEmpty(iterator)); + iterator = Lists.newArrayList("1").iterator(); + Assert.isTrue(CollectionUtil.isNotEmpty(iterator)); } } From a655b1dad47441c5e6caefb1d9b91509c1b24a3b Mon Sep 17 00:00:00 2001 From: lucky 8 <40255310+shining-stars-lk@users.noreply.github.com> Date: Wed, 31 Aug 2022 11:24:39 +0800 Subject: [PATCH 3/6] Fix the UndertowWeb adaptation (#619) * Fix the UndertowWeb adaptation * Fix the UndertowWeb adaptation --- .../adapter/web/UndertowWebThreadPoolHandler.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hippo4j-adapter/hippo4j-adapter-web/src/main/java/cn/hippo4j/adapter/web/UndertowWebThreadPoolHandler.java b/hippo4j-adapter/hippo4j-adapter-web/src/main/java/cn/hippo4j/adapter/web/UndertowWebThreadPoolHandler.java index bfdc5b7d..90ba9b7f 100644 --- a/hippo4j-adapter/hippo4j-adapter-web/src/main/java/cn/hippo4j/adapter/web/UndertowWebThreadPoolHandler.java +++ b/hippo4j-adapter/hippo4j-adapter-web/src/main/java/cn/hippo4j/adapter/web/UndertowWebThreadPoolHandler.java @@ -27,7 +27,7 @@ import cn.hippo4j.core.executor.DynamicThreadPoolExecutor; import cn.hutool.core.date.DateUtil; import io.undertow.Undertow; import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.web.embedded.undertow.UndertowWebServer; +import org.springframework.boot.web.embedded.undertow.UndertowServletWebServer; import org.springframework.boot.web.server.WebServer; import org.springframework.util.ReflectionUtils; import org.xnio.Options; @@ -50,11 +50,12 @@ public class UndertowWebThreadPoolHandler extends AbstractWebThreadPoolService { @Override protected Executor getWebThreadPoolByServer(WebServer webServer) { // There is no need to consider reflection performance because the fetch is a singleton. - UndertowWebServer undertowWebServer = (UndertowWebServer) webServer; - Field undertowField = ReflectionUtils.findField(UndertowWebServer.class, UNDERTOW_NAME); + // Springboot 2-3 version, can directly through reflection to obtain the undertow property + UndertowServletWebServer undertowServletWebServer = (UndertowServletWebServer) webServer; + Field undertowField = ReflectionUtils.findField(UndertowServletWebServer.class, UNDERTOW_NAME); ReflectionUtils.makeAccessible(undertowField); - Undertow undertow = (Undertow) ReflectionUtils.getField(undertowField, undertowWebServer); + Undertow undertow = (Undertow) ReflectionUtils.getField(undertowField, undertowServletWebServer); return Objects.isNull(undertow) ? null : undertow.getWorker(); } From 2813f7260c59ad97a1f29107a6e2a52d9324bdef Mon Sep 17 00:00:00 2001 From: weihubeats Date: Wed, 31 Aug 2022 11:28:42 +0800 Subject: [PATCH 4/6] add etcd (#618) --- .../pom.xml | 8 ++ .../config/BootstrapConfigProperties.java | 12 +- .../config/ConfigHandlerConfiguration.java | 16 +++ .../refresher/EtcdRefresherHandler.java | 105 ++++++++++++++++++ pom.xml | 1 + 5 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/core/springboot/starter/refresher/EtcdRefresherHandler.java 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 d3ba03c1..9c3ed8e7 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/pom.xml +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/pom.xml @@ -56,6 +56,14 @@ true + + io.etcd + jetcd-core + ${jetcd.version} + compile + true + + org.springframework.boot spring-boot-configuration-processor diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/core/springboot/starter/config/BootstrapConfigProperties.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/core/springboot/starter/config/BootstrapConfigProperties.java index 430786b1..62ec0ffe 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/core/springboot/starter/config/BootstrapConfigProperties.java +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/core/springboot/starter/config/BootstrapConfigProperties.java @@ -17,14 +17,15 @@ package cn.hippo4j.core.springboot.starter.config; +import java.util.List; +import java.util.Map; + import cn.hippo4j.core.config.BootstrapPropertiesInterface; import cn.hippo4j.core.springboot.starter.parser.ConfigFileTypeEnum; import lombok.Getter; import lombok.Setter; -import org.springframework.boot.context.properties.ConfigurationProperties; -import java.util.List; -import java.util.Map; +import org.springframework.boot.context.properties.ConfigurationProperties; /** * Bootstrap core properties. @@ -86,6 +87,11 @@ public class BootstrapConfigProperties implements BootstrapPropertiesInterface { */ private Map zookeeper; + /** + * etcd config + */ + private Map etcd; + /** * Tomcat thread pool config. */ diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/core/springboot/starter/config/ConfigHandlerConfiguration.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/core/springboot/starter/config/ConfigHandlerConfiguration.java index 23bca9d3..493d2f1d 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/core/springboot/starter/config/ConfigHandlerConfiguration.java +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/core/springboot/starter/config/ConfigHandlerConfiguration.java @@ -21,8 +21,10 @@ import cn.hippo4j.core.springboot.starter.refresher.ApolloRefresherHandler; import cn.hippo4j.core.springboot.starter.refresher.NacosCloudRefresherHandler; import cn.hippo4j.core.springboot.starter.refresher.NacosRefresherHandler; import cn.hippo4j.core.springboot.starter.refresher.ZookeeperRefresherHandler; +import cn.hippo4j.core.springboot.starter.refresher.EtcdRefresherHandler; import com.alibaba.cloud.nacos.NacosConfigManager; import com.alibaba.nacos.api.config.ConfigService; +import io.etcd.jetcd.Client; import lombok.RequiredArgsConstructor; import org.apache.curator.framework.CuratorFramework; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -45,6 +47,8 @@ public class ConfigHandlerConfiguration { private static final String ZOOKEEPER_CONNECT_STR_KEY = "zookeeper.zk-connect-str"; + private static final String ETCD = "endpoints"; + @RequiredArgsConstructor @ConditionalOnClass(ConfigService.class) @ConditionalOnMissingClass(NACOS_CONFIG_MANAGER_KEY) @@ -88,4 +92,16 @@ public class ConfigHandlerConfiguration { return new ZookeeperRefresherHandler(); } } + + @ConditionalOnClass(Client.class) + @ConditionalOnProperty(prefix = BootstrapConfigProperties.PREFIX, name = ETCD) + static class EmbeddedEtcd { + + @Bean + public EtcdRefresherHandler etcdRefresher() { + return new EtcdRefresherHandler(); + } + } + + } diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/core/springboot/starter/refresher/EtcdRefresherHandler.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/core/springboot/starter/refresher/EtcdRefresherHandler.java new file mode 100644 index 00000000..0754752b --- /dev/null +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/core/springboot/starter/refresher/EtcdRefresherHandler.java @@ -0,0 +1,105 @@ +package cn.hippo4j.core.springboot.starter.refresher; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.Objects; + +import cn.hippo4j.common.toolkit.JSONUtil; +import cn.hippo4j.common.toolkit.StringUtil; +import io.etcd.jetcd.ByteSequence; +import io.etcd.jetcd.Client; +import io.etcd.jetcd.ClientBuilder; +import io.etcd.jetcd.KeyValue; +import io.etcd.jetcd.Watch; +import io.etcd.jetcd.watch.WatchEvent; +import io.etcd.jetcd.watch.WatchResponse; +import lombok.extern.slf4j.Slf4j; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +/** + *@author : wh + *@date : 2022/8/30 17:59 + *@description: + */ +@Slf4j +public class EtcdRefresherHandler extends AbstractCoreThreadPoolDynamicRefresh implements ApplicationContextAware { + + private ApplicationContext applicationContext; + + private Client client; + + private static final String ENDPOINTS = "endpoints"; + + private static final String USER = "user"; + + private static final String PASSWORD = "password"; + + private static final String CHARSET = "charset"; + + private static final String AUTHORITY = "authority"; + + private static final String KEY = "key"; + + + @Override + public void afterPropertiesSet() throws Exception { + Map etcd = bootstrapConfigProperties.getEtcd(); + String user = etcd.get(USER); + String password = etcd.get(PASSWORD); + String endpoints = etcd.get(ENDPOINTS); + String authority = etcd.get(AUTHORITY); + String key = etcd.get(KEY); + Charset charset = StringUtil.isBlank(etcd.get(CHARSET)) ? StandardCharsets.UTF_8 : Charset.forName(etcd.get(CHARSET)); + + ClientBuilder clientBuilder = Client.builder().endpoints(endpoints.split(",")); + + client = applicationContext.getBean(Client.class); + if (Objects.isNull(client)) { + client = StringUtil.isAllNotEmpty(user, password) ? clientBuilder.user(ByteSequence.from(user, charset)) + .password(ByteSequence.from(password, charset)).authority(authority) + .build() : clientBuilder.build(); + } + + // todo Currently only supports json + KeyValue keyValue = client.getKVClient().get(ByteSequence.from(key, charset)).get().getKvs().get(0); + if (Objects.isNull(keyValue)) { + return; + } + + client.getWatchClient().watch(ByteSequence.from(key, charset), new Watch.Listener() { + @Override + public void onNext(WatchResponse response) { + WatchEvent watchEvent = response.getEvents().get(0); + WatchEvent.EventType eventType = watchEvent.getEventType(); + // todo Currently only supports json + if (Objects.equals(eventType, WatchEvent.EventType.PUT)) { + KeyValue keyValue1 = watchEvent.getKeyValue(); + String value = keyValue1.getValue().toString(charset); + Map map = JSONUtil.parseObject(value, Map.class); + dynamicRefresh(keyValue1.getKey().toString(charset), map); + } + + } + + @Override + public void onError(Throwable throwable) { + log.error("dynamic thread pool etcd config watcher exception ", throwable); + } + + @Override + public void onCompleted() { + log.info("dynamic thread pool etcd config key refreshed, config key {}", key); + } + }); + + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } +} diff --git a/pom.xml b/pom.xml index ec01bb02..ca39d771 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,7 @@ 3.4.2 2.3.2.RELEASE 1.9.1 + 0.7.3 2.2.2 4.1.56.Final 9.0.55 From f3c5fc083bbb534c2d535a7f9c67daa50a14a3ea Mon Sep 17 00:00:00 2001 From: Lijx Date: Wed, 31 Aug 2022 18:18:51 +0800 Subject: [PATCH 5/6] Register company information (#621) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 登记公司 * Register company information --- docs/docs/community/powered-by.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/docs/community/powered-by.md b/docs/docs/community/powered-by.md index ced23458..4570ffa3 100644 --- a/docs/docs/community/powered-by.md +++ b/docs/docs/community/powered-by.md @@ -12,7 +12,7 @@ sidebar_position: 3 ## 谁在使用 Hippo4J -共计 16+ 家公司生产接入 Hippo4J。按照公司登记时间排序。 +共计 17+ 家公司生产接入 Hippo4J。按照公司登记时间排序。 - [身边云](https://serviceshare.com) - [Medbanks](https://www.medbanks.cn) @@ -30,3 +30,4 @@ sidebar_position: 3 - [众合云科(51社保)](https://home.101hr.com/) - [好货云店](https://pc.haohuoyundian.com/) - [斗象科技](https://www.tophant.com/) +- [深圳航天信息有限公司](http://sz.aisino.com/) From 6a0a05728907bbcf8976c85679347f5476543190 Mon Sep 17 00:00:00 2001 From: "chen.ma" Date: Wed, 31 Aug 2022 22:10:08 +0800 Subject: [PATCH 6/6] Update official documentation --- docs/docusaurus.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index d5d60cd7..50df8518 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -64,7 +64,7 @@ const config = { // content: `👉 《小马哥的代码实战课》官方知识星球来啦!!!`, }, navbar: { - title: 'hippoforjava', + title: 'HIPPO-4J', logo: { alt: 'HIPPO-4J 动态可观测线程池框架', src: 'img/web.png',