From d9d56d0574f4ff6e21851f6d0819334f72f9ee71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=89=91=E9=91=AB?= <1064730540@qq.com> Date: Sun, 5 Mar 2023 22:02:03 +0800 Subject: [PATCH 01/10] feat: kafka support #229 #231 #269 --- hippo4j-adapter/hippo4j-adapter-kafka/pom.xml | 24 ++ .../adapter/kafka/KafkaThreadPoolAdapter.java | 208 ++++++++++++++++++ hippo4j-adapter/pom.xml | 1 + .../hippo4j/common/toolkit/ReflectUtil.java | 38 ++++ .../common/spi/MyArrayBlockingQueue.java | 17 ++ .../pom.xml | 49 +++++ .../adapter/kafka/example/MessageConsume.java | 35 +++ .../adapter/kafka/example/MessageProduce.java | 65 ++++++ .../ServerAdapterKafkaExampleApplication.java | 31 +++ .../src/main/resources/application.properties | 13 ++ hippo4j-example/pom.xml | 1 + .../pom.xml | 24 ++ .../kafka/KafkaAdapterAutoConfiguration.java | 49 +++++ .../main/resources/META-INF/spring.factories | 1 + .../pom.xml | 1 + 15 files changed, 557 insertions(+) create mode 100644 hippo4j-adapter/hippo4j-adapter-kafka/pom.xml create mode 100644 hippo4j-adapter/hippo4j-adapter-kafka/src/main/java/cn/hippo4j/adapter/kafka/KafkaThreadPoolAdapter.java create mode 100644 hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/pom.xml create mode 100644 hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/src/main/java/cn/hippo4j/springboot/starter/adapter/kafka/example/MessageConsume.java create mode 100644 hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/src/main/java/cn/hippo4j/springboot/starter/adapter/kafka/example/MessageProduce.java create mode 100644 hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/src/main/java/cn/hippo4j/springboot/starter/adapter/kafka/example/ServerAdapterKafkaExampleApplication.java create mode 100644 hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/src/main/resources/application.properties create mode 100644 hippo4j-spring-boot/hippo4j-spring-boot-starter-adapter/hippo4j-spring-boot-starter-adapter-kafka/pom.xml create mode 100644 hippo4j-spring-boot/hippo4j-spring-boot-starter-adapter/hippo4j-spring-boot-starter-adapter-kafka/src/main/java/cn/hippo4j/springboot/starter/adapter/kafka/KafkaAdapterAutoConfiguration.java create mode 100644 hippo4j-spring-boot/hippo4j-spring-boot-starter-adapter/hippo4j-spring-boot-starter-adapter-kafka/src/main/resources/META-INF/spring.factories diff --git a/hippo4j-adapter/hippo4j-adapter-kafka/pom.xml b/hippo4j-adapter/hippo4j-adapter-kafka/pom.xml new file mode 100644 index 00000000..b963ef9f --- /dev/null +++ b/hippo4j-adapter/hippo4j-adapter-kafka/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + cn.hippo4j + hippo4j-adapter + ${revision} + + hippo4j-adapter-kafka + + + + cn.hippo4j + hippo4j-adapter-base + ${project.version} + + + org.springframework.kafka + spring-kafka + true + + + diff --git a/hippo4j-adapter/hippo4j-adapter-kafka/src/main/java/cn/hippo4j/adapter/kafka/KafkaThreadPoolAdapter.java b/hippo4j-adapter/hippo4j-adapter-kafka/src/main/java/cn/hippo4j/adapter/kafka/KafkaThreadPoolAdapter.java new file mode 100644 index 00000000..21e417ac --- /dev/null +++ b/hippo4j-adapter/hippo4j-adapter-kafka/src/main/java/cn/hippo4j/adapter/kafka/KafkaThreadPoolAdapter.java @@ -0,0 +1,208 @@ +/* + * 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.adapter.kafka; + +import cn.hippo4j.adapter.base.ThreadPoolAdapter; +import cn.hippo4j.adapter.base.ThreadPoolAdapterParameter; +import cn.hippo4j.adapter.base.ThreadPoolAdapterState; +import cn.hippo4j.common.config.ApplicationContextHolder; +import cn.hippo4j.common.toolkit.ReflectUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.event.ApplicationStartedEvent; +import org.springframework.cglib.core.Constants; +import org.springframework.context.ApplicationListener; +import org.springframework.kafka.config.KafkaListenerEndpointRegistry; +import org.springframework.kafka.listener.ConcurrentMessageListenerContainer; +import org.springframework.kafka.listener.ContainerProperties; +import org.springframework.kafka.listener.KafkaMessageListenerContainer; +import org.springframework.kafka.listener.MessageListenerContainer; +import org.springframework.kafka.support.TopicPartitionOffset; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import static cn.hippo4j.common.constant.ChangeThreadPoolConstants.CHANGE_DELIMITER; + +/** + * Kafka thread-pool adapter. + */ +@Slf4j +public class KafkaThreadPoolAdapter implements ThreadPoolAdapter, ApplicationListener { + + private KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry; + + @Override + public String mark() { + return "Kafka"; + } + + @Override + public ThreadPoolAdapterState getThreadPoolState(String identify) { + ThreadPoolAdapterState result = new ThreadPoolAdapterState(); + MessageListenerContainer listenerContainer = kafkaListenerEndpointRegistry.getListenerContainer(identify); + + if (listenerContainer == null) { + log.warn("[{}] Kafka consuming thread pool not found.", identify); + return result; + } + + result.setThreadPoolKey(identify); + if (listenerContainer instanceof ConcurrentMessageListenerContainer) { + result.setCoreSize(((ConcurrentMessageListenerContainer) listenerContainer).getConcurrency()); + result.setMaximumSize(result.getCoreSize()); + } else { + result.setCoreSize(1); + result.setMaximumSize(1); + } + return result; + } + + @Override + public List getThreadPoolStates() { + List adapterStateList = new ArrayList<>(); + kafkaListenerEndpointRegistry.getListenerContainerIds().forEach(id -> adapterStateList.add(getThreadPoolState(id))); + return adapterStateList; + } + + @Override + public boolean updateThreadPool(ThreadPoolAdapterParameter threadPoolAdapterParameter) { + String threadPoolKey = threadPoolAdapterParameter.getThreadPoolKey(); + MessageListenerContainer listenerContainer = kafkaListenerEndpointRegistry.getListenerContainer(threadPoolKey); + + if (listenerContainer == null) { + log.warn("[{}] Kafka consuming thread pool not found.", threadPoolKey); + return false; + } + if (!(listenerContainer instanceof ConcurrentMessageListenerContainer)) { + log.warn("[{}] Kafka consuming thread pool not support modify.", threadPoolKey); + return false; + } + ConcurrentMessageListenerContainer concurrentContainer = (ConcurrentMessageListenerContainer) listenerContainer; + int originalCoreSize = concurrentContainer.getConcurrency(); + int originalMaximumPoolSize = originalCoreSize; + Integer concurrency = threadPoolAdapterParameter.getCorePoolSize(); + if (originalCoreSize < concurrency) { + // add consumer + if (!addConsumer(threadPoolKey, concurrentContainer, originalCoreSize, concurrency)) { + return false; + } + } else { + // stop consumer + decreaseConsumer(threadPoolKey, concurrentContainer, originalCoreSize, concurrency); + } + concurrentContainer.setConcurrency(concurrency); + log.info("[{}] Kafka consumption thread pool parameter change. coreSize: {}, maximumSize: {}", + threadPoolKey, + String.format(CHANGE_DELIMITER, originalCoreSize, concurrency), + String.format(CHANGE_DELIMITER, originalMaximumPoolSize, concurrency)); + return true; + + } + + /** + * @param threadPoolKey + * @param concurrentContainer + * @param originalCoreSize + * @param concurrency + * @since org.springframework.kafka.listener.ConcurrentMessageListenerContainer.doStop + */ + private static void decreaseConsumer(String threadPoolKey, ConcurrentMessageListenerContainer concurrentContainer, int originalCoreSize, Integer concurrency) { + int targetDecrease = originalCoreSize - concurrency; + List containers = (List) ReflectUtil.getFieldValue(concurrentContainer, "containers"); + Iterator iterator = containers.iterator(); + int count = 0; + while (iterator.hasNext() && count < targetDecrease) { + KafkaMessageListenerContainer container = iterator.next(); + if (container.isRunning()) { + container.stop(() -> { + }); + count++; + } + } + log.info("[{}] Kafka consumption change. target decrease {} ,real decrease {}", threadPoolKey, targetDecrease, count); + } + + /** + * @param threadPoolKey + * @param concurrentContainer + * @param originalCoreSize + * @param concurrency + * @return true success + * @since org.springframework.kafka.listener.ConcurrentMessageListenerContainer#doStart() + */ + private static boolean addConsumer(String threadPoolKey, ConcurrentMessageListenerContainer concurrentContainer, int originalCoreSize, Integer concurrency) { + ContainerProperties containerProperties = concurrentContainer.getContainerProperties(); + TopicPartitionOffset[] topicPartitions = containerProperties.getTopicPartitions(); + if (topicPartitions != null && concurrency > topicPartitions.length) { + log.warn("[{}] Kafka consuming thread pool not support modify. " + + "When specific partitions are provided, the concurrency must be less than or " + + "equal to the number of partitions;", threadPoolKey); + return false; + } + List containers = (List) ReflectUtil.getFieldValue(concurrentContainer, "containers"); + boolean alwaysClientIdSuffix = (Boolean) ReflectUtil.getFieldValue(concurrentContainer, "alwaysClientIdSuffix"); + int size = containers.size(); + for (int i = size; i < concurrency - originalCoreSize + size; i++) { + KafkaMessageListenerContainer container = ReflectUtil.invoke(concurrentContainer, "constructContainer", containerProperties, topicPartitions, i); + String beanName = concurrentContainer.getBeanName(); + container.setBeanName((beanName != null ? beanName : "consumer") + "-" + i); + container.setApplicationContext(ApplicationContextHolder.getInstance()); + if (concurrentContainer.getApplicationEventPublisher() != null) { + container.setApplicationEventPublisher(concurrentContainer.getApplicationEventPublisher()); + } + container.setClientIdSuffix(concurrency > 1 || alwaysClientIdSuffix ? "-" + i : ""); + container.setGenericErrorHandler(ReflectUtil.invoke(concurrentContainer, "getGenericErrorHandler")); + container.setAfterRollbackProcessor(ReflectUtil.invoke(concurrentContainer, "getAfterRollbackProcessor")); + + Method getRecordInterceptor = ReflectUtil.findDeclaredMethod(concurrentContainer.getClass(), "getRecordInterceptor", Constants.EMPTY_CLASS_ARRAY); + ReflectUtil.setAccessible(getRecordInterceptor); + container.setRecordInterceptor(ReflectUtil.invoke(concurrentContainer, getRecordInterceptor)); + + Method isInterceptBeforeTx = ReflectUtil.findDeclaredMethod(concurrentContainer.getClass(), "isInterceptBeforeTx", Constants.EMPTY_CLASS_ARRAY); + ReflectUtil.setAccessible(isInterceptBeforeTx); + container.setInterceptBeforeTx(ReflectUtil.invoke(concurrentContainer, isInterceptBeforeTx)); + + container.setEmergencyStop(() -> { + concurrentContainer.stop(() -> { + }); + ReflectUtil.invoke(concurrentContainer, "publishContainerStoppedEvent"); + }); + Method isPaused = ReflectUtil.findDeclaredMethod(concurrentContainer.getClass(), "isPaused", Constants.EMPTY_CLASS_ARRAY); + ReflectUtil.setAccessible(isPaused); + + if (ReflectUtil.invoke(concurrentContainer, isPaused)) { + container.pause(); + } + container.start(); + containers.add(container); + } + return true; + } + + @Override + public void onApplicationEvent(ApplicationStartedEvent event) { + try { + KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry = ApplicationContextHolder.getBean(KafkaListenerEndpointRegistry.class); + this.kafkaListenerEndpointRegistry = kafkaListenerEndpointRegistry; + } catch (Exception ex) { + log.error("Failed to get Kafka thread pool.", ex); + } + } +} diff --git a/hippo4j-adapter/pom.xml b/hippo4j-adapter/pom.xml index e65296d8..263f7ccd 100644 --- a/hippo4j-adapter/pom.xml +++ b/hippo4j-adapter/pom.xml @@ -17,6 +17,7 @@ hippo4j-adapter-alibaba-dubbo hippo4j-adapter-rabbitmq hippo4j-adapter-rocketmq + hippo4j-adapter-kafka hippo4j-adapter-hystrix hippo4j-adapter-spring-cloud-stream-rocketmq hippo4j-adapter-spring-cloud-stream-rabbitmq diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/ReflectUtil.java b/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/ReflectUtil.java index 8f4fc5b4..317740ba 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/ReflectUtil.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/ReflectUtil.java @@ -20,6 +20,7 @@ package cn.hippo4j.common.toolkit; import cn.hippo4j.common.web.exception.IllegalException; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import org.springframework.cglib.core.ReflectUtils; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; @@ -234,6 +235,28 @@ public class ReflectUtil { return null; } + /** + * Invoke. + * + * @param obj the obj + * @param methodName the method Name + * @param arguments parameters + * @return result for zhe method + */ + @SuppressWarnings("unchecked") + public static T invoke(Object obj, String methodName, Object... arguments) { + try { + Method method = ReflectUtil.getMethodByName(obj.getClass(), methodName); + if (method == null) { + throw new IllegalException(methodName + "method not exists"); + } + ReflectUtil.setAccessible(method); + return (T) method.invoke(obj, arguments); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalException(e); + } + } + /** * Invoke. * @@ -283,4 +306,19 @@ public class ReflectUtil { } return null; } + + /** + * + * @param clazz + * @param methodName + * @param parameterTypes + * @return + */ + public static Method findDeclaredMethod(Class clazz, String methodName, Class[] parameterTypes) { + try { + return ReflectUtils.findDeclaredMethod(clazz, methodName, parameterTypes); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } } diff --git a/hippo4j-common/src/test/java/cn/hippo4j/common/spi/MyArrayBlockingQueue.java b/hippo4j-common/src/test/java/cn/hippo4j/common/spi/MyArrayBlockingQueue.java index 16b86e2e..47408032 100644 --- a/hippo4j-common/src/test/java/cn/hippo4j/common/spi/MyArrayBlockingQueue.java +++ b/hippo4j-common/src/test/java/cn/hippo4j/common/spi/MyArrayBlockingQueue.java @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package cn.hippo4j.common.spi; import cn.hippo4j.common.executor.support.CustomBlockingQueue; diff --git a/hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/pom.xml b/hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/pom.xml new file mode 100644 index 00000000..70e5d3a4 --- /dev/null +++ b/hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + cn.hippo4j + hippo4j-example + ${revision} + + hippo4j-spring-boot-starter-adapter-kafka-example + + + true + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + org.projectlombok + lombok + + + cn.hippo4j + hippo4j-spring-boot-starter-adapter-kafka + ${project.version} + + + cn.hippo4j + hippo4j-spring-boot-starter + ${project.version} + + + cn.hippo4j + hippo4j-example-core + ${revision} + + + org.springframework.kafka + spring-kafka + + + diff --git a/hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/src/main/java/cn/hippo4j/springboot/starter/adapter/kafka/example/MessageConsume.java b/hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/src/main/java/cn/hippo4j/springboot/starter/adapter/kafka/example/MessageConsume.java new file mode 100644 index 00000000..c146b598 --- /dev/null +++ b/hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/src/main/java/cn/hippo4j/springboot/starter/adapter/kafka/example/MessageConsume.java @@ -0,0 +1,35 @@ +/* + * 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.springboot.starter.adapter.kafka.example; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Service; + +/** + * Message consume. + */ +@Slf4j +@Service +public class MessageConsume { + + @KafkaListener(id = "testId1", topics = MessageProduce.TOPIC, groupId = "testGroup") + public void onMessage(String message) { + log.info("Message: {}", message); + } +} diff --git a/hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/src/main/java/cn/hippo4j/springboot/starter/adapter/kafka/example/MessageProduce.java b/hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/src/main/java/cn/hippo4j/springboot/starter/adapter/kafka/example/MessageProduce.java new file mode 100644 index 00000000..d910d9e1 --- /dev/null +++ b/hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/src/main/java/cn/hippo4j/springboot/starter/adapter/kafka/example/MessageProduce.java @@ -0,0 +1,65 @@ +/* + * 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.springboot.starter.adapter.kafka.example; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.PostConstruct; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +/** + * Message produce. + */ +@Slf4j +@Component +@RestController +@AllArgsConstructor +public class MessageProduce { + + public static final String TOPIC = "test"; + + private final KafkaTemplate template; + + @GetMapping("/message/send") + public String sendMessage() { + template.send(TOPIC, "testMessage"); + return "success"; + } + + @PostConstruct + public void init() { + Thread t = new Thread(() -> { + while (true) { + String message = UUID.randomUUID().toString(); + template.send(TOPIC, "autoTestMessage " + message); + try { + TimeUnit.SECONDS.sleep(3); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }); + t.start(); + } +} diff --git a/hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/src/main/java/cn/hippo4j/springboot/starter/adapter/kafka/example/ServerAdapterKafkaExampleApplication.java b/hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/src/main/java/cn/hippo4j/springboot/starter/adapter/kafka/example/ServerAdapterKafkaExampleApplication.java new file mode 100644 index 00000000..08e6f069 --- /dev/null +++ b/hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/src/main/java/cn/hippo4j/springboot/starter/adapter/kafka/example/ServerAdapterKafkaExampleApplication.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.springboot.starter.adapter.kafka.example; + +import cn.hippo4j.core.enable.EnableDynamicThreadPool; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@EnableDynamicThreadPool +@SpringBootApplication(scanBasePackages = {"cn.hippo4j.example.core", "cn.hippo4j.springboot.starter.adapter.kafka.example"}) +public class ServerAdapterKafkaExampleApplication { + + public static void main(String[] args) { + SpringApplication.run(ServerAdapterKafkaExampleApplication.class, args); + } +} diff --git a/hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/src/main/resources/application.properties b/hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/src/main/resources/application.properties new file mode 100644 index 00000000..ed0c980e --- /dev/null +++ b/hippo4j-example/hippo4j-spring-boot-starter-adapter-kafka-example/src/main/resources/application.properties @@ -0,0 +1,13 @@ +server.port=8011 + +debug=true + +spring.application.name=hippo4j-spring-boot-starter-adapter-kafka-example +spring.dynamic.thread-pool.server-addr=http://localhost:6691 +spring.dynamic.thread-pool.namespace=prescription +spring.dynamic.thread-pool.item-id=dynamic-threadpool-example +spring.dynamic.thread-pool.username=admin +spring.dynamic.thread-pool.password=123456 + + +spring.kafka.bootstrap-servers=localhost:9093,localhost:9094,localhost:9095 \ No newline at end of file diff --git a/hippo4j-example/pom.xml b/hippo4j-example/pom.xml index 0a3a623e..04daf166 100644 --- a/hippo4j-example/pom.xml +++ b/hippo4j-example/pom.xml @@ -26,6 +26,7 @@ hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rabbitmq-example hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rocketmq-example hippo4j-spring-boot-starter-adapter-rocketmq-example + hippo4j-spring-boot-starter-adapter-kafka-example hippo4j-config-etcd-spring-boot-starter-example hippo4j-config-nacos-spring-boot-1x-starter-example hippo4j-config-apollo-spring-boot-1x-starter-example diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter-adapter/hippo4j-spring-boot-starter-adapter-kafka/pom.xml b/hippo4j-spring-boot/hippo4j-spring-boot-starter-adapter/hippo4j-spring-boot-starter-adapter-kafka/pom.xml new file mode 100644 index 00000000..1de46008 --- /dev/null +++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter-adapter/hippo4j-spring-boot-starter-adapter-kafka/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + cn.hippo4j + hippo4j-spring-boot-starter-adapter + ${revision} + + hippo4j-spring-boot-starter-adapter-kafka + + + + cn.hippo4j + hippo4j-adapter-kafka + ${project.version} + + + org.springframework.kafka + spring-kafka + true + + + diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter-adapter/hippo4j-spring-boot-starter-adapter-kafka/src/main/java/cn/hippo4j/springboot/starter/adapter/kafka/KafkaAdapterAutoConfiguration.java b/hippo4j-spring-boot/hippo4j-spring-boot-starter-adapter/hippo4j-spring-boot-starter-adapter-kafka/src/main/java/cn/hippo4j/springboot/starter/adapter/kafka/KafkaAdapterAutoConfiguration.java new file mode 100644 index 00000000..24107d28 --- /dev/null +++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter-adapter/hippo4j-spring-boot-starter-adapter-kafka/src/main/java/cn/hippo4j/springboot/starter/adapter/kafka/KafkaAdapterAutoConfiguration.java @@ -0,0 +1,49 @@ +/* + * 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.springboot.starter.adapter.kafka; + +import cn.hippo4j.adapter.kafka.KafkaThreadPoolAdapter; +import cn.hippo4j.common.config.ApplicationContextHolder; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.KafkaTemplate; + +/** + * Kafka adapter auto configuration. + */ +@Configuration +@AutoConfigureAfter(KafkaAutoConfiguration.class) +public class KafkaAdapterAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public ApplicationContextHolder simpleApplicationContextHolder() { + return new ApplicationContextHolder(); + } + + @Bean + @SuppressWarnings("all") + @ConditionalOnBean(KafkaTemplate.class) + public KafkaThreadPoolAdapter kafkaThreadPoolAdapter(ApplicationContextHolder applicationContextHolder) { + return new KafkaThreadPoolAdapter(); + } +} diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter-adapter/hippo4j-spring-boot-starter-adapter-kafka/src/main/resources/META-INF/spring.factories b/hippo4j-spring-boot/hippo4j-spring-boot-starter-adapter/hippo4j-spring-boot-starter-adapter-kafka/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..592fba93 --- /dev/null +++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter-adapter/hippo4j-spring-boot-starter-adapter-kafka/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.hippo4j.springboot.starter.adapter.kafka.KafkaAdapterAutoConfiguration diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter-adapter/pom.xml b/hippo4j-spring-boot/hippo4j-spring-boot-starter-adapter/pom.xml index f2c5b783..1781a251 100644 --- a/hippo4j-spring-boot/hippo4j-spring-boot-starter-adapter/pom.xml +++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter-adapter/pom.xml @@ -17,6 +17,7 @@ hippo4j-spring-boot-starter-adapter-alibaba-dubbo hippo4j-spring-boot-starter-adapter-rabbitmq hippo4j-spring-boot-starter-adapter-rocketmq + hippo4j-spring-boot-starter-adapter-kafka hippo4j-spring-boot-starter-adapter-hystrix hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rocketmq hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rabbitmq From d369391acadf9668e3914f2924625499e0b5449f Mon Sep 17 00:00:00 2001 From: machen Date: Mon, 13 Mar 2023 21:15:48 +0800 Subject: [PATCH 02/10] Refactor blocking queue enum --- .../support/BlockingQueueTypeEnum.java | 80 +++++++++++++------ 1 file changed, 55 insertions(+), 25 deletions(-) diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/BlockingQueueTypeEnum.java b/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/BlockingQueueTypeEnum.java index 31ab11da..6d4d2d26 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/BlockingQueueTypeEnum.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/BlockingQueueTypeEnum.java @@ -47,6 +47,11 @@ public enum BlockingQueueTypeEnum { BlockingQueue of(Integer capacity) { return new ArrayBlockingQueue<>(capacity); } + + @Override + BlockingQueue of() { + return new ArrayBlockingQueue<>(DEFAULT_CAPACITY); + } }, /** @@ -57,12 +62,22 @@ public enum BlockingQueueTypeEnum { BlockingQueue of(Integer capacity) { return new LinkedBlockingQueue<>(capacity); } + + @Override + BlockingQueue of() { + return new LinkedBlockingQueue<>(); + } }, /** * {@link java.util.concurrent.LinkedBlockingDeque} */ LINKED_BLOCKING_DEQUE(3, "LinkedBlockingDeque") { + @Override + BlockingQueue of(Integer capacity) { + return new LinkedBlockingDeque<>(capacity); + } + @Override BlockingQueue of() { return new LinkedBlockingDeque<>(); @@ -73,6 +88,11 @@ public enum BlockingQueueTypeEnum { * {@link java.util.concurrent.SynchronousQueue} */ SYNCHRONOUS_QUEUE(4, "SynchronousQueue") { + @Override + BlockingQueue of(Integer capacity) { + return new SynchronousQueue<>(); + } + @Override BlockingQueue of() { return new SynchronousQueue<>(); @@ -83,6 +103,11 @@ public enum BlockingQueueTypeEnum { * {@link java.util.concurrent.LinkedTransferQueue} */ LINKED_TRANSFER_QUEUE(5, "LinkedTransferQueue") { + @Override + BlockingQueue of(Integer capacity) { + return new LinkedTransferQueue<>(); + } + @Override BlockingQueue of() { return new LinkedTransferQueue<>(); @@ -97,6 +122,11 @@ public enum BlockingQueueTypeEnum { BlockingQueue of(Integer capacity) { return new PriorityBlockingQueue<>(capacity); } + + @Override + BlockingQueue of() { + return new PriorityBlockingQueue<>(); + } }, /** @@ -107,6 +137,11 @@ public enum BlockingQueueTypeEnum { BlockingQueue of(Integer capacity) { return new ResizableCapacityLinkedBlockingQueue<>(capacity); } + + @Override + BlockingQueue of() { + return new ResizableCapacityLinkedBlockingQueue<>(); + } }; @Getter @@ -115,24 +150,6 @@ public enum BlockingQueueTypeEnum { @Getter private String name; - BlockingQueueTypeEnum(int type, String name) { - this.type = type; - this.name = name; - } - - private static Map typeToEnumMap; - private static Map nameToEnumMap; - - static { - final BlockingQueueTypeEnum[] values = BlockingQueueTypeEnum.values(); - typeToEnumMap = new HashMap<>(values.length); - nameToEnumMap = new HashMap<>(values.length); - for (BlockingQueueTypeEnum value : values) { - typeToEnumMap.put(value.type, value); - nameToEnumMap.put(value.name, value); - } - } - /** * Create the specified implement of BlockingQueue with init capacity. * Abstract method, depends on sub override @@ -141,9 +158,7 @@ public enum BlockingQueueTypeEnum { * @param the class of the objects in the BlockingQueue * @return a BlockingQueue view of the specified T */ - BlockingQueue of(Integer capacity) { - throw new NotSupportedException("该队列必须有界"); - } + abstract BlockingQueue of(Integer capacity); /** * Create the specified implement of BlockingQueue,has no capacity limit. @@ -153,8 +168,24 @@ public enum BlockingQueueTypeEnum { * @return a BlockingQueue view of the specified T * @throws NotSupportedException */ - BlockingQueue of() { - throw new NotSupportedException("该队列不支持有界"); + abstract BlockingQueue of(); + + BlockingQueueTypeEnum(int type, String name) { + this.type = type; + this.name = name; + } + + private static Map typeToEnumMap; + private static Map nameToEnumMap; + + static { + final BlockingQueueTypeEnum[] values = BlockingQueueTypeEnum.values(); + typeToEnumMap = new HashMap<>(values.length); + nameToEnumMap = new HashMap<>(values.length); + for (BlockingQueueTypeEnum value : values) { + typeToEnumMap.put(value.type, value); + nameToEnumMap.put(value.name, value); + } } /** @@ -188,7 +219,7 @@ public enum BlockingQueueTypeEnum { if (typeEnum == null) { return null; } - return Objects.isNull(capacity) ? typeEnum.of() : typeEnum.of(capacity); + return typeEnum.of(); } private static final int DEFAULT_CAPACITY = 1024; @@ -197,7 +228,6 @@ public enum BlockingQueueTypeEnum { DynamicThreadPoolServiceLoader.register(CustomBlockingQueue.class); } - private static BlockingQueue customOrDefaultQueue(Integer capacity, Predicate predicate) { Collection customBlockingQueues = DynamicThreadPoolServiceLoader .getSingletonServiceInstances(CustomBlockingQueue.class); From fd6b4a3e348ccd9fa65f4cc22d001c8b91ebd10b Mon Sep 17 00:00:00 2001 From: machen Date: Mon, 13 Mar 2023 21:21:26 +0800 Subject: [PATCH 03/10] Refactor blocking queue enum --- .../hippo4j/common/executor/support/BlockingQueueTypeEnum.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/BlockingQueueTypeEnum.java b/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/BlockingQueueTypeEnum.java index 6d4d2d26..a2f2c0e1 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/BlockingQueueTypeEnum.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/BlockingQueueTypeEnum.java @@ -219,7 +219,7 @@ public enum BlockingQueueTypeEnum { if (typeEnum == null) { return null; } - return typeEnum.of(); + return Objects.isNull(capacity) ? typeEnum.of() : typeEnum.of(capacity); } private static final int DEFAULT_CAPACITY = 1024; From 0e87fff31f1a1c9bb106330cf9b903c0c92d8c5c Mon Sep 17 00:00:00 2001 From: zjHe <34431616+zjHe@users.noreply.github.com> Date: Tue, 14 Mar 2023 10:21:00 +0800 Subject: [PATCH 04/10] feature:close and shutdown (#1103) --- .../cn/hippo4j/springboot/starter/core/DiscoveryClient.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/core/DiscoveryClient.java b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/core/DiscoveryClient.java index 0bc94ea3..92cb52e3 100644 --- a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/core/DiscoveryClient.java +++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/core/DiscoveryClient.java @@ -92,6 +92,8 @@ public class DiscoveryClient implements DisposableBean { String clientCloseUrlPath = Constants.BASE_PATH + "/client/close"; Result clientCloseResult; try { + // close scheduledExecutor + this.scheduler.shutdown(); String groupKeyIp = new StringBuilder() .append(instanceInfo.getGroupKey()) .append(Constants.GROUP_KEY_DELIMITER) @@ -126,6 +128,9 @@ public class DiscoveryClient implements DisposableBean { private boolean renew() { Result renewResult; try { + if (this.scheduler.isShutdown()) { + return false; + } InstanceInfo.InstanceRenew instanceRenew = new InstanceInfo.InstanceRenew() .setAppName(instanceInfo.getAppName()) .setInstanceId(instanceInfo.getInstanceId()) From 5e524fab44362f956d455978a0014fe00428bc17 Mon Sep 17 00:00:00 2001 From: ShengTongSun <35056992+ShengTongSun@users.noreply.github.com> Date: Tue, 14 Mar 2023 13:09:28 +0800 Subject: [PATCH 05/10] IdentifyUtil 77 lines of StringBuilder can use string + instead to simplify the code #1093 (#1104) --- .../java/cn/hippo4j/core/toolkit/IdentifyUtil.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/toolkit/IdentifyUtil.java b/hippo4j-core/src/main/java/cn/hippo4j/core/toolkit/IdentifyUtil.java index 106d5c92..2d883772 100644 --- a/hippo4j-core/src/main/java/cn/hippo4j/core/toolkit/IdentifyUtil.java +++ b/hippo4j-core/src/main/java/cn/hippo4j/core/toolkit/IdentifyUtil.java @@ -74,13 +74,11 @@ public class IdentifyUtil { ip = inetUtil.findFirstNonLoopBackHostInfo().getIpAddress(); port = environment.getProperty("server.port", "8080"); } - String identify = new StringBuilder() - .append(ip) - .append(":") - .append(port) - .append(IDENTIFY_SLICER_SYMBOL) - .append(CLIENT_IDENTIFICATION_VALUE) - .toString(); + String identify = ip + + ":" + + port + + IDENTIFY_SLICER_SYMBOL + + CLIENT_IDENTIFICATION_VALUE; IDENTIFY = identify; return identify; } From 0aa2c22bed165fdbdca907671970093b019121f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=93=E8=81=94=E9=BE=99?= <53131003+2595001965@users.noreply.github.com> Date: Tue, 14 Mar 2023 15:39:28 +0800 Subject: [PATCH 06/10] use lambda to simplify the code (#1105) --- .../support/adpter/DynamicThreadPoolAdapterChoose.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/executor/support/adpter/DynamicThreadPoolAdapterChoose.java b/hippo4j-core/src/main/java/cn/hippo4j/core/executor/support/adpter/DynamicThreadPoolAdapterChoose.java index 39a4ba73..c3169502 100644 --- a/hippo4j-core/src/main/java/cn/hippo4j/core/executor/support/adpter/DynamicThreadPoolAdapterChoose.java +++ b/hippo4j-core/src/main/java/cn/hippo4j/core/executor/support/adpter/DynamicThreadPoolAdapterChoose.java @@ -76,9 +76,7 @@ public class DynamicThreadPoolAdapterChoose { */ public static void replace(Object executor, Executor dynamicThreadPoolExecutor) { Optional dynamicThreadPoolAdapterOptional = DYNAMIC_THREAD_POOL_ADAPTERS.stream().filter(each -> each.match(executor)).findFirst(); - if (dynamicThreadPoolAdapterOptional.isPresent()) { - dynamicThreadPoolAdapterOptional.get().replace(executor, dynamicThreadPoolExecutor); - } + dynamicThreadPoolAdapterOptional.ifPresent(dynamicThreadPoolAdapter -> dynamicThreadPoolAdapter.replace(executor, dynamicThreadPoolExecutor)); } /** From 1f20678cb038bb50f0249c9044d93ac5d581d251 Mon Sep 17 00:00:00 2001 From: SquirrelChen <13654811+GM-Studio@users.noreply.github.com> Date: Wed, 15 Mar 2023 11:29:07 +0800 Subject: [PATCH 07/10] feat(ThreadPoolMonitor) (#1108) 1. the ThreadPoolMonitor use the new api instead of the deprecated api --- .../springboot/starter/monitor/ThreadPoolMonitorExecutor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/monitor/ThreadPoolMonitorExecutor.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/monitor/ThreadPoolMonitorExecutor.java index 04f2d938..7818fe42 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/monitor/ThreadPoolMonitorExecutor.java +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/monitor/ThreadPoolMonitorExecutor.java @@ -79,8 +79,8 @@ public class ThreadPoolMonitorExecutor implements ApplicationRunner, DisposableB // Execute dynamic thread pool monitoring component. collectScheduledExecutor.scheduleWithFixedDelay( this::scheduleRunnable, - properties.getInitialDelay(), - properties.getCollectInterval(), + monitor.getInitialDelay(), + monitor.getCollectInterval(), TimeUnit.MILLISECONDS); if (GlobalThreadPoolManage.getThreadPoolNum() > 0) { log.info("Dynamic thread pool: [{}]. The dynamic thread pool starts data collection and reporting.", getThreadPoolNum()); From f65dbb552101528ee5df3ae88fb14cfef824a67a Mon Sep 17 00:00:00 2001 From: zongyuanGitHub <187233878@qq.com> Date: Wed, 15 Mar 2023 11:29:15 +0800 Subject: [PATCH 08/10] delete obsolete field (#1107) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 启元 --- .../config/BootstrapConfigProperties.java | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/BootstrapConfigProperties.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/BootstrapConfigProperties.java index 57654b06..a5a435d2 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/BootstrapConfigProperties.java +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/config/BootstrapConfigProperties.java @@ -51,30 +51,6 @@ public class BootstrapConfigProperties implements BootstrapPropertiesInterface { */ private MonitorProperties monitor = new MonitorProperties(); - /*** - * Latest use {@link MonitorProperties#getEnable()} - */ - @Deprecated - private Boolean collect = Boolean.TRUE; - - /** - * Latest use {@link MonitorProperties#getCollectTypes()} - */ - @Deprecated - private String collectType; - - /** - * Latest use {@link MonitorProperties#getInitialDelay()} - */ - @Deprecated - private Long initialDelay = 10000L; - - /** - * Latest use {@link MonitorProperties#getCollectInterval()} - */ - @Deprecated - private Long collectInterval = 5000L; - /** * Config file type. */ From 72aa732688b5c4ed0d40afdb1605b2c304456582 Mon Sep 17 00:00:00 2001 From: Kevin Date: Wed, 15 Mar 2023 12:20:37 +0800 Subject: [PATCH 09/10] refactor BlockingQueueTypeEnum (#1109) --- .../support/BlockingQueueTypeEnum.java | 40 +++++++------------ 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/BlockingQueueTypeEnum.java b/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/BlockingQueueTypeEnum.java index a2f2c0e1..be4b603d 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/BlockingQueueTypeEnum.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/BlockingQueueTypeEnum.java @@ -20,18 +20,8 @@ package cn.hippo4j.common.executor.support; import cn.hippo4j.common.spi.DynamicThreadPoolServiceLoader; import lombok.Getter; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.LinkedTransferQueue; -import java.util.concurrent.PriorityBlockingQueue; -import java.util.concurrent.SynchronousQueue; +import java.util.*; +import java.util.concurrent.*; import java.util.function.Predicate; /** @@ -145,10 +135,10 @@ public enum BlockingQueueTypeEnum { }; @Getter - private Integer type; + private final Integer type; @Getter - private String name; + private final String name; /** * Create the specified implement of BlockingQueue with init capacity. @@ -175,16 +165,16 @@ public enum BlockingQueueTypeEnum { this.name = name; } - private static Map typeToEnumMap; - private static Map nameToEnumMap; + private static final Map TYPE_TO_ENUM_MAP; + private static final Map NAME_TO_ENUM_MAP; static { final BlockingQueueTypeEnum[] values = BlockingQueueTypeEnum.values(); - typeToEnumMap = new HashMap<>(values.length); - nameToEnumMap = new HashMap<>(values.length); + TYPE_TO_ENUM_MAP = new HashMap<>(values.length); + NAME_TO_ENUM_MAP = new HashMap<>(values.length); for (BlockingQueueTypeEnum value : values) { - typeToEnumMap.put(value.type, value); - nameToEnumMap.put(value.name, value); + TYPE_TO_ENUM_MAP.put(value.type, value); + NAME_TO_ENUM_MAP.put(value.name, value); } } @@ -198,7 +188,7 @@ public enum BlockingQueueTypeEnum { * @return a BlockingQueue view of the specified T */ private static BlockingQueue of(String blockingQueueName, Integer capacity) { - final BlockingQueueTypeEnum typeEnum = nameToEnumMap.get(blockingQueueName); + final BlockingQueueTypeEnum typeEnum = NAME_TO_ENUM_MAP.get(blockingQueueName); if (typeEnum == null) { return null; } @@ -215,7 +205,7 @@ public enum BlockingQueueTypeEnum { * @return a BlockingQueue view of the specified T */ private static BlockingQueue of(int type, Integer capacity) { - final BlockingQueueTypeEnum typeEnum = typeToEnumMap.get(type); + final BlockingQueueTypeEnum typeEnum = TYPE_TO_ENUM_MAP.get(type); if (typeEnum == null) { return null; } @@ -262,7 +252,7 @@ public enum BlockingQueueTypeEnum { } return customOrDefaultQueue(capacity, - (customeQueue) -> Objects.equals(customeQueue.getName(), blockingQueueName)); + (customerQueue) -> Objects.equals(customerQueue.getName(), blockingQueueName)); } /** @@ -293,7 +283,7 @@ public enum BlockingQueueTypeEnum { * @return {@link BlockingQueueTypeEnum#name BlockingQueueTypeEnum.name } or "". */ public static String getBlockingQueueNameByType(int type) { - return Optional.ofNullable(typeToEnumMap.get(type)) + return Optional.ofNullable(TYPE_TO_ENUM_MAP.get(type)) .map(value -> value.getName()) .orElse(""); } @@ -306,7 +296,7 @@ public enum BlockingQueueTypeEnum { * @return enum {@link BlockingQueueTypeEnum} */ public static BlockingQueueTypeEnum getBlockingQueueTypeEnumByName(String name) { - return Optional.ofNullable(nameToEnumMap.get(name)) + return Optional.ofNullable(NAME_TO_ENUM_MAP.get(name)) .orElse(LINKED_BLOCKING_QUEUE); } } From 275a8bfb928dd07ea482b9df393ff81212aca4b0 Mon Sep 17 00:00:00 2001 From: yanrongzhen Date: Wed, 15 Mar 2023 13:27:22 +0800 Subject: [PATCH 10/10] Bruceyan/issue#1092 (#1102) * refactor: Extension module * refactor: Update packageNames and classNames, mark ServiceLoader deprecated. * fix: remove some unused fields. * method does not override or implement a method from a supertype * fix: Modify some field names, add scoped target object filtering. --- .../common/constant/HttpMediaType.java | 2 - .../hippo4j/common/constant/HttpMethod.java | 2 - .../common/constant/HttpResponseCode.java | 2 - .../support/BlockingQueueTypeEnum.java | 13 ++- .../support/NotSupportedException.java | 17 ++++ .../support/RejectedPolicyTypeEnum.java | 8 +- .../hippo4j/common/extension/IExtension.java | 24 +++++ .../common/extension/IExtensionRequest.java | 24 +++++ .../extension/annotation/Realization.java | 35 +++++++ .../annotation/SingletonSPI.java | 3 +- .../config/ExtensionRegisterBootstrap.java | 61 ++++++++++++ .../common/extension/reducer/AllMatch.java | 61 ++++++++++++ .../common/extension/reducer/AnyMatch.java | 60 ++++++++++++ .../common/extension/reducer/FirstOf.java | 54 +++++++++++ .../common/extension/reducer/None.java | 36 +++++++ .../common/extension/reducer/Reducer.java | 53 ++++++++++ .../common/extension/reducer/Reducers.java | 77 +++++++++++++++ .../support/ExtensionAutoConfiguration.java | 31 ++++++ .../extension/support/ExtensionCallback.java | 31 ++++++ .../extension/support/ExtensionInvoker.java | 60 ++++++++++++ .../extension/support/ExtensionRegistry.java | 97 +++++++++++++++++++ .../extension/support/IExtensionRegistry.java | 29 ++++++ .../common/extension/support/ReduceType.java | 26 +++++ .../ServiceLoaderInstantiationException.java | 2 +- .../support/ServiceLoaderRegistry.java} | 12 ++- .../cn/hippo4j/common/toolkit/Assert.java | 6 ++ .../cn/hippo4j/common/toolkit/ClassUtil.java | 53 ++++++++++ .../hippo4j/common/toolkit/http/HttpUtil.java | 2 - .../toolkit/http/JdkHttpClientResponse.java | 2 - .../common/toolkit/logtracing/LogMessage.java | 2 - .../main/resources/META-INF/spring.factories | 1 + .../extension/ExtensionInvokerTest.java | 81 ++++++++++++++++ .../extension/anymatch/AnyMatchExtImplA.java | 29 ++++++ .../extension/anymatch/AnyMatchExtImplB.java | 29 ++++++ .../anymatch/IAnyMatchExtension.java | 25 +++++ .../extension/firstof/FirstOfExtImplA.java | 29 ++++++ .../extension/firstof/FirstOfExtImplB.java | 29 ++++++ .../extension/firstof/IFirstOfExtension.java | 25 +++++ .../hippo4j/common/extension/spi/IOldSpi.java | 25 +++++ .../common/extension/spi/IOldSpiImplA.java | 27 ++++++ .../DynamicThreadPoolServiceLoaderTest.java | 31 +++--- .../hippo4j/common/spi/TestInterfaceSPI.java | 4 +- .../common/spi/TestInterfaceSPIImpl.java | 4 +- .../common/spi/TestSingletonInterfaceSPI.java | 5 +- .../spi/TestSingletonInterfaceSPIImpl.java | 4 +- .../cn.hippo4j.common.extension.spi.IOldSpi | 1 + .../DynamicThreadPoolAdapterChoose.java | 6 +- .../cn/hippo4j/core/toolkit/IdentifyUtil.java | 6 +- .../monitor/ThreadPoolMonitorExecutor.java | 4 +- .../ThreadPoolAdapterController.java | 4 +- .../monitor/ReportingEventExecutor.java | 4 +- .../provider/InstanceInfoProviderFactory.java | 6 +- 52 files changed, 1203 insertions(+), 61 deletions(-) create mode 100644 hippo4j-common/src/main/java/cn/hippo4j/common/extension/IExtension.java create mode 100644 hippo4j-common/src/main/java/cn/hippo4j/common/extension/IExtensionRequest.java create mode 100644 hippo4j-common/src/main/java/cn/hippo4j/common/extension/annotation/Realization.java rename hippo4j-common/src/main/java/cn/hippo4j/common/{spi => extension}/annotation/SingletonSPI.java (94%) create mode 100644 hippo4j-common/src/main/java/cn/hippo4j/common/extension/config/ExtensionRegisterBootstrap.java create mode 100644 hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/AllMatch.java create mode 100644 hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/AnyMatch.java create mode 100644 hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/FirstOf.java create mode 100644 hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/None.java create mode 100644 hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/Reducer.java create mode 100644 hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/Reducers.java create mode 100644 hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ExtensionAutoConfiguration.java create mode 100644 hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ExtensionCallback.java create mode 100644 hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ExtensionInvoker.java create mode 100644 hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ExtensionRegistry.java create mode 100644 hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/IExtensionRegistry.java create mode 100644 hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ReduceType.java rename hippo4j-common/src/main/java/cn/hippo4j/common/{spi => extension/support}/ServiceLoaderInstantiationException.java (96%) rename hippo4j-common/src/main/java/cn/hippo4j/common/{spi/DynamicThreadPoolServiceLoader.java => extension/support/ServiceLoaderRegistry.java} (91%) create mode 100644 hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/ClassUtil.java create mode 100644 hippo4j-common/src/main/resources/META-INF/spring.factories create mode 100644 hippo4j-common/src/test/java/cn/hippo4j/common/extension/ExtensionInvokerTest.java create mode 100644 hippo4j-common/src/test/java/cn/hippo4j/common/extension/anymatch/AnyMatchExtImplA.java create mode 100644 hippo4j-common/src/test/java/cn/hippo4j/common/extension/anymatch/AnyMatchExtImplB.java create mode 100644 hippo4j-common/src/test/java/cn/hippo4j/common/extension/anymatch/IAnyMatchExtension.java create mode 100644 hippo4j-common/src/test/java/cn/hippo4j/common/extension/firstof/FirstOfExtImplA.java create mode 100644 hippo4j-common/src/test/java/cn/hippo4j/common/extension/firstof/FirstOfExtImplB.java create mode 100644 hippo4j-common/src/test/java/cn/hippo4j/common/extension/firstof/IFirstOfExtension.java create mode 100644 hippo4j-common/src/test/java/cn/hippo4j/common/extension/spi/IOldSpi.java create mode 100644 hippo4j-common/src/test/java/cn/hippo4j/common/extension/spi/IOldSpiImplA.java create mode 100644 hippo4j-common/src/test/resources/META-INF/services/cn.hippo4j.common.extension.spi.IOldSpi diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/constant/HttpMediaType.java b/hippo4j-common/src/main/java/cn/hippo4j/common/constant/HttpMediaType.java index 58caa1d8..fe45a4be 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/constant/HttpMediaType.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/constant/HttpMediaType.java @@ -21,8 +21,6 @@ import cn.hippo4j.common.toolkit.StringUtil; /** * Http media type. - * - * @author Rongzhen Yan */ public final class HttpMediaType { diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/constant/HttpMethod.java b/hippo4j-common/src/main/java/cn/hippo4j/common/constant/HttpMethod.java index fde14dfe..01bc3734 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/constant/HttpMethod.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/constant/HttpMethod.java @@ -19,8 +19,6 @@ package cn.hippo4j.common.constant; /** * Http method constants. - * - * @author Rongzhen Yan */ public class HttpMethod { diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/constant/HttpResponseCode.java b/hippo4j-common/src/main/java/cn/hippo4j/common/constant/HttpResponseCode.java index 72e9df94..e5117937 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/constant/HttpResponseCode.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/constant/HttpResponseCode.java @@ -19,8 +19,6 @@ package cn.hippo4j.common.constant; /** * Http response code. - * - * @author Rongzhen Yan */ public class HttpResponseCode { diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/BlockingQueueTypeEnum.java b/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/BlockingQueueTypeEnum.java index be4b603d..a1a77720 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/BlockingQueueTypeEnum.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/BlockingQueueTypeEnum.java @@ -17,7 +17,7 @@ package cn.hippo4j.common.executor.support; -import cn.hippo4j.common.spi.DynamicThreadPoolServiceLoader; +import cn.hippo4j.common.extension.support.ServiceLoaderRegistry; import lombok.Getter; import java.util.*; @@ -33,6 +33,7 @@ public enum BlockingQueueTypeEnum { * {@link java.util.concurrent.ArrayBlockingQueue} */ ARRAY_BLOCKING_QUEUE(1, "ArrayBlockingQueue") { + @Override BlockingQueue of(Integer capacity) { return new ArrayBlockingQueue<>(capacity); @@ -48,6 +49,7 @@ public enum BlockingQueueTypeEnum { * {@link java.util.concurrent.LinkedBlockingQueue} */ LINKED_BLOCKING_QUEUE(2, "LinkedBlockingQueue") { + @Override BlockingQueue of(Integer capacity) { return new LinkedBlockingQueue<>(capacity); @@ -63,6 +65,7 @@ public enum BlockingQueueTypeEnum { * {@link java.util.concurrent.LinkedBlockingDeque} */ LINKED_BLOCKING_DEQUE(3, "LinkedBlockingDeque") { + @Override BlockingQueue of(Integer capacity) { return new LinkedBlockingDeque<>(capacity); @@ -78,6 +81,7 @@ public enum BlockingQueueTypeEnum { * {@link java.util.concurrent.SynchronousQueue} */ SYNCHRONOUS_QUEUE(4, "SynchronousQueue") { + @Override BlockingQueue of(Integer capacity) { return new SynchronousQueue<>(); @@ -93,6 +97,7 @@ public enum BlockingQueueTypeEnum { * {@link java.util.concurrent.LinkedTransferQueue} */ LINKED_TRANSFER_QUEUE(5, "LinkedTransferQueue") { + @Override BlockingQueue of(Integer capacity) { return new LinkedTransferQueue<>(); @@ -108,6 +113,7 @@ public enum BlockingQueueTypeEnum { * {@link java.util.concurrent.PriorityBlockingQueue} */ PRIORITY_BLOCKING_QUEUE(6, "PriorityBlockingQueue") { + @Override BlockingQueue of(Integer capacity) { return new PriorityBlockingQueue<>(capacity); @@ -123,6 +129,7 @@ public enum BlockingQueueTypeEnum { * {@link ResizableCapacityLinkedBlockingQueue} */ RESIZABLE_LINKED_BLOCKING_QUEUE(9, "ResizableCapacityLinkedBlockingQueue") { + @Override BlockingQueue of(Integer capacity) { return new ResizableCapacityLinkedBlockingQueue<>(capacity); @@ -215,11 +222,11 @@ public enum BlockingQueueTypeEnum { private static final int DEFAULT_CAPACITY = 1024; static { - DynamicThreadPoolServiceLoader.register(CustomBlockingQueue.class); + ServiceLoaderRegistry.register(CustomBlockingQueue.class); } private static BlockingQueue customOrDefaultQueue(Integer capacity, Predicate predicate) { - Collection customBlockingQueues = DynamicThreadPoolServiceLoader + Collection customBlockingQueues = ServiceLoaderRegistry .getSingletonServiceInstances(CustomBlockingQueue.class); return customBlockingQueues.stream() diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/NotSupportedException.java b/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/NotSupportedException.java index 9a9e8105..f3996a05 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/NotSupportedException.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/NotSupportedException.java @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package cn.hippo4j.common.executor.support; import cn.hippo4j.common.web.exception.AbstractException; diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/RejectedPolicyTypeEnum.java b/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/RejectedPolicyTypeEnum.java index eed9b2ae..98272da1 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/RejectedPolicyTypeEnum.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/executor/support/RejectedPolicyTypeEnum.java @@ -17,7 +17,7 @@ package cn.hippo4j.common.executor.support; -import cn.hippo4j.common.spi.DynamicThreadPoolServiceLoader; +import cn.hippo4j.common.extension.support.ServiceLoaderRegistry; import lombok.Getter; import java.util.Collection; @@ -59,7 +59,7 @@ public enum RejectedPolicyTypeEnum { } static { - DynamicThreadPoolServiceLoader.register(CustomRejectedExecutionHandler.class); + ServiceLoaderRegistry.register(CustomRejectedExecutionHandler.class); } public static RejectedExecutionHandler createPolicy(String name) { @@ -70,7 +70,7 @@ public enum RejectedPolicyTypeEnum { if (rejectedTypeEnum != null) { return rejectedTypeEnum.rejectedHandler; } - Collection customRejectedExecutionHandlers = DynamicThreadPoolServiceLoader + Collection customRejectedExecutionHandlers = ServiceLoaderRegistry .getSingletonServiceInstances(CustomRejectedExecutionHandler.class); Optional customRejected = customRejectedExecutionHandlers.stream() .filter(each -> Objects.equals(name, each.getName())) @@ -85,7 +85,7 @@ public enum RejectedPolicyTypeEnum { .map(each -> each.rejectedHandler) .findFirst(); RejectedExecutionHandler resultRejected = rejectedTypeEnum.orElseGet(() -> { - Collection customRejectedExecutionHandlers = DynamicThreadPoolServiceLoader + Collection customRejectedExecutionHandlers = ServiceLoaderRegistry .getSingletonServiceInstances(CustomRejectedExecutionHandler.class); Optional customRejected = customRejectedExecutionHandlers.stream() .filter(each -> Objects.equals(type, each.getType())) diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/extension/IExtension.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/IExtension.java new file mode 100644 index 00000000..cae01c93 --- /dev/null +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/IExtension.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension; + +/** + * Top level interface of extension-point. + */ +public interface IExtension { +} diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/extension/IExtensionRequest.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/IExtensionRequest.java new file mode 100644 index 00000000..1ad5e14e --- /dev/null +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/IExtensionRequest.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension; + +/** + * Top level interface of extension-point request obj. + */ +public interface IExtensionRequest { +} diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/extension/annotation/Realization.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/annotation/Realization.java new file mode 100644 index 00000000..d0981ac6 --- /dev/null +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/annotation/Realization.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.annotation; + +import org.springframework.stereotype.Component; + +import java.lang.annotation.*; + +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +@Component +public @interface Realization { + + String code() default "DEFAULT_CODE"; + + String name() default "DEFAULT_NAME"; + + int order() default 0; +} diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/spi/annotation/SingletonSPI.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/annotation/SingletonSPI.java similarity index 94% rename from hippo4j-common/src/main/java/cn/hippo4j/common/spi/annotation/SingletonSPI.java rename to hippo4j-common/src/main/java/cn/hippo4j/common/extension/annotation/SingletonSPI.java index 1b04524c..7f1620ba 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/spi/annotation/SingletonSPI.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/annotation/SingletonSPI.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package cn.hippo4j.common.spi.annotation; +package cn.hippo4j.common.extension.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -27,5 +27,6 @@ import java.lang.annotation.Target; */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) +@Deprecated public @interface SingletonSPI { } diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/extension/config/ExtensionRegisterBootstrap.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/config/ExtensionRegisterBootstrap.java new file mode 100644 index 00000000..0dbae207 --- /dev/null +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/config/ExtensionRegisterBootstrap.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.config; + +import cn.hippo4j.common.extension.IExtension; +import cn.hippo4j.common.extension.annotation.Realization; +import cn.hippo4j.common.extension.support.ExtensionRegistry; +import cn.hippo4j.common.toolkit.ClassUtil; +import org.springframework.aop.scope.ScopedProxyUtils; +import org.springframework.beans.BeansException; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Extension register bootstrap + */ +public class ExtensionRegisterBootstrap implements ApplicationContextAware, ApplicationRunner { + + private ExtensionRegistry registry = ExtensionRegistry.getInstance(); + + private ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + @Override + public void run(ApplicationArguments args) throws Exception { + applicationContext.getBeansWithAnnotation(Realization.class) + .entrySet().stream() + .filter(entry -> !filterClass(entry.getKey(), entry.getValue())) + .forEach(entry -> registry.register((IExtension) entry.getValue())); + } + + private boolean filterClass(String beanName, Object bean) { + return bean.getClass().isAssignableFrom(IExtension.class) || + ScopedProxyUtils.isScopedTarget(beanName) || + !(bean instanceof IExtension); + } +} diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/AllMatch.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/AllMatch.java new file mode 100644 index 00000000..f1f37e7f --- /dev/null +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/AllMatch.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.reducer; + +import cn.hippo4j.common.extension.IExtension; +import cn.hippo4j.common.extension.support.ReduceType; +import cn.hippo4j.common.toolkit.CollectionUtil; +import lombok.Getter; +import lombok.NonNull; + +import java.util.Objects; +import java.util.function.Predicate; + +/** + * All-match extension reduce policy. + */ +public class AllMatch extends Reducer { + + @Getter + private final Predicate predicate; + + public AllMatch(@NonNull Predicate predicate) { + Objects.requireNonNull(predicate); + this.predicate = predicate; + } + + @Override + public Boolean reduce() { + if (CollectionUtil.isEmpty(realizations)) { + return false; + } else { + for (IExtension realization : realizations) { + if (!predicate.test(getCallback().apply(realization))) { + return false; + } + } + } + return true; + } + + @Override + public ReduceType reducerType() { + return ReduceType.ALL; + } + +} diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/AnyMatch.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/AnyMatch.java new file mode 100644 index 00000000..66305b00 --- /dev/null +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/AnyMatch.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.reducer; + +import cn.hippo4j.common.extension.IExtension; +import cn.hippo4j.common.extension.support.ReduceType; +import cn.hippo4j.common.toolkit.CollectionUtil; +import lombok.Getter; +import lombok.NonNull; + +import java.util.Objects; +import java.util.function.Predicate; + +/** + * Any-match extension reduce policy. + */ +public class AnyMatch extends Reducer { + + @Getter + private final Predicate predicate; + + public AnyMatch(@NonNull Predicate predicate) { + Objects.requireNonNull(predicate); + this.predicate = predicate; + } + + @Override + public Boolean reduce() { + if (CollectionUtil.isEmpty(realizations)) { + return false; + } + for (IExtension extension : realizations) { + if (predicate.test(getCallback().apply(extension))) { + return true; + } + } + return false; + } + + @Override + public ReduceType reducerType() { + return ReduceType.FIRST; + } + +} diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/FirstOf.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/FirstOf.java new file mode 100644 index 00000000..c7aa6981 --- /dev/null +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/FirstOf.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.reducer; + +import cn.hippo4j.common.extension.IExtension; +import cn.hippo4j.common.extension.support.ReduceType; +import lombok.NonNull; + +import java.util.Objects; +import java.util.function.Predicate; + +/** + * First-of extension reduce policy. + */ +public class FirstOf extends Reducer { + + private Predicate predicate; + + public FirstOf(@NonNull Predicate predicate) { + Objects.requireNonNull(predicate); + this.predicate = predicate; + } + + @Override + public ReduceType reducerType() { + return ReduceType.FIRST; + } + + @Override + public Element reduce() { + for (IExtension extension : realizations) { + Element element = getCallback().apply(extension); + if (null == predicate || predicate.test(element)) { + return element; + } + } + return null; + } +} diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/None.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/None.java new file mode 100644 index 00000000..3280a832 --- /dev/null +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/None.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.reducer; + +import cn.hippo4j.common.extension.support.ReduceType; + +import java.util.List; +import java.util.stream.Collectors; + +public class None extends Reducer> { + + @Override + public ReduceType reducerType() { + return ReduceType.NONE; + } + + @Override + public List reduce() { + return realizations.stream().map(getCallback()).collect(Collectors.toList()); + } +} diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/Reducer.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/Reducer.java new file mode 100644 index 00000000..079625d2 --- /dev/null +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/Reducer.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.reducer; + +import cn.hippo4j.common.extension.IExtension; +import cn.hippo4j.common.extension.IExtensionRequest; +import cn.hippo4j.common.extension.support.ExtensionCallback; +import cn.hippo4j.common.extension.support.ReduceType; +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +public abstract class Reducer { + + @Getter + private Result result; + + @Setter + protected IExtensionRequest request; + + @Setter + protected List realizations; + + @Setter + @Getter + private ExtensionCallback callback; + + public abstract Result reduce(); + + public abstract ReduceType reducerType(); + + public String reduceName() { + return this.getClass().getSimpleName(); + } + +} diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/Reducers.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/Reducers.java new file mode 100644 index 00000000..b3ea7186 --- /dev/null +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/reducer/Reducers.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.reducer; + +import lombok.NonNull; + +import java.util.List; +import java.util.Objects; +import java.util.function.Predicate; + +@SuppressWarnings("all") +public class Reducers { + + /** + * No reduce policy needed. + * + * @return None type reducer + */ + public static Reducer> none() { + return new None<>(); + } + + /** + * Build a FirstOf Reducer. + * + * @param predicate the condition predicate. + * @return FirstOf Policy Reducer. + */ + public static Reducer firstOf(@NonNull Predicate predicate) { + return new FirstOf<>(predicate); + } + + /** + * Build a FirstOf Not-null Reducer. + * + * @return FirstOf Not-null Policy Reducer. + */ + public static Reducer firstOfNotNull() { + return new FirstOf<>(Objects::nonNull); + } + + /** + * Build a AnyMatch Reducer. + * + * @param predicate the condition predicate. + * @return AnyMatch Policy Reducer. + */ + public static Reducer anyMatch(Predicate predicate) { + return new AnyMatch<>(predicate); + } + + /** + * Build a AllMatch Reducer + * + * @param predicate the condition predicate. + * @return AllMatch Policy Reducer. + */ + public static Reducer allMatch(@NonNull Predicate predicate) { + return new AllMatch<>(predicate); + } + +} diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ExtensionAutoConfiguration.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ExtensionAutoConfiguration.java new file mode 100644 index 00000000..78736976 --- /dev/null +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ExtensionAutoConfiguration.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.common.extension.support; + +import cn.hippo4j.common.extension.config.ExtensionRegisterBootstrap; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ExtensionAutoConfiguration { + + @Bean + public ExtensionRegisterBootstrap bootstrap() { + return new ExtensionRegisterBootstrap(); + } +} diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ExtensionCallback.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ExtensionCallback.java new file mode 100644 index 00000000..5c71fcb5 --- /dev/null +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ExtensionCallback.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.common.extension.support; + +import java.util.function.Function; + +/** + * Callback function of extension invocation. + * @param + * @param + */ +@FunctionalInterface +public interface ExtensionCallback extends Function { + + R apply(T extension); +} diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ExtensionInvoker.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ExtensionInvoker.java new file mode 100644 index 00000000..0c748680 --- /dev/null +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ExtensionInvoker.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.support; + +import cn.hippo4j.common.extension.IExtension; +import cn.hippo4j.common.extension.reducer.Reducer; +import cn.hippo4j.common.extension.reducer.Reducers; +import cn.hippo4j.common.toolkit.Assert; +import cn.hippo4j.common.toolkit.CollectionUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * Extension point invoker. + * + * Providing extension-point invocation ability that supports the use of reducing policy. + */ +public class ExtensionInvoker { + + private static final ExtensionRegistry registry = ExtensionRegistry.getInstance(); + + public static List reduceExecute(Class targetClz, + ExtensionCallback callback) { + return reduceExecute(targetClz, callback, Reducers.none()); + } + + @SuppressWarnings("unchecked") + public static R reduceExecute(Class targetClz, + ExtensionCallback callback, + Reducer reducer) { + Assert.isTrue(IExtension.class.isAssignableFrom(targetClz), + "can not execute extension point. please implement base extension interface(" + IExtension.class.getName() + ") first."); + + List realizations = registry.find(targetClz); + if (CollectionUtil.isEmpty(realizations)) { + realizations = new ArrayList<>(ServiceLoaderRegistry.getSingletonServiceInstances(targetClz)); + } + Assert.notEmpty(realizations, "can not find any extension realizations with interface: " + targetClz.getName()); + + reducer.setRealizations(realizations); + reducer.setCallback((ExtensionCallback) callback); + return reducer.reduce(); + } +} diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ExtensionRegistry.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ExtensionRegistry.java new file mode 100644 index 00000000..b835446c --- /dev/null +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ExtensionRegistry.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.support; + +import cn.hippo4j.common.extension.IExtension; +import cn.hippo4j.common.extension.annotation.Realization; +import cn.hippo4j.common.toolkit.CollectionUtil; +import cn.hippo4j.common.toolkit.logtracing.LogMessage; +import lombok.extern.slf4j.Slf4j; +import org.springframework.aop.support.AopUtils; +import org.springframework.util.ClassUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Extension registry + */ +@Slf4j +public class ExtensionRegistry implements IExtensionRegistry { + + private final Map, List> registry = new ConcurrentHashMap<>(); + + private static ExtensionRegistry INSTANCE; + + private ExtensionRegistry() { + } + + public static ExtensionRegistry getInstance() { + if (null == INSTANCE) { + synchronized (ExtensionRegistry.class) { + if (null == INSTANCE) { + INSTANCE = new ExtensionRegistry(); + } + } + } + return INSTANCE; + } + + @SuppressWarnings("unchecked") + @Override + public void register(IExtension realization) { + + Class implClass = realization.getClass(); + if (AopUtils.isAopProxy(implClass)) { + implClass = ClassUtils.getUserClass(implClass); + } + Realization annotation = implClass.getAnnotation(Realization.class); + + Class[] interfaces = implClass.getInterfaces(); + + for (Class intf : interfaces) { + if (IExtension.class.isAssignableFrom(intf)) { + this.register((Class) intf, realization); + } + } + } + + private void register(Class extension, IExtension realization) { + if (!registry.containsKey(extension) || CollectionUtil.isEmpty(registry.get(extension))) { + List realizations = new ArrayList<>(); + realizations.add(realization); + registry.put(extension, realizations); + } else { + if (registry.get(extension).contains(realization)) { + log.warn(LogMessage.getInstance() + .kv("realizationClassName", realization.getClass().getName()) + .msg("Extension realization already registered, skip.")); + } + List realizations = registry.get(extension); + realizations.add(realization); + registry.put(extension, realizations); + } + } + + @Override + public List find(Class extension) { + return registry.get(extension); + } +} diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/IExtensionRegistry.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/IExtensionRegistry.java new file mode 100644 index 00000000..d1ffa3e2 --- /dev/null +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/IExtensionRegistry.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.support; + +import cn.hippo4j.common.extension.IExtension; + +import java.util.List; + +public interface IExtensionRegistry { + + void register(IExtension realization); + + List find(Class extension); +} diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ReduceType.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ReduceType.java new file mode 100644 index 00000000..7a4fe9e4 --- /dev/null +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ReduceType.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.support; + +public enum ReduceType { + + NONE, + ALL, + FIRST, + UNKNOWN +} diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/spi/ServiceLoaderInstantiationException.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ServiceLoaderInstantiationException.java similarity index 96% rename from hippo4j-common/src/main/java/cn/hippo4j/common/spi/ServiceLoaderInstantiationException.java rename to hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ServiceLoaderInstantiationException.java index 496d44dd..239817d1 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/spi/ServiceLoaderInstantiationException.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ServiceLoaderInstantiationException.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package cn.hippo4j.common.spi; +package cn.hippo4j.common.extension.support; /** * Service loader instantiation exception. diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/spi/DynamicThreadPoolServiceLoader.java b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ServiceLoaderRegistry.java similarity index 91% rename from hippo4j-common/src/main/java/cn/hippo4j/common/spi/DynamicThreadPoolServiceLoader.java rename to hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ServiceLoaderRegistry.java index cd96e4a8..493dd489 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/spi/DynamicThreadPoolServiceLoader.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/extension/support/ServiceLoaderRegistry.java @@ -15,9 +15,10 @@ * limitations under the License. */ -package cn.hippo4j.common.spi; +package cn.hippo4j.common.extension.support; -import cn.hippo4j.common.spi.annotation.SingletonSPI; +import cn.hippo4j.common.extension.annotation.SingletonSPI; +import cn.hippo4j.common.extension.support.ServiceLoaderInstantiationException; import java.lang.reflect.InvocationTargetException; import java.util.Collection; @@ -29,9 +30,10 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; /** - * Dynamic thread-pool service loader. + * Dynamic thread-pool SPI service loader. */ -public class DynamicThreadPoolServiceLoader { +@Deprecated +public class ServiceLoaderRegistry { /** * safe container。 @@ -40,7 +42,7 @@ public class DynamicThreadPoolServiceLoader { */ private static final Map, Collection> SERVICES = new ConcurrentHashMap<>(); - private DynamicThreadPoolServiceLoader() { + private ServiceLoaderRegistry() { } /** diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/Assert.java b/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/Assert.java index 327152a0..3dee268f 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/Assert.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/Assert.java @@ -38,6 +38,12 @@ public class Assert { isTrue(expression, "[Assertion failed] - this expression must be true"); } + public static void isEmpty(Collection collection, String message) { + if (!CollectionUtil.isEmpty(collection)) { + throw new IllegalArgumentException(message); + } + } + public static void isNull(Object object, String message) { if (object != null) { throw new IllegalArgumentException(message); diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/ClassUtil.java b/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/ClassUtil.java new file mode 100644 index 00000000..94950732 --- /dev/null +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/ClassUtil.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.toolkit; + +/** + * Class Util. + */ +public class ClassUtil { + + /** + * get class loader + * + * @param clazz + * @return class loader + */ + public static ClassLoader getClassLoader(Class clazz) { + ClassLoader cl = null; + try { + cl = Thread.currentThread().getContextClassLoader(); + } catch (Throwable ex) { + // Cannot access thread context ClassLoader - falling back to system class loader... + } + if (cl == null) { + // No thread context class loader -> use class loader of this class. + cl = clazz.getClassLoader(); + if (cl == null) { + // getClassLoader() returning null indicates the bootstrap ClassLoader + try { + cl = ClassLoader.getSystemClassLoader(); + } catch (Throwable ex) { + // Cannot access system ClassLoader - oh well, maybe the caller can live with null... + } + } + } + + return cl; + } +} diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/http/HttpUtil.java b/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/http/HttpUtil.java index 1aaae2b9..138b6076 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/http/HttpUtil.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/http/HttpUtil.java @@ -43,8 +43,6 @@ import static cn.hippo4j.common.constant.HttpHeaderConstants.CONTENT_LENGTH; /** * Http request utilities. - * - * @author Rongzhen Yan */ @Slf4j @NoArgsConstructor(access = AccessLevel.PRIVATE) diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/http/JdkHttpClientResponse.java b/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/http/JdkHttpClientResponse.java index 683b6191..c6671aaa 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/http/JdkHttpClientResponse.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/http/JdkHttpClientResponse.java @@ -30,8 +30,6 @@ import java.util.Map; /** * Represents a client-side HTTP response with JDK implementation - * - * @author Rongzhen Yan */ public class JdkHttpClientResponse implements HttpClientResponse { diff --git a/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/logtracing/LogMessage.java b/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/logtracing/LogMessage.java index 47ef1090..b961a4b2 100644 --- a/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/logtracing/LogMessage.java +++ b/hippo4j-common/src/main/java/cn/hippo4j/common/toolkit/logtracing/LogMessage.java @@ -28,8 +28,6 @@ import java.util.concurrent.ConcurrentHashMap; /** * Log message. - * - * @author Rongzhen Yan */ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class LogMessage { diff --git a/hippo4j-common/src/main/resources/META-INF/spring.factories b/hippo4j-common/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..520aa9cd --- /dev/null +++ b/hippo4j-common/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.hippo4j.common.extension.support.ExtensionAutoConfiguration \ No newline at end of file diff --git a/hippo4j-common/src/test/java/cn/hippo4j/common/extension/ExtensionInvokerTest.java b/hippo4j-common/src/test/java/cn/hippo4j/common/extension/ExtensionInvokerTest.java new file mode 100644 index 00000000..343bb745 --- /dev/null +++ b/hippo4j-common/src/test/java/cn/hippo4j/common/extension/ExtensionInvokerTest.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension; + +import cn.hippo4j.common.extension.anymatch.AnyMatchExtImplA; +import cn.hippo4j.common.extension.anymatch.AnyMatchExtImplB; +import cn.hippo4j.common.extension.anymatch.IAnyMatchExtension; +import cn.hippo4j.common.extension.firstof.FirstOfExtImplA; +import cn.hippo4j.common.extension.firstof.FirstOfExtImplB; +import cn.hippo4j.common.extension.firstof.IFirstOfExtension; +import cn.hippo4j.common.extension.reducer.Reducers; +import cn.hippo4j.common.extension.spi.IOldSpi; +import cn.hippo4j.common.extension.support.ExtensionInvoker; +import cn.hippo4j.common.extension.support.ExtensionRegistry; +import cn.hippo4j.common.extension.support.ServiceLoaderRegistry; +import org.assertj.core.util.Lists; +import org.junit.Before; +import org.junit.Test; + +import java.util.List; +import java.util.Objects; + +import static org.junit.Assert.*; + +public class ExtensionInvokerTest { + + @Before + public void before() { + ExtensionRegistry.getInstance().register(new FirstOfExtImplA()); + ExtensionRegistry.getInstance().register(new FirstOfExtImplB()); + ExtensionRegistry.getInstance().register(new AnyMatchExtImplA()); + ExtensionRegistry.getInstance().register(new AnyMatchExtImplB()); + + ServiceLoaderRegistry.register(IOldSpi.class); + } + @Test + public void test() { + + Integer arg = 20; + // first-of + Integer res1 = ExtensionInvoker.reduceExecute(IFirstOfExtension.class, (ext) -> ext.foo(arg), + Reducers.firstOfNotNull()); + assertEquals(arg, res1); + + // any-match + Boolean res2 = ExtensionInvoker.reduceExecute(IAnyMatchExtension.class, (ext) -> ext.foo(arg), + Reducers.anyMatch(Objects::nonNull)); + assertTrue(res2); + + // none + List res3 = ExtensionInvoker.reduceExecute(IFirstOfExtension.class, (ext) -> ext.foo(arg)); + assertArrayEquals(res3.toArray(new Integer[0]), Lists.newArrayList(null, arg).toArray()); + + // all-match + Boolean res4 = ExtensionInvoker.reduceExecute(IAnyMatchExtension.class, (ext) -> ext.foo(arg), + Reducers.allMatch(Objects::nonNull)); + assertTrue(res4); + + } + + @Test + public void test_spi_old() { + Boolean res1 = ExtensionInvoker.reduceExecute(IOldSpi.class, IOldSpi::foo, Reducers.firstOfNotNull()); + assertTrue(res1); + } +} diff --git a/hippo4j-common/src/test/java/cn/hippo4j/common/extension/anymatch/AnyMatchExtImplA.java b/hippo4j-common/src/test/java/cn/hippo4j/common/extension/anymatch/AnyMatchExtImplA.java new file mode 100644 index 00000000..75829c75 --- /dev/null +++ b/hippo4j-common/src/test/java/cn/hippo4j/common/extension/anymatch/AnyMatchExtImplA.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.anymatch; + +import cn.hippo4j.common.extension.annotation.Realization; + +@Realization +public class AnyMatchExtImplA implements IAnyMatchExtension { + + @Override + public Integer foo(Integer arg) { + return arg > 0 ? arg : null; + } +} diff --git a/hippo4j-common/src/test/java/cn/hippo4j/common/extension/anymatch/AnyMatchExtImplB.java b/hippo4j-common/src/test/java/cn/hippo4j/common/extension/anymatch/AnyMatchExtImplB.java new file mode 100644 index 00000000..8aef4d5d --- /dev/null +++ b/hippo4j-common/src/test/java/cn/hippo4j/common/extension/anymatch/AnyMatchExtImplB.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.anymatch; + +import cn.hippo4j.common.extension.annotation.Realization; + +@Realization +public class AnyMatchExtImplB implements IAnyMatchExtension { + + @Override + public Integer foo(Integer arg) { + return arg > 0 ? arg : null; + } +} diff --git a/hippo4j-common/src/test/java/cn/hippo4j/common/extension/anymatch/IAnyMatchExtension.java b/hippo4j-common/src/test/java/cn/hippo4j/common/extension/anymatch/IAnyMatchExtension.java new file mode 100644 index 00000000..94d9adec --- /dev/null +++ b/hippo4j-common/src/test/java/cn/hippo4j/common/extension/anymatch/IAnyMatchExtension.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.anymatch; + +import cn.hippo4j.common.extension.IExtension; + +public interface IAnyMatchExtension extends IExtension { + + Integer foo(Integer arg); +} diff --git a/hippo4j-common/src/test/java/cn/hippo4j/common/extension/firstof/FirstOfExtImplA.java b/hippo4j-common/src/test/java/cn/hippo4j/common/extension/firstof/FirstOfExtImplA.java new file mode 100644 index 00000000..b5a17c87 --- /dev/null +++ b/hippo4j-common/src/test/java/cn/hippo4j/common/extension/firstof/FirstOfExtImplA.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.firstof; + +import cn.hippo4j.common.extension.annotation.Realization; + +@Realization +public class FirstOfExtImplA implements IFirstOfExtension { + + @Override + public Integer foo(Integer arg) { + return null; + } +} diff --git a/hippo4j-common/src/test/java/cn/hippo4j/common/extension/firstof/FirstOfExtImplB.java b/hippo4j-common/src/test/java/cn/hippo4j/common/extension/firstof/FirstOfExtImplB.java new file mode 100644 index 00000000..7128541a --- /dev/null +++ b/hippo4j-common/src/test/java/cn/hippo4j/common/extension/firstof/FirstOfExtImplB.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.firstof; + +import cn.hippo4j.common.extension.annotation.Realization; + +@Realization +public class FirstOfExtImplB implements IFirstOfExtension { + + @Override + public Integer foo(Integer arg) { + return arg; + } +} diff --git a/hippo4j-common/src/test/java/cn/hippo4j/common/extension/firstof/IFirstOfExtension.java b/hippo4j-common/src/test/java/cn/hippo4j/common/extension/firstof/IFirstOfExtension.java new file mode 100644 index 00000000..f7c8c333 --- /dev/null +++ b/hippo4j-common/src/test/java/cn/hippo4j/common/extension/firstof/IFirstOfExtension.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.firstof; + +import cn.hippo4j.common.extension.IExtension; + +public interface IFirstOfExtension extends IExtension { + + Integer foo(Integer arg); +} diff --git a/hippo4j-common/src/test/java/cn/hippo4j/common/extension/spi/IOldSpi.java b/hippo4j-common/src/test/java/cn/hippo4j/common/extension/spi/IOldSpi.java new file mode 100644 index 00000000..7391d6f1 --- /dev/null +++ b/hippo4j-common/src/test/java/cn/hippo4j/common/extension/spi/IOldSpi.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.spi; + +import cn.hippo4j.common.extension.IExtension; + +public interface IOldSpi extends IExtension { + + Boolean foo(); +} diff --git a/hippo4j-common/src/test/java/cn/hippo4j/common/extension/spi/IOldSpiImplA.java b/hippo4j-common/src/test/java/cn/hippo4j/common/extension/spi/IOldSpiImplA.java new file mode 100644 index 00000000..d161b024 --- /dev/null +++ b/hippo4j-common/src/test/java/cn/hippo4j/common/extension/spi/IOldSpiImplA.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hippo4j.common.extension.spi; + +public class IOldSpiImplA implements IOldSpi { + + @Override + public Boolean foo() { + System.out.println(this.getClass().getName()); + return true; + } +} diff --git a/hippo4j-common/src/test/java/cn/hippo4j/common/spi/DynamicThreadPoolServiceLoaderTest.java b/hippo4j-common/src/test/java/cn/hippo4j/common/spi/DynamicThreadPoolServiceLoaderTest.java index 0e8e7fba..ddd3f317 100644 --- a/hippo4j-common/src/test/java/cn/hippo4j/common/spi/DynamicThreadPoolServiceLoaderTest.java +++ b/hippo4j-common/src/test/java/cn/hippo4j/common/spi/DynamicThreadPoolServiceLoaderTest.java @@ -19,6 +19,7 @@ package cn.hippo4j.common.spi; import java.util.Collection; +import cn.hippo4j.common.extension.support.ServiceLoaderRegistry; import org.junit.Test; import static org.hamcrest.MatcherAssert.assertThat; @@ -28,46 +29,46 @@ import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertTrue; /** - * test {@link DynamicThreadPoolServiceLoader} + * test {@link ServiceLoaderRegistry} */ public final class DynamicThreadPoolServiceLoaderTest { @Test public void assertRegister() { - DynamicThreadPoolServiceLoader.register(Collection.class); - Collection collections = DynamicThreadPoolServiceLoader.getSingletonServiceInstances(Collection.class); + ServiceLoaderRegistry.register(Collection.class); + Collection collections = ServiceLoaderRegistry.getSingletonServiceInstances(Collection.class); assertTrue(collections.isEmpty()); } @Test public void assertGetSingletonServiceInstances() { - DynamicThreadPoolServiceLoader.register(TestSingletonInterfaceSPI.class); - Collection instances = DynamicThreadPoolServiceLoader.getSingletonServiceInstances(TestSingletonInterfaceSPI.class); + ServiceLoaderRegistry.register(TestSingletonInterfaceSPI.class); + Collection instances = ServiceLoaderRegistry.getSingletonServiceInstances(TestSingletonInterfaceSPI.class); assertThat(instances.size(), equalTo(1)); - assertThat(instances.iterator().next(), is(DynamicThreadPoolServiceLoader.getSingletonServiceInstances(TestSingletonInterfaceSPI.class).iterator().next())); + assertThat(instances.iterator().next(), is(ServiceLoaderRegistry.getSingletonServiceInstances(TestSingletonInterfaceSPI.class).iterator().next())); } @Test public void assertNewServiceInstances() { - DynamicThreadPoolServiceLoader.register(TestSingletonInterfaceSPI.class); - Collection instances = DynamicThreadPoolServiceLoader.newServiceInstances(TestSingletonInterfaceSPI.class); + ServiceLoaderRegistry.register(TestSingletonInterfaceSPI.class); + Collection instances = ServiceLoaderRegistry.newServiceInstances(TestSingletonInterfaceSPI.class); assertThat(instances.size(), equalTo(1)); - assertThat(instances.iterator().next(), not(DynamicThreadPoolServiceLoader.getSingletonServiceInstances(TestSingletonInterfaceSPI.class).iterator().next())); + assertThat(instances.iterator().next(), not(ServiceLoaderRegistry.getSingletonServiceInstances(TestSingletonInterfaceSPI.class).iterator().next())); } @Test public void assertGetServiceInstancesWhenIsSingleton() { - DynamicThreadPoolServiceLoader.register(TestSingletonInterfaceSPI.class); - Collection instances = DynamicThreadPoolServiceLoader.getServiceInstances(TestSingletonInterfaceSPI.class); - assertThat(instances.iterator().next(), is(DynamicThreadPoolServiceLoader.getSingletonServiceInstances(TestSingletonInterfaceSPI.class).iterator().next())); + ServiceLoaderRegistry.register(TestSingletonInterfaceSPI.class); + Collection instances = ServiceLoaderRegistry.getServiceInstances(TestSingletonInterfaceSPI.class); + assertThat(instances.iterator().next(), is(ServiceLoaderRegistry.getSingletonServiceInstances(TestSingletonInterfaceSPI.class).iterator().next())); } @Test public void assertGetServiceInstancesWhenNotSingleton() { - DynamicThreadPoolServiceLoader.register(TestInterfaceSPI.class); - Collection instances = DynamicThreadPoolServiceLoader.getServiceInstances(TestInterfaceSPI.class); - assertThat(instances.iterator().next(), not(DynamicThreadPoolServiceLoader.getSingletonServiceInstances(TestInterfaceSPI.class).iterator().next())); + ServiceLoaderRegistry.register(TestInterfaceSPI.class); + Collection instances = ServiceLoaderRegistry.getServiceInstances(TestInterfaceSPI.class); + assertThat(instances.iterator().next(), not(ServiceLoaderRegistry.getSingletonServiceInstances(TestInterfaceSPI.class).iterator().next())); } } diff --git a/hippo4j-common/src/test/java/cn/hippo4j/common/spi/TestInterfaceSPI.java b/hippo4j-common/src/test/java/cn/hippo4j/common/spi/TestInterfaceSPI.java index 69baeb8a..2851f7e9 100644 --- a/hippo4j-common/src/test/java/cn/hippo4j/common/spi/TestInterfaceSPI.java +++ b/hippo4j-common/src/test/java/cn/hippo4j/common/spi/TestInterfaceSPI.java @@ -17,8 +17,10 @@ package cn.hippo4j.common.spi; +import cn.hippo4j.common.extension.support.ServiceLoaderRegistry; + /** - * test {@link DynamicThreadPoolServiceLoader} + * test {@link ServiceLoaderRegistry} */ public interface TestInterfaceSPI { } diff --git a/hippo4j-common/src/test/java/cn/hippo4j/common/spi/TestInterfaceSPIImpl.java b/hippo4j-common/src/test/java/cn/hippo4j/common/spi/TestInterfaceSPIImpl.java index 833a5919..fc8b2779 100644 --- a/hippo4j-common/src/test/java/cn/hippo4j/common/spi/TestInterfaceSPIImpl.java +++ b/hippo4j-common/src/test/java/cn/hippo4j/common/spi/TestInterfaceSPIImpl.java @@ -17,8 +17,10 @@ package cn.hippo4j.common.spi; +import cn.hippo4j.common.extension.support.ServiceLoaderRegistry; + /** - * test {@link DynamicThreadPoolServiceLoader} + * test {@link ServiceLoaderRegistry} */ public class TestInterfaceSPIImpl implements TestInterfaceSPI { } diff --git a/hippo4j-common/src/test/java/cn/hippo4j/common/spi/TestSingletonInterfaceSPI.java b/hippo4j-common/src/test/java/cn/hippo4j/common/spi/TestSingletonInterfaceSPI.java index 739e08d3..e530d6bb 100644 --- a/hippo4j-common/src/test/java/cn/hippo4j/common/spi/TestSingletonInterfaceSPI.java +++ b/hippo4j-common/src/test/java/cn/hippo4j/common/spi/TestSingletonInterfaceSPI.java @@ -17,10 +17,11 @@ package cn.hippo4j.common.spi; -import cn.hippo4j.common.spi.annotation.SingletonSPI; +import cn.hippo4j.common.extension.annotation.SingletonSPI; +import cn.hippo4j.common.extension.support.ServiceLoaderRegistry; /** - * test {@link DynamicThreadPoolServiceLoader} + * test {@link ServiceLoaderRegistry} */ @SingletonSPI public interface TestSingletonInterfaceSPI { diff --git a/hippo4j-common/src/test/java/cn/hippo4j/common/spi/TestSingletonInterfaceSPIImpl.java b/hippo4j-common/src/test/java/cn/hippo4j/common/spi/TestSingletonInterfaceSPIImpl.java index d5babd2a..6aeb275f 100644 --- a/hippo4j-common/src/test/java/cn/hippo4j/common/spi/TestSingletonInterfaceSPIImpl.java +++ b/hippo4j-common/src/test/java/cn/hippo4j/common/spi/TestSingletonInterfaceSPIImpl.java @@ -17,8 +17,10 @@ package cn.hippo4j.common.spi; +import cn.hippo4j.common.extension.support.ServiceLoaderRegistry; + /** - * test {@link DynamicThreadPoolServiceLoader} + * test {@link ServiceLoaderRegistry} */ public class TestSingletonInterfaceSPIImpl implements TestSingletonInterfaceSPI { } diff --git a/hippo4j-common/src/test/resources/META-INF/services/cn.hippo4j.common.extension.spi.IOldSpi b/hippo4j-common/src/test/resources/META-INF/services/cn.hippo4j.common.extension.spi.IOldSpi new file mode 100644 index 00000000..29dcbcac --- /dev/null +++ b/hippo4j-common/src/test/resources/META-INF/services/cn.hippo4j.common.extension.spi.IOldSpi @@ -0,0 +1 @@ +cn.hippo4j.common.extension.spi.IOldSpiImplA \ No newline at end of file diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/executor/support/adpter/DynamicThreadPoolAdapterChoose.java b/hippo4j-core/src/main/java/cn/hippo4j/core/executor/support/adpter/DynamicThreadPoolAdapterChoose.java index c3169502..420fc353 100644 --- a/hippo4j-core/src/main/java/cn/hippo4j/core/executor/support/adpter/DynamicThreadPoolAdapterChoose.java +++ b/hippo4j-core/src/main/java/cn/hippo4j/core/executor/support/adpter/DynamicThreadPoolAdapterChoose.java @@ -17,7 +17,7 @@ package cn.hippo4j.core.executor.support.adpter; -import cn.hippo4j.common.spi.DynamicThreadPoolServiceLoader; +import cn.hippo4j.common.extension.support.ServiceLoaderRegistry; import cn.hippo4j.common.toolkit.CollectionUtil; import cn.hippo4j.core.executor.DynamicThreadPoolExecutor; import cn.hippo4j.core.executor.support.spi.DynamicThreadPoolAdapterSPI; @@ -83,8 +83,8 @@ public class DynamicThreadPoolAdapterChoose { * Load SPI customer adapter. */ private static void loadCustomerAdapter() { - DynamicThreadPoolServiceLoader.register(DynamicThreadPoolAdapterSPI.class); - Collection instances = DynamicThreadPoolServiceLoader.getSingletonServiceInstances(DynamicThreadPoolAdapterSPI.class); + ServiceLoaderRegistry.register(DynamicThreadPoolAdapterSPI.class); + Collection instances = ServiceLoaderRegistry.getSingletonServiceInstances(DynamicThreadPoolAdapterSPI.class); if (CollectionUtil.isEmpty(instances)) { return; } diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/toolkit/IdentifyUtil.java b/hippo4j-core/src/main/java/cn/hippo4j/core/toolkit/IdentifyUtil.java index 2d883772..00a67f26 100644 --- a/hippo4j-core/src/main/java/cn/hippo4j/core/toolkit/IdentifyUtil.java +++ b/hippo4j-core/src/main/java/cn/hippo4j/core/toolkit/IdentifyUtil.java @@ -19,7 +19,7 @@ package cn.hippo4j.core.toolkit; import cn.hippo4j.common.api.ClientNetworkService; import cn.hippo4j.common.config.ApplicationContextHolder; -import cn.hippo4j.common.spi.DynamicThreadPoolServiceLoader; +import cn.hippo4j.common.extension.support.ServiceLoaderRegistry; import cn.hippo4j.common.toolkit.CollectionUtil; import cn.hippo4j.common.toolkit.IdUtil; import cn.hippo4j.common.toolkit.Joiner; @@ -39,7 +39,7 @@ import static cn.hippo4j.common.constant.Constants.IDENTIFY_SLICER_SYMBOL; public class IdentifyUtil { static { - DynamicThreadPoolServiceLoader.register(ClientNetworkService.class); + ServiceLoaderRegistry.register(ClientNetworkService.class); } /** @@ -63,7 +63,7 @@ public class IdentifyUtil { if (StringUtil.isNotBlank(IDENTIFY)) { return IDENTIFY; } - String[] customerNetwork = DynamicThreadPoolServiceLoader.getSingletonServiceInstances(ClientNetworkService.class) + String[] customerNetwork = ServiceLoaderRegistry.getSingletonServiceInstances(ClientNetworkService.class) .stream().findFirst().map(each -> each.getNetworkIpPort(environment)).orElse(null); String ip; String port; diff --git a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/monitor/ThreadPoolMonitorExecutor.java b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/monitor/ThreadPoolMonitorExecutor.java index 7818fe42..5b91d02d 100644 --- a/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/monitor/ThreadPoolMonitorExecutor.java +++ b/hippo4j-spring-boot/hippo4j-config-spring-boot-starter/src/main/java/cn/hippo4j/config/springboot/starter/monitor/ThreadPoolMonitorExecutor.java @@ -27,7 +27,7 @@ import java.util.concurrent.TimeUnit; import cn.hippo4j.common.config.ApplicationContextHolder; import cn.hippo4j.common.design.builder.ThreadFactoryBuilder; -import cn.hippo4j.common.spi.DynamicThreadPoolServiceLoader; +import cn.hippo4j.common.extension.support.ServiceLoaderRegistry; import cn.hippo4j.common.toolkit.StringUtil; import cn.hippo4j.config.springboot.starter.config.BootstrapConfigProperties; import cn.hippo4j.config.springboot.starter.config.MonitorProperties; @@ -74,7 +74,7 @@ public class ThreadPoolMonitorExecutor implements ApplicationRunner, DisposableB List collectTypes = Arrays.asList(monitor.getCollectTypes().split(",")); ApplicationContextHolder.getBeansOfType(ThreadPoolMonitor.class).forEach((beanName, bean) -> threadPoolMonitors.add(bean)); Collection dynamicThreadPoolMonitors = - DynamicThreadPoolServiceLoader.getSingletonServiceInstances(DynamicThreadPoolMonitor.class); + ServiceLoaderRegistry.getSingletonServiceInstances(DynamicThreadPoolMonitor.class); dynamicThreadPoolMonitors.stream().filter(each -> collectTypes.contains(each.getType())).forEach(each -> threadPoolMonitors.add(each)); // Execute dynamic thread pool monitoring component. collectScheduledExecutor.scheduleWithFixedDelay( diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/controller/ThreadPoolAdapterController.java b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/controller/ThreadPoolAdapterController.java index 6bc1bad8..decbc0fc 100644 --- a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/controller/ThreadPoolAdapterController.java +++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/controller/ThreadPoolAdapterController.java @@ -21,7 +21,7 @@ import cn.hippo4j.adapter.base.ThreadPoolAdapter; import cn.hippo4j.adapter.base.ThreadPoolAdapterParameter; import cn.hippo4j.adapter.base.ThreadPoolAdapterState; import cn.hippo4j.common.api.ClientNetworkService; -import cn.hippo4j.common.spi.DynamicThreadPoolServiceLoader; +import cn.hippo4j.common.extension.support.ServiceLoaderRegistry; import cn.hippo4j.common.toolkit.StringUtil; import cn.hippo4j.common.web.base.Result; import cn.hippo4j.common.web.base.Results; @@ -59,7 +59,7 @@ public class ThreadPoolAdapterController { ThreadPoolAdapterState threadPoolState = each.getThreadPoolState(requestParameter.getThreadPoolKey()); String active = environment.getProperty("spring.profiles.active", "UNKNOWN"); threadPoolState.setActive(active.toUpperCase()); - String[] customerNetwork = DynamicThreadPoolServiceLoader.getSingletonServiceInstances(ClientNetworkService.class) + String[] customerNetwork = ServiceLoaderRegistry.getSingletonServiceInstances(ClientNetworkService.class) .stream().findFirst().map(network -> network.getNetworkIpPort(environment)).orElse(null); String clientAddress; if (customerNetwork != null) { diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/monitor/ReportingEventExecutor.java b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/monitor/ReportingEventExecutor.java index b4edecc0..b908c3e6 100644 --- a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/monitor/ReportingEventExecutor.java +++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/monitor/ReportingEventExecutor.java @@ -20,7 +20,7 @@ package cn.hippo4j.springboot.starter.monitor; import cn.hippo4j.common.config.ApplicationContextHolder; import cn.hippo4j.common.design.builder.ThreadFactoryBuilder; import cn.hippo4j.common.monitor.Message; -import cn.hippo4j.common.spi.DynamicThreadPoolServiceLoader; +import cn.hippo4j.common.extension.support.ServiceLoaderRegistry; import cn.hippo4j.common.toolkit.CollectionUtil; import cn.hippo4j.common.toolkit.StringUtil; import cn.hippo4j.common.toolkit.ThreadUtil; @@ -119,7 +119,7 @@ public class ReportingEventExecutor implements Runnable, CommandLineRunner, Disp new Integer(collectType.split(",").length), ThreadFactoryBuilder.builder().daemon(true).prefix("client.scheduled.collect.data").build()); Collection dynamicThreadPoolMonitors = - DynamicThreadPoolServiceLoader.getSingletonServiceInstances(ThreadPoolMonitor.class); + ServiceLoaderRegistry.getSingletonServiceInstances(ThreadPoolMonitor.class); Map threadPoolMonitorMap = ApplicationContextHolder.getBeansOfType(ThreadPoolMonitor.class); boolean customerDynamicThreadPoolMonitorFlag = CollectionUtil.isNotEmpty(dynamicThreadPoolMonitors) || CollectionUtil.isNotEmpty(threadPoolMonitorMap); if (customerDynamicThreadPoolMonitorFlag) { diff --git a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/provider/InstanceInfoProviderFactory.java b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/provider/InstanceInfoProviderFactory.java index 41a20e9e..02b8f047 100644 --- a/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/provider/InstanceInfoProviderFactory.java +++ b/hippo4j-spring-boot/hippo4j-spring-boot-starter/src/main/java/cn/hippo4j/springboot/starter/provider/InstanceInfoProviderFactory.java @@ -19,7 +19,7 @@ package cn.hippo4j.springboot.starter.provider; import cn.hippo4j.common.api.ClientNetworkService; import cn.hippo4j.common.model.InstanceInfo; -import cn.hippo4j.common.spi.DynamicThreadPoolServiceLoader; +import cn.hippo4j.common.extension.support.ServiceLoaderRegistry; import cn.hippo4j.common.toolkit.ContentUtil; import cn.hippo4j.core.toolkit.IdentifyUtil; import cn.hippo4j.core.toolkit.inet.InetUtils; @@ -40,7 +40,7 @@ import static cn.hippo4j.core.toolkit.IdentifyUtil.CLIENT_IDENTIFICATION_VALUE; public final class InstanceInfoProviderFactory { static { - DynamicThreadPoolServiceLoader.register(ClientNetworkService.class); + ServiceLoaderRegistry.register(ClientNetworkService.class); } /** @@ -69,7 +69,7 @@ public final class InstanceInfoProviderFactory { .setIpApplicationName(CloudCommonIdUtil.getIpApplicationName(environment, inetUtils)) .setHostName(InetAddress.getLocalHost().getHostAddress()).setAppName(applicationName) .setPort(port).setClientBasePath(contextPath).setGroupKey(ContentUtil.getGroupKey(itemId, namespace)); - String[] customerNetwork = DynamicThreadPoolServiceLoader.getSingletonServiceInstances(ClientNetworkService.class) + String[] customerNetwork = ServiceLoaderRegistry.getSingletonServiceInstances(ClientNetworkService.class) .stream().findFirst().map(each -> each.getNetworkIpPort(environment)).orElse(null); String callBackUrl = new StringBuilder().append(Optional.ofNullable(customerNetwork).map(each -> each[0]).orElse(instanceInfo.getHostName())).append(":") .append(Optional.ofNullable(customerNetwork).map(each -> each[1]).orElse(port)).append(instanceInfo.getClientBasePath())