├── .github └── workflows │ ├── maven-build.yml │ └── maven-publish.yml ├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── LICENSE ├── README.md ├── microsphere-spring-cloud-commons ├── pom.xml └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── microsphere │ │ │ └── spring │ │ │ └── cloud │ │ │ ├── client │ │ │ ├── condition │ │ │ │ └── ConditionalOnFeaturesEnabled.java │ │ │ ├── discovery │ │ │ │ ├── UnionDiscoveryClient.java │ │ │ │ ├── autoconfigure │ │ │ │ │ └── DiscoveryClientAutoConfiguration.java │ │ │ │ └── constants │ │ │ │ │ └── DiscoveryClientConstants.java │ │ │ ├── event │ │ │ │ └── ServiceInstancesChangedEvent.java │ │ │ └── service │ │ │ │ ├── registry │ │ │ │ ├── DefaultRegistration.java │ │ │ │ ├── InMemoryServiceRegistry.java │ │ │ │ ├── MultipleAutoServiceRegistration.java │ │ │ │ ├── MultipleRegistration.java │ │ │ │ ├── MultipleServiceRegistry.java │ │ │ │ ├── RegistrationCustomizer.java │ │ │ │ ├── RegistrationMetaData.java │ │ │ │ ├── SimpleAutoServiceRegistration.java │ │ │ │ ├── actuate │ │ │ │ │ └── autoconfigure │ │ │ │ │ │ └── ServiceRegistrationEndpointAutoConfiguration.java │ │ │ │ ├── aspect │ │ │ │ │ └── EventPublishingRegistrationAspect.java │ │ │ │ ├── autoconfigure │ │ │ │ │ ├── ServiceRegistryAutoConfiguration.java │ │ │ │ │ ├── SimpleAutoServiceRegistrationAutoConfiguration.java │ │ │ │ │ ├── WebFluxServiceRegistryAutoConfiguration.java │ │ │ │ │ └── WebMvcServiceRegistryAutoConfiguration.java │ │ │ │ ├── condition │ │ │ │ │ ├── ConditionalOnAutoServiceRegistrationEnabled.java │ │ │ │ │ └── ConditionalOnMultipleRegistrationEnabled.java │ │ │ │ ├── constants │ │ │ │ │ └── InstanceConstants.java │ │ │ │ ├── endpoint │ │ │ │ │ ├── AbstractServiceRegistrationEndpoint.java │ │ │ │ │ ├── ServiceDeregistrationEndpoint.java │ │ │ │ │ └── ServiceRegistrationEndpoint.java │ │ │ │ └── event │ │ │ │ │ ├── RegistrationDeregisteredEvent.java │ │ │ │ │ ├── RegistrationEvent.java │ │ │ │ │ ├── RegistrationPreDeregisteredEvent.java │ │ │ │ │ ├── RegistrationPreRegisteredEvent.java │ │ │ │ │ └── RegistrationRegisteredEvent.java │ │ │ │ └── util │ │ │ │ └── ServiceInstanceUtils.java │ │ │ ├── commons │ │ │ └── constants │ │ │ │ └── CommonsPropertyConstants.java │ │ │ └── fault │ │ │ └── tolerance │ │ │ ├── constants │ │ │ └── FaultTolerancePropertyConstants.java │ │ │ ├── loadbalancer │ │ │ ├── WeightedRoundRobin.java │ │ │ └── util │ │ │ │ └── LoadBalancerUtils.java │ │ │ └── tomcat │ │ │ ├── autoconfigure │ │ │ └── TomcatFaultToleranceAutoConfiguration.java │ │ │ └── event │ │ │ └── TomcatDynamicConfigurationListener.java │ └── resources │ │ └── META-INF │ │ ├── config │ │ └── default │ │ │ └── endpoints.properties │ │ ├── spring.factories │ │ └── spring │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ └── test │ ├── java │ └── io │ │ └── microsphere │ │ └── spring │ │ └── cloud │ │ ├── client │ │ ├── condition │ │ │ └── ConditionalOnFeaturesEnabledTest.java │ │ ├── discovery │ │ │ ├── autoconfigure │ │ │ │ ├── DiscoveryClientAutoConfigurationTest.java │ │ │ │ └── UnionDiscoveryClientTest.java │ │ │ └── constants │ │ │ │ └── DiscoveryClientConstantsTest.java │ │ ├── event │ │ │ └── ServiceInstancesChangedEventTest.java │ │ └── service │ │ │ └── registry │ │ │ ├── MultipleServiceRegistryTest.java │ │ │ ├── actuate │ │ │ └── autoconfigure │ │ │ │ └── ServiceRegistrationEndpointAutoConfigurationTest.java │ │ │ └── autoconfigure │ │ │ ├── ServiceRegistryAutoConfigurationTest.java │ │ │ ├── SimpleAutoServiceRegistrationAutoConfigurationTest.java │ │ │ └── WebMvcServiceRegistryAutoConfigurationTest.java │ │ ├── commons │ │ └── constants │ │ │ └── CommonsPropertyConstantsTest.java │ │ └── fault │ │ └── tolerance │ │ └── tomcat │ │ └── autoconfigure │ │ └── TomcatFaultToleranceAutoConfigurationTest.java │ └── resources │ └── application.yaml ├── microsphere-spring-cloud-dependencies └── pom.xml ├── microsphere-spring-cloud-openfeign ├── pom.xml └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── microsphere │ │ │ └── spring │ │ │ └── cloud │ │ │ └── openfeign │ │ │ ├── autoconfigure │ │ │ ├── EnableFeignAutoRefresh.java │ │ │ ├── FeignClientAutoRefreshAutoConfiguration.java │ │ │ └── FeignClientSpecificationPostProcessor.java │ │ │ ├── autorefresh │ │ │ ├── AutoRefreshCapability.java │ │ │ ├── FeignClientConfigurationChangedListener.java │ │ │ └── FeignComponentRegistry.java │ │ │ └── components │ │ │ ├── CompositedRequestInterceptor.java │ │ │ ├── DecoratedContract.java │ │ │ ├── DecoratedDecoder.java │ │ │ ├── DecoratedEncoder.java │ │ │ ├── DecoratedErrorDecoder.java │ │ │ ├── DecoratedFeignComponent.java │ │ │ ├── DecoratedQueryMapEncoder.java │ │ │ ├── DecoratedRetryer.java │ │ │ ├── NoOpRequestInterceptor.java │ │ │ └── Refreshable.java │ └── resources │ │ └── META-INF │ │ └── spring │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ └── test │ └── java │ └── io │ └── microsphere │ └── spring │ └── cloud │ └── openfeign │ ├── BaseClient.java │ ├── BaseTest.java │ ├── FeignComponentAssert.java │ ├── MockCapability.java │ ├── ObservableFeignInvocationHandler.java │ ├── decoder │ ├── ADecoder.java │ ├── BDecoder.java │ ├── DecoderChangedTest.java │ └── DecoderComponentAssert.java │ ├── encoder │ ├── AEncoder.java │ ├── BEncoder.java │ ├── EncoderChangedTest.java │ └── EncoderComponentAssert.java │ ├── errordecoder │ ├── AErrorDecoder.java │ ├── BErrorEncoder.java │ ├── ErrorDecoderChangedTest.java │ └── ErrorDecoderComponentAssert.java │ ├── querymapencoder │ ├── AQueryMapEncoder.java │ ├── BQueryMapEncoder.java │ ├── QueryMapEncoderChangedTest.java │ └── QueryMapEncoderComponentAssert.java │ ├── requestInterceptor │ ├── ARequestInterceptor.java │ ├── BRequestInterceptor.java │ ├── RequestInterceptorChangedTest.java │ └── RequestInterceptorComponentAssert.java │ └── retryer │ ├── ARetry.java │ ├── BRetry.java │ ├── RetryerChangedTest.java │ └── RetryerComponentAssert.java ├── microsphere-spring-cloud-parent └── pom.xml └── pom.xml /.github/workflows/maven-build.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven 3 | 4 | # This workflow uses actions that are not certified by GitHub. 5 | # They are provided by a third-party and are governed by 6 | # separate terms of service, privacy policy, and support 7 | # documentation. 8 | 9 | name: Maven Build 10 | 11 | on: 12 | push: 13 | branches: [ 'dev' ] 14 | pull_request: 15 | branches: [ 'main', 'dev' , 'release' ] 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | strategy: 21 | matrix: 22 | java: [ '17' , '21' ] 23 | maven-profile-spring-cloud: [ 'spring-cloud-2022' , 'spring-cloud-2023' , 'spring-cloud-2024' ] 24 | steps: 25 | - name: Checkout Source 26 | uses: actions/checkout@v4 27 | 28 | - name: Setup JDK ${{ matrix.Java }} 29 | uses: actions/setup-java@v4 30 | with: 31 | distribution: 'temurin' 32 | java-version: ${{ matrix.java }} 33 | cache: maven 34 | 35 | - name: Build with Maven 36 | run: mvn 37 | --batch-mode 38 | --update-snapshots 39 | --file pom.xml 40 | -Drevision=0.0.1-SNAPSHOT 41 | test 42 | --activate-profiles test,coverage,${{ matrix.maven-profile-spring-cloud }} 43 | 44 | - name: Upload coverage reports to Codecov 45 | uses: codecov/codecov-action@v5 46 | with: 47 | token: ${{ secrets.CODECOV_TOKEN }} 48 | slug: microsphere-projects/microsphere-spring-cloud -------------------------------------------------------------------------------- /.github/workflows/maven-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven 3 | 4 | # This workflow uses actions that are not certified by GitHub. 5 | # They are provided by a third-party and are governed by 6 | # separate terms of service, privacy policy, and support 7 | # documentation. 8 | 9 | name: Maven Publish 10 | 11 | on: 12 | push: 13 | branches: [ 'release' ] 14 | workflow_dispatch: 15 | inputs: 16 | revision: 17 | description: 'The version to publish for Spring Cloud 2022+ and JDK 17+' 18 | required: true 19 | default: '2.0.0-SNAPSHOT' 20 | 21 | jobs: 22 | build: 23 | runs-on: ubuntu-latest 24 | if: ${{ inputs.revision }} 25 | steps: 26 | - name: Checkout Source 27 | uses: actions/checkout@v4 28 | 29 | - name: Setup Maven Central Repository 30 | uses: actions/setup-java@v4 31 | with: 32 | java-version: '17' 33 | distribution: 'temurin' 34 | server-id: ossrh 35 | server-username: MAVEN_USERNAME 36 | server-password: MAVEN_PASSWORD 37 | cache: maven 38 | 39 | - name: Publish package 40 | run: mvn 41 | --batch-mode 42 | --update-snapshots 43 | --file pom.xml 44 | -Drevision=${{ inputs.revision }} 45 | -Dgpg.skip=true 46 | deploy 47 | --activate-profiles release,ci 48 | env: 49 | MAVEN_USERNAME: ${{ secrets.OSS_SONATYPE_USERNAME }} 50 | MAVEN_PASSWORD: ${{ secrets.OSS_SONATYPE_PASSWORD }} 51 | SIGN_KEY_ID: ${{ secrets.OSS_SIGNING_KEY_ID_LONG }} 52 | SIGN_KEY: ${{ secrets.OSS_SIGNING_KEY }} 53 | SIGN_KEY_PASS: ${{ secrets.OSS_SIGNING_PASSWORD }} 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # maven ignore 26 | target/ 27 | !.mvn/wrapper/* 28 | 29 | # eclipse ignore 30 | .settings/ 31 | .project 32 | .classpath 33 | 34 | # idea ignore 35 | .idea/ 36 | .idea 37 | *.ipr 38 | *.iml 39 | *.iws 40 | 41 | # temp ignore 42 | *.log 43 | *.cache 44 | *.diff 45 | *.patch 46 | *.tmp 47 | 48 | # system ignore 49 | .DS_Store 50 | Thumbs.db 51 | *.orig 52 | 53 | # flatten ignore 54 | .flattened-pom.xml 55 | 56 | # license check result 57 | license-list 58 | 59 | # grpc compiler 60 | compiler/gradle.properties 61 | compiler/build/* 62 | compiler/.gradle/* 63 | 64 | # Tomcat 65 | .extract 66 | .java-version 67 | 68 | # others 69 | build.txt -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsphere-projects/microsphere-spring-cloud/6791f2abf86918c56b67f65a12c1fed595af279a/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Copyright 2013-2023 the original author or authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.0/apache-maven-3.9.0-bin.zip 16 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Microsphere Spring Cloud 2 | 3 | Microsphere Projects for Spring Cloud 4 | 5 | [![Maven Build](https://github.com/microsphere-projects/microsphere-spring-cloud/actions/workflows/maven-build.yml/badge.svg)](https://github.com/microsphere-projects/microsphere-spring-cloud/actions/workflows/maven-build.yml) 6 | [![Codecov](https://codecov.io/gh/microsphere-projects/microsphere-spring-cloud/branch/main/graph/badge.svg)](https://app.codecov.io/gh/microsphere-projects/microsphere-spring-cloud) 7 | ![Maven](https://img.shields.io/maven-central/v/io.github.microsphere-projects/microsphere-spring-cloud.svg) 8 | ![License](https://img.shields.io/github/license/microsphere-projects/microsphere-spring-cloud.svg) 9 | [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/microsphere-projects/microsphere-spring-cloud.svg)](http://isitmaintained.com/project/microsphere-projects/microsphere-spring-cloud "Average time to resolve an issue") 10 | [![Percentage of issues still open](http://isitmaintained.com/badge/open/microsphere-projects/microsphere-spring-cloud.svg)](http://isitmaintained.com/project/microsphere-projects/microsphere-spring-cloud "Percentage of issues still open") 11 | 12 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | io.github.microsphere-projects 7 | microsphere-spring-cloud-parent 8 | ${revision} 9 | ../microsphere-spring-cloud-parent/pom.xml 10 | 11 | 4.0.0 12 | 13 | microsphere-spring-cloud-commons 14 | ${revision} 15 | 16 | Microsphere :: Spring Cloud :: Commons 17 | Microsphere Spring Cloud Commons 18 | 19 | 20 | 21 | 22 | org.aspectj 23 | aspectjweaver 24 | 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter 30 | true 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-web 36 | true 37 | 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-webflux 42 | true 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-configuration-processor 48 | true 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-starter-actuator 54 | true 55 | 56 | 57 | 58 | 59 | org.springframework.cloud 60 | spring-cloud-commons 61 | true 62 | 63 | 64 | 65 | org.springframework.cloud 66 | spring-cloud-context 67 | true 68 | 69 | 70 | 71 | 72 | io.github.microsphere-projects 73 | microsphere-spring-boot-core 74 | 75 | 76 | 77 | io.github.microsphere-projects 78 | microsphere-spring-webmvc 79 | true 80 | 81 | 82 | 83 | io.github.microsphere-projects 84 | microsphere-spring-webflux 85 | true 86 | 87 | 88 | 89 | 90 | org.springframework.boot 91 | spring-boot-starter-test 92 | test 93 | 94 | 95 | 96 | 97 | org.testcontainers 98 | junit-jupiter 99 | test 100 | 101 | 102 | 103 | 104 | org.springframework.cloud 105 | spring-cloud-netflix-eureka-client 106 | test 107 | 108 | 109 | 110 | com.netflix.eureka 111 | eureka-client 112 | test 113 | 114 | 115 | 116 | 117 | com.alibaba.cloud 118 | spring-cloud-starter-alibaba-nacos-discovery 119 | test 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/condition/ConditionalOnFeaturesEnabled.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.condition; 18 | 19 | import io.microsphere.spring.cloud.commons.constants.CommonsPropertyConstants; 20 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 21 | import org.springframework.cloud.client.CommonsClientAutoConfiguration; 22 | import org.springframework.cloud.client.actuator.FeaturesEndpoint; 23 | import org.springframework.cloud.client.actuator.HasFeatures; 24 | import org.springframework.core.annotation.AliasFor; 25 | 26 | import java.lang.annotation.Documented; 27 | import java.lang.annotation.ElementType; 28 | import java.lang.annotation.Retention; 29 | import java.lang.annotation.RetentionPolicy; 30 | import java.lang.annotation.Target; 31 | 32 | import static io.microsphere.spring.cloud.commons.constants.CommonsPropertyConstants.FEATURES_ENABLED_PROPERTY_NAME; 33 | 34 | /** 35 | * The conditional annotation meta-annotates {@link ConditionalOnProperty @ConditionalOnProperty} for 36 | * {@link FeaturesEndpoint @FeaturesEndpoint} enabled. 37 | * 38 | * @author Mercy 39 | * @see CommonsClientAutoConfiguration.ActuatorConfiguration 40 | * @see FeaturesEndpoint 41 | * @see HasFeatures 42 | * @see CommonsPropertyConstants#FEATURES_ENABLED_PROPERTY_NAME 43 | * @see ConditionalOnProperty 44 | * @since 1.0.0 45 | */ 46 | @Retention(RetentionPolicy.RUNTIME) 47 | @Target({ElementType.TYPE, ElementType.METHOD}) 48 | @Documented 49 | @ConditionalOnProperty(name = FEATURES_ENABLED_PROPERTY_NAME) 50 | public @interface ConditionalOnFeaturesEnabled { 51 | 52 | /** 53 | * Specify if the condition should match if the property is not set. Defaults to 54 | * {@code true}. 55 | * 56 | * @return if the condition should match if the property is missing 57 | */ 58 | @AliasFor(annotation = ConditionalOnProperty.class, attribute = "matchIfMissing") 59 | boolean matchIfMissing() default true; 60 | } 61 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/discovery/UnionDiscoveryClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.discovery; 18 | 19 | import org.springframework.beans.factory.DisposableBean; 20 | import org.springframework.beans.factory.ObjectProvider; 21 | import org.springframework.beans.factory.SmartInitializingSingleton; 22 | import org.springframework.cloud.client.ServiceInstance; 23 | import org.springframework.cloud.client.discovery.DiscoveryClient; 24 | import org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClient; 25 | 26 | import java.util.ArrayList; 27 | import java.util.LinkedHashSet; 28 | import java.util.LinkedList; 29 | import java.util.List; 30 | 31 | import static io.microsphere.reflect.TypeUtils.getClassName; 32 | import static io.microsphere.spring.cloud.client.discovery.constants.DiscoveryClientConstants.COMPOSITE_DISCOVERY_CLIENT_CLASS_NAME; 33 | 34 | /** 35 | * The {@link DiscoveryClient} implementation for a union of the given {@link DiscoveryClient} 36 | * 37 | * @author Mercy 38 | * @see CompositeDiscoveryClient 39 | * @since 1.0.0 40 | */ 41 | public final class UnionDiscoveryClient implements DiscoveryClient, SmartInitializingSingleton, DisposableBean { 42 | 43 | private final ObjectProvider discoveryClientsProvider; 44 | 45 | private List discoveryClients; 46 | 47 | public UnionDiscoveryClient(ObjectProvider discoveryClientsProvider) { 48 | this.discoveryClientsProvider = discoveryClientsProvider; 49 | } 50 | 51 | @Override 52 | public String description() { 53 | return "Union Discovery Client"; 54 | } 55 | 56 | @Override 57 | public List getInstances(String serviceId) { 58 | List serviceInstances = new LinkedList<>(); 59 | List discoveryClients = getDiscoveryClients(); 60 | for (DiscoveryClient discoveryClient : discoveryClients) { 61 | List instances = discoveryClient.getInstances(serviceId); 62 | if (instances != null && !instances.isEmpty()) { 63 | serviceInstances.addAll(instances); 64 | } 65 | } 66 | return serviceInstances; 67 | } 68 | 69 | @Override 70 | public List getServices() { 71 | LinkedHashSet services = new LinkedHashSet<>(); 72 | List discoveryClients = getDiscoveryClients(); 73 | for (DiscoveryClient discoveryClient : discoveryClients) { 74 | List serviceForClient = discoveryClient.getServices(); 75 | if (serviceForClient != null) { 76 | services.addAll(serviceForClient); 77 | } 78 | } 79 | return new ArrayList<>(services); 80 | } 81 | 82 | public List getDiscoveryClients() { 83 | List discoveryClients = this.discoveryClients; 84 | if (discoveryClients != null) { 85 | return discoveryClients; 86 | } 87 | 88 | discoveryClients = new LinkedList<>(); 89 | 90 | for (DiscoveryClient discoveryClient : discoveryClientsProvider) { 91 | String className = getClassName(discoveryClient.getClass()); 92 | if (COMPOSITE_DISCOVERY_CLIENT_CLASS_NAME.equals(className) || this.equals(discoveryClient)) { 93 | // excludes CompositeDiscoveryClient and self 94 | continue; 95 | } 96 | discoveryClients.add(discoveryClient); 97 | } 98 | return discoveryClients; 99 | } 100 | 101 | @Override 102 | public int getOrder() { 103 | return HIGHEST_PRECEDENCE; 104 | } 105 | 106 | @Override 107 | public void afterSingletonsInstantiated() { 108 | this.discoveryClients = getDiscoveryClients(); 109 | } 110 | 111 | @Override 112 | public void destroy() throws Exception { 113 | this.discoveryClients.clear(); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/discovery/autoconfigure/DiscoveryClientAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.discovery.autoconfigure; 18 | 19 | import io.microsphere.spring.cloud.client.discovery.UnionDiscoveryClient; 20 | import org.springframework.beans.factory.ObjectProvider; 21 | import org.springframework.boot.autoconfigure.AutoConfigureBefore; 22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 23 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 24 | import org.springframework.cloud.client.CommonsClientAutoConfiguration; 25 | import org.springframework.cloud.client.ConditionalOnBlockingDiscoveryEnabled; 26 | import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled; 27 | import org.springframework.cloud.client.discovery.DiscoveryClient; 28 | import org.springframework.context.annotation.Bean; 29 | import org.springframework.context.annotation.Configuration; 30 | 31 | import static io.microsphere.spring.cloud.client.discovery.constants.DiscoveryClientConstants.COMMONS_CLIENT_AUTO_CONFIGURATION_CLASS_NAME; 32 | import static io.microsphere.spring.cloud.client.discovery.constants.DiscoveryClientConstants.DISCOVERY_CLIENT_CLASS_NAME; 33 | import static io.microsphere.spring.cloud.client.discovery.constants.DiscoveryClientConstants.DISCOVERY_CLIENT_PROPERTY_PREFIX; 34 | import static io.microsphere.spring.cloud.client.discovery.constants.DiscoveryClientConstants.MODE_PROPERTY_NAME; 35 | import static io.microsphere.spring.cloud.client.discovery.constants.DiscoveryClientConstants.UNION_DISCOVERY_CLIENT_MODE; 36 | 37 | /** 38 | * {@link UnionDiscoveryClient} Auto-Configuration Class 39 | * 40 | * @author Mercy 41 | * @see UnionDiscoveryClient 42 | * @see CommonsClientAutoConfiguration 43 | * @since 1.0.0 44 | */ 45 | @Configuration(proxyBeanMethods = false) 46 | @ConditionalOnClass(name = { 47 | DISCOVERY_CLIENT_CLASS_NAME 48 | }) 49 | @ConditionalOnDiscoveryEnabled 50 | @ConditionalOnBlockingDiscoveryEnabled 51 | @AutoConfigureBefore(name = { 52 | COMMONS_CLIENT_AUTO_CONFIGURATION_CLASS_NAME 53 | }) 54 | public class DiscoveryClientAutoConfiguration { 55 | 56 | @Configuration(proxyBeanMethods = false) 57 | @ConditionalOnProperty(prefix = DISCOVERY_CLIENT_PROPERTY_PREFIX, name = MODE_PROPERTY_NAME, havingValue = UNION_DISCOVERY_CLIENT_MODE) 58 | public static class UnionConfiguration { 59 | 60 | @Bean 61 | public UnionDiscoveryClient unionDiscoveryClient(ObjectProvider discoveryClientsProvider) { 62 | return new UnionDiscoveryClient(discoveryClientsProvider); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/discovery/constants/DiscoveryClientConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.discovery.constants; 18 | 19 | import io.microsphere.spring.cloud.client.discovery.UnionDiscoveryClient; 20 | import org.springframework.cloud.client.CommonsClientAutoConfiguration; 21 | import org.springframework.cloud.client.discovery.DiscoveryClient; 22 | import org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClient; 23 | 24 | import static io.microsphere.spring.cloud.commons.constants.CommonsPropertyConstants.MICROSPHERE_SPRING_CLOUD_PROPERTY_NAME_PREFIX; 25 | 26 | /** 27 | * The constants for {@link DiscoveryClient} 28 | * 29 | * @author Mercy 30 | * @since 1.0.0 31 | */ 32 | public interface DiscoveryClientConstants { 33 | 34 | /** 35 | * The property prefix of {@link DiscoveryClient} : "microsphere.spring.cloud.client.discovery." 36 | */ 37 | String DISCOVERY_CLIENT_PROPERTY_PREFIX = MICROSPHERE_SPRING_CLOUD_PROPERTY_NAME_PREFIX + "client.discovery."; 38 | 39 | /** 40 | * The property name of mode : "mode" 41 | */ 42 | String MODE_PROPERTY_NAME = "mode"; 43 | 44 | /** 45 | * The {@link DiscoveryClient} "mode" for {@link UnionDiscoveryClient} : "union" 46 | */ 47 | String UNION_DISCOVERY_CLIENT_MODE = "union"; 48 | 49 | /** 50 | * The class name of {@link DiscoveryClient} 51 | */ 52 | String DISCOVERY_CLIENT_CLASS_NAME = "org.springframework.cloud.client.discovery.DiscoveryClient"; 53 | 54 | /** 55 | * The class name of {@link CompositeDiscoveryClient} 56 | */ 57 | String COMPOSITE_DISCOVERY_CLIENT_CLASS_NAME = "org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClient"; 58 | 59 | /** 60 | * The class name of {@link CommonsClientAutoConfiguration} 61 | */ 62 | String COMMONS_CLIENT_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.client.CommonsClientAutoConfiguration"; 63 | 64 | } 65 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/event/ServiceInstancesChangedEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.event; 18 | 19 | import org.springframework.cloud.client.ServiceInstance; 20 | import org.springframework.context.ApplicationEvent; 21 | import org.springframework.context.event.ApplicationEventMulticaster; 22 | import org.springframework.context.event.SimpleApplicationEventMulticaster; 23 | 24 | import java.util.List; 25 | 26 | import static java.util.Collections.unmodifiableList; 27 | import static org.springframework.util.Assert.notEmpty; 28 | 29 | /** 30 | * An event raised when the {@link ServiceInstance instances} of one service has been 31 | * changed. 32 | * 33 | * @author Mercy 34 | */ 35 | public class ServiceInstancesChangedEvent extends ApplicationEvent { 36 | 37 | private final List serviceInstances; 38 | 39 | /** 40 | * Current event has been processed or not. Typically, Spring Event was based on sync 41 | * {@link ApplicationEventMulticaster} 42 | * 43 | * @see SimpleApplicationEventMulticaster 44 | */ 45 | private boolean processed = false; 46 | 47 | /** 48 | * @param serviceName The name of service that was changed 49 | * @param serviceInstances all {@link ServiceInstance service instances} 50 | * @throws IllegalArgumentException if source is null. 51 | */ 52 | public ServiceInstancesChangedEvent(String serviceName, 53 | List serviceInstances) { 54 | super(serviceName); 55 | notEmpty(serviceInstances, () -> "The arguments 'serviceInstances' must not be empty!"); 56 | this.serviceInstances = unmodifiableList(serviceInstances); 57 | } 58 | 59 | /** 60 | * @return The name of service that was changed 61 | */ 62 | public String getServiceName() { 63 | return (String) getSource(); 64 | } 65 | 66 | /** 67 | * @return all {@link ServiceInstance service instances}. 68 | */ 69 | public List getServiceInstances() { 70 | return serviceInstances; 71 | } 72 | 73 | /** 74 | * Mark current event being processed. 75 | */ 76 | public void processed() { 77 | processed = true; 78 | } 79 | 80 | /** 81 | * Current event has been processed or not. 82 | * 83 | * @return if processed, return true, or false 84 | */ 85 | public boolean isProcessed() { 86 | return processed; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/DefaultRegistration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.service.registry; 18 | 19 | import org.springframework.cloud.client.DefaultServiceInstance; 20 | import org.springframework.cloud.client.serviceregistry.Registration; 21 | 22 | /** 23 | * Default {@link Registration} 24 | * 25 | * @author Mercy 26 | * @see DefaultServiceInstance 27 | * @since 1.0.0 28 | */ 29 | public class DefaultRegistration extends DefaultServiceInstance implements Registration { 30 | } 31 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/InMemoryServiceRegistry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.service.registry; 18 | 19 | import org.springframework.cloud.client.serviceregistry.Registration; 20 | import org.springframework.cloud.client.serviceregistry.ServiceRegistry; 21 | 22 | import java.util.Map; 23 | import java.util.concurrent.ConcurrentHashMap; 24 | import java.util.concurrent.ConcurrentMap; 25 | 26 | /** 27 | * In-Memory {@link ServiceRegistry} 28 | * 29 | * @author Mercy 30 | * @since 1.0.0 31 | */ 32 | public class InMemoryServiceRegistry implements ServiceRegistry { 33 | 34 | private static final String STATUS_KEY = "_status_"; 35 | 36 | private final ConcurrentMap storage = new ConcurrentHashMap<>(1); 37 | 38 | @Override 39 | public void register(Registration registration) { 40 | String id = registration.getInstanceId(); 41 | storage.put(id, registration); 42 | } 43 | 44 | @Override 45 | public void deregister(Registration registration) { 46 | String id = registration.getInstanceId(); 47 | storage.remove(id, registration); 48 | } 49 | 50 | @Override 51 | public void close() { 52 | storage.clear(); 53 | } 54 | 55 | @Override 56 | public void setStatus(Registration registration, String status) { 57 | Map metadata = getMetadata(registration); 58 | if (metadata != null) { 59 | metadata.put(STATUS_KEY, status); 60 | } 61 | } 62 | 63 | @Override 64 | public Object getStatus(Registration registration) { 65 | Map metadata = getMetadata(registration); 66 | if (metadata != null) { 67 | return metadata.get(STATUS_KEY); 68 | } 69 | return null; 70 | } 71 | 72 | protected Map getMetadata(Registration registration) { 73 | String id = registration.getInstanceId(); 74 | Registration instance = storage.get(id); 75 | if (storage != null) { 76 | return instance.getMetadata(); 77 | } 78 | return null; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/MultipleAutoServiceRegistration.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.client.service.registry; 2 | 3 | import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration; 4 | import org.springframework.cloud.client.serviceregistry.AutoServiceRegistration; 5 | import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; 6 | import org.springframework.cloud.client.serviceregistry.ServiceRegistry; 7 | 8 | /** 9 | * {@link AutoServiceRegistration} for the multiple service registration 10 | * 11 | * @author 韩超 12 | * @author Mercy 13 | * @see AutoServiceRegistration 14 | * @see MultipleRegistration 15 | * @since 1.0.0 16 | */ 17 | public class MultipleAutoServiceRegistration extends AbstractAutoServiceRegistration { 18 | 19 | private final AutoServiceRegistrationProperties autoServiceRegistrationProperties; 20 | private final MultipleRegistration multipleRegistration; 21 | 22 | public MultipleAutoServiceRegistration(MultipleRegistration multipleRegistration, 23 | ServiceRegistry serviceRegistry, 24 | AutoServiceRegistrationProperties properties) { 25 | super(serviceRegistry, properties); 26 | this.autoServiceRegistrationProperties = properties; 27 | this.multipleRegistration = multipleRegistration; 28 | } 29 | 30 | @Override 31 | protected Object getConfiguration() { 32 | return null; 33 | } 34 | 35 | @Override 36 | protected boolean isEnabled() { 37 | return this.autoServiceRegistrationProperties.isEnabled(); 38 | } 39 | 40 | @Override 41 | protected MultipleRegistration getRegistration() { 42 | return this.multipleRegistration; 43 | } 44 | 45 | @Override 46 | protected MultipleRegistration getManagementRegistration() { 47 | return this.multipleRegistration; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/MultipleRegistration.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.client.service.registry; 2 | 3 | import org.springframework.cloud.client.serviceregistry.Registration; 4 | import org.springframework.util.CollectionUtils; 5 | 6 | import java.net.URI; 7 | import java.util.Collection; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | /** 12 | * The Delegating {@link Registration} for the multiple service registration 13 | * 14 | * @author 韩超 15 | * @see MultipleAutoServiceRegistration 16 | * @see MultipleServiceRegistry 17 | * @since 1.0.0 18 | */ 19 | public class MultipleRegistration implements Registration { 20 | 21 | private Map, Registration> registrationMap = new HashMap<>(); 22 | 23 | private Registration defaultRegistration; 24 | 25 | private final RegistrationMetaData metaData; 26 | 27 | public MultipleRegistration(Collection registrations) { 28 | if (CollectionUtils.isEmpty(registrations)) 29 | throw new IllegalArgumentException("registrations cannot be empty"); 30 | //init map 31 | for (Registration registration : registrations) { 32 | Class clazz = registration.getClass(); 33 | this.registrationMap.put(clazz, registration); 34 | this.defaultRegistration = registration; 35 | } 36 | this.metaData = new RegistrationMetaData(registrations); 37 | } 38 | 39 | @Override 40 | public String getServiceId() { 41 | return getDefaultRegistration().getServiceId(); 42 | } 43 | 44 | @Override 45 | public String getHost() { 46 | return getDefaultRegistration().getHost(); 47 | } 48 | 49 | @Override 50 | public int getPort() { 51 | return getDefaultRegistration().getPort(); 52 | } 53 | 54 | @Override 55 | public boolean isSecure() { 56 | return getDefaultRegistration().isSecure(); 57 | } 58 | 59 | @Override 60 | public URI getUri() { 61 | return getDefaultRegistration().getUri(); 62 | } 63 | 64 | @Override 65 | public Map getMetadata() { 66 | return metaData; 67 | } 68 | 69 | public Registration getDefaultRegistration() { 70 | return defaultRegistration; 71 | } 72 | 73 | public T special(Class specialClass) { 74 | if (specialClass.equals(Registration.class)) 75 | return (T) this; 76 | return (T) this.registrationMap.getOrDefault(specialClass, null); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/RegistrationCustomizer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.service.registry; 18 | 19 | import org.springframework.cloud.client.serviceregistry.Registration; 20 | 21 | /** 22 | * {@link Registration} Customizer 23 | * 24 | * @author Mercy 25 | * @see Registration 26 | * @since 1.0.0 27 | */ 28 | public interface RegistrationCustomizer { 29 | 30 | /** 31 | * Customize the specified {@link Registration} before register 32 | * 33 | * @param registration {@link Registration} 34 | */ 35 | void customize(Registration registration); 36 | } 37 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/RegistrationMetaData.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.client.service.registry; 2 | 3 | import org.springframework.cloud.client.serviceregistry.Registration; 4 | import org.springframework.util.CollectionUtils; 5 | 6 | import java.util.Collection; 7 | import java.util.Collections; 8 | import java.util.Map; 9 | import java.util.Set; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | 12 | /** 13 | * @author 韩超 14 | * @since 1.0.0 15 | */ 16 | public final class RegistrationMetaData implements Map { 17 | 18 | /** 19 | * MetaData information manually added by the application,usually specified by configuration 20 | */ 21 | private final Map applicationMetaData; 22 | private final Collection registrations; 23 | private final Object lock = new Object(); 24 | 25 | public RegistrationMetaData(Collection registrations) { 26 | if (CollectionUtils.isEmpty(registrations)) 27 | throw new IllegalArgumentException("registrations cannot be empty"); 28 | 29 | this.registrations = registrations; 30 | this.applicationMetaData = new ConcurrentHashMap<>(); 31 | for (Registration registration : registrations) { 32 | Map metaData = registration.getMetadata(); 33 | if (!CollectionUtils.isEmpty(metaData)) { 34 | //check key and value must not be null 35 | metaData.forEach((k, v) -> { 36 | if (k == null || v == null) 37 | return; 38 | this.applicationMetaData.put(k, v); 39 | }); 40 | } 41 | } 42 | } 43 | 44 | @Override 45 | public int size() { 46 | return applicationMetaData.size(); 47 | } 48 | 49 | @Override 50 | public boolean isEmpty() { 51 | return this.applicationMetaData.isEmpty(); 52 | } 53 | 54 | @Override 55 | public boolean containsKey(Object key) { 56 | return this.applicationMetaData.containsKey(key); 57 | } 58 | 59 | @Override 60 | public boolean containsValue(Object value) { 61 | return this.applicationMetaData.containsValue(value); 62 | } 63 | 64 | @Override 65 | public String get(Object key) { 66 | return this.applicationMetaData.get(key); 67 | } 68 | 69 | @Override 70 | public String put(String key, String value) { 71 | synchronized (lock) { 72 | this.registrations.forEach(registration -> { 73 | registration.getMetadata().put(key, value); 74 | }); 75 | } 76 | return this.applicationMetaData.put(key, value); 77 | } 78 | 79 | @Override 80 | public String remove(Object key) { 81 | synchronized (lock) { 82 | this.registrations.forEach(registration -> { 83 | registration.getMetadata().remove(key); 84 | }); 85 | } 86 | return this.applicationMetaData.remove(key); 87 | } 88 | 89 | @Override 90 | public void putAll(Map m) { 91 | synchronized (lock) { 92 | this.registrations.forEach(registration -> { 93 | registration.getMetadata().putAll(m); 94 | }); 95 | } 96 | this.applicationMetaData.putAll(m); 97 | } 98 | 99 | @Override 100 | public void clear() { 101 | synchronized (lock) { 102 | this.registrations.forEach(registration -> registration.getMetadata().clear()); 103 | } 104 | this.applicationMetaData.clear(); 105 | } 106 | 107 | @Override 108 | public Set keySet() { 109 | return Collections.unmodifiableSet(this.applicationMetaData.keySet()); 110 | } 111 | 112 | @Override 113 | public Collection values() { 114 | return Collections.unmodifiableCollection(this.applicationMetaData.values()); 115 | } 116 | 117 | @Override 118 | public Set> entrySet() { 119 | return this.applicationMetaData.entrySet(); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/SimpleAutoServiceRegistration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.service.registry; 18 | 19 | import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration; 20 | import org.springframework.cloud.client.serviceregistry.AutoServiceRegistration; 21 | import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; 22 | import org.springframework.cloud.client.serviceregistry.Registration; 23 | import org.springframework.cloud.client.serviceregistry.ServiceRegistry; 24 | 25 | /** 26 | * Default {@link AutoServiceRegistration} 27 | * 28 | * @author Mercy 29 | * @since 1.0.0 30 | */ 31 | public class SimpleAutoServiceRegistration extends AbstractAutoServiceRegistration { 32 | 33 | private final AutoServiceRegistrationProperties properties; 34 | 35 | private final Registration registration; 36 | 37 | protected SimpleAutoServiceRegistration(ServiceRegistry serviceRegistry, 38 | AutoServiceRegistrationProperties properties, Registration registration) { 39 | super(serviceRegistry, properties); 40 | this.properties = properties; 41 | this.registration = registration; 42 | } 43 | 44 | @Override 45 | protected Object getConfiguration() { 46 | return properties; 47 | } 48 | 49 | @Override 50 | protected boolean isEnabled() { 51 | return properties.isEnabled(); 52 | } 53 | 54 | @Override 55 | protected Registration getRegistration() { 56 | return registration; 57 | } 58 | 59 | @Override 60 | protected Registration getManagementRegistration() { 61 | return registration; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/actuate/autoconfigure/ServiceRegistrationEndpointAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.service.registry.actuate.autoconfigure; 18 | 19 | import io.microsphere.spring.cloud.client.service.registry.condition.ConditionalOnAutoServiceRegistrationEnabled; 20 | import io.microsphere.spring.cloud.client.service.registry.endpoint.ServiceDeregistrationEndpoint; 21 | import io.microsphere.spring.cloud.client.service.registry.endpoint.ServiceRegistrationEndpoint; 22 | import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint; 23 | import org.springframework.boot.actuate.endpoint.annotation.Endpoint; 24 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; 25 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 26 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 27 | import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled; 28 | import org.springframework.context.annotation.Bean; 29 | 30 | /** 31 | * Microsphere {@link Endpoint @Endpoints} Auto-Configuration for Service Registration 32 | * 33 | * @author Mercy 34 | * @see Endpoint 35 | * @since 1.0.0 36 | */ 37 | @ConditionalOnDiscoveryEnabled 38 | @ConditionalOnClass(name = { 39 | "org.springframework.boot.actuate.endpoint.annotation.Endpoint", 40 | "org.springframework.cloud.client.serviceregistry.AutoServiceRegistration" 41 | }) 42 | @ConditionalOnAutoServiceRegistrationEnabled 43 | @AutoConfigureAfter(name = { 44 | "org.springframework.cloud.client.serviceregistry.ServiceRegistryAutoConfiguration", 45 | "org.springframework.cloud.zookeeper.serviceregistry.ZookeeperServiceRegistryAutoConfiguration", 46 | "org.springframework.cloud.consul.serviceregistry.ConsulServiceRegistryAutoConfiguration", 47 | "org.springframework.cloud.kubernetes.discovery.KubernetesDiscoveryClientAutoConfiguration", 48 | "com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration", 49 | }) 50 | public class ServiceRegistrationEndpointAutoConfiguration { 51 | 52 | @Bean 53 | @ConditionalOnMissingBean 54 | @ConditionalOnAvailableEndpoint 55 | public ServiceRegistrationEndpoint serviceRegistrationEndpoint() { 56 | return new ServiceRegistrationEndpoint(); 57 | } 58 | 59 | @Bean 60 | @ConditionalOnMissingBean 61 | @ConditionalOnAvailableEndpoint 62 | public ServiceDeregistrationEndpoint serviceDeregistrationEndpoint() { 63 | return new ServiceDeregistrationEndpoint(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/aspect/EventPublishingRegistrationAspect.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.service.registry.aspect; 18 | 19 | import io.microsphere.spring.cloud.client.service.registry.MultipleServiceRegistry; 20 | import io.microsphere.spring.cloud.client.service.registry.RegistrationCustomizer; 21 | import io.microsphere.spring.cloud.client.service.registry.event.RegistrationDeregisteredEvent; 22 | import io.microsphere.spring.cloud.client.service.registry.event.RegistrationPreDeregisteredEvent; 23 | import io.microsphere.spring.cloud.client.service.registry.event.RegistrationPreRegisteredEvent; 24 | import io.microsphere.spring.cloud.client.service.registry.event.RegistrationRegisteredEvent; 25 | import org.aspectj.lang.annotation.After; 26 | import org.aspectj.lang.annotation.Aspect; 27 | import org.aspectj.lang.annotation.Before; 28 | import org.springframework.beans.BeansException; 29 | import org.springframework.beans.factory.ObjectProvider; 30 | import org.springframework.cloud.client.serviceregistry.Registration; 31 | import org.springframework.cloud.client.serviceregistry.ServiceRegistry; 32 | import org.springframework.context.ApplicationContext; 33 | import org.springframework.context.ApplicationContextAware; 34 | 35 | /** 36 | * Event-Publishing Aspect for {@link Registration}. 37 | * 38 | * @author Mercy 39 | * @see RegistrationPreRegisteredEvent 40 | * @see RegistrationRegisteredEvent 41 | * @see RegistrationPreDeregisteredEvent 42 | * @see RegistrationDeregisteredEvent 43 | * @since 1.0.0 44 | */ 45 | @Aspect 46 | public class EventPublishingRegistrationAspect implements ApplicationContextAware { 47 | 48 | /** 49 | * The pointcut expression for {@link ServiceRegistry#register(Registration)}. 50 | */ 51 | public static final String REGISTER_POINTCUT_EXPRESSION = "execution(* org.springframework.cloud.client.serviceregistry.ServiceRegistry.register(*)) && target(registry) && args(registration)"; 52 | 53 | /** 54 | * The pointcut expression for {@link ServiceRegistry#deregister(Registration)}. 55 | */ 56 | public static final String DEREGISTER_POINTCUT_EXPRESSION = "execution(* org.springframework.cloud.client.serviceregistry.ServiceRegistry.deregister(*)) && target(registry) && args(registration)"; 57 | 58 | private ApplicationContext context; 59 | 60 | private ObjectProvider registrationCustomizers; 61 | 62 | @Before(value = REGISTER_POINTCUT_EXPRESSION, argNames = "registry, registration") 63 | public void beforeRegister(ServiceRegistry registry, Registration registration) { 64 | if (registry.getClass().isAssignableFrom(MultipleServiceRegistry.class)) 65 | return;//Remove redundant register 66 | context.publishEvent(new RegistrationPreRegisteredEvent(registry, registration)); 67 | registrationCustomizers.forEach(customizer -> { 68 | customizer.customize(registration); 69 | }); 70 | } 71 | 72 | @Before(value = DEREGISTER_POINTCUT_EXPRESSION, argNames = "registry, registration") 73 | public void beforeDeregister(ServiceRegistry registry, Registration registration) { 74 | if (registry.getClass().isAssignableFrom(MultipleServiceRegistry.class)) 75 | return;//Remove redundant deregister 76 | context.publishEvent(new RegistrationPreDeregisteredEvent(registry, registration)); 77 | } 78 | 79 | @After(value = REGISTER_POINTCUT_EXPRESSION, argNames = "registry, registration") 80 | public void afterRegister(ServiceRegistry registry, Registration registration) { 81 | if (registry.getClass().isAssignableFrom(MultipleServiceRegistry.class)) 82 | return;//Remove redundant register 83 | context.publishEvent(new RegistrationRegisteredEvent(registry, registration)); 84 | } 85 | 86 | @After(value = DEREGISTER_POINTCUT_EXPRESSION, argNames = "registry, registration") 87 | public void afterDeregister(ServiceRegistry registry, Registration registration) { 88 | if (registry.getClass().isAssignableFrom(MultipleServiceRegistry.class)) 89 | return;//Remove redundant deregister 90 | context.publishEvent(new RegistrationDeregisteredEvent(registry, registration)); 91 | } 92 | 93 | @Override 94 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 95 | this.context = applicationContext; 96 | this.registrationCustomizers = applicationContext.getBeanProvider(RegistrationCustomizer.class); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/autoconfigure/ServiceRegistryAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.service.registry.autoconfigure; 18 | 19 | import io.microsphere.spring.cloud.client.service.registry.MultipleAutoServiceRegistration; 20 | import io.microsphere.spring.cloud.client.service.registry.MultipleRegistration; 21 | import io.microsphere.spring.cloud.client.service.registry.MultipleServiceRegistry; 22 | import io.microsphere.spring.cloud.client.service.registry.aspect.EventPublishingRegistrationAspect; 23 | import io.microsphere.spring.cloud.client.service.registry.condition.ConditionalOnAutoServiceRegistrationEnabled; 24 | import io.microsphere.spring.cloud.client.service.registry.condition.ConditionalOnMultipleRegistrationEnabled; 25 | import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; 26 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 27 | import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; 28 | import org.springframework.cloud.client.serviceregistry.Registration; 29 | import org.springframework.cloud.client.serviceregistry.ServiceRegistry; 30 | import org.springframework.context.annotation.Bean; 31 | import org.springframework.context.annotation.Configuration; 32 | import org.springframework.context.annotation.Import; 33 | import org.springframework.context.annotation.Primary; 34 | 35 | import java.util.Collection; 36 | import java.util.Map; 37 | 38 | /** 39 | * Auto-Configuration class for {@link ServiceRegistry ServiceRegistry} 40 | * 41 | * @author Mercy 42 | * @since 1.0.0 43 | */ 44 | @Configuration(proxyBeanMethods = false) 45 | @ConditionalOnAutoServiceRegistrationEnabled 46 | @Import(value = { 47 | EventPublishingRegistrationAspect.class, 48 | ServiceRegistryAutoConfiguration.MultipleConfiguration.class 49 | }) 50 | public class ServiceRegistryAutoConfiguration { 51 | 52 | /** 53 | * The configuration class of the multiple service registration 54 | */ 55 | @ConditionalOnMultipleRegistrationEnabled 56 | static class MultipleConfiguration { 57 | 58 | @Primary 59 | @Bean 60 | @ConditionalOnMissingBean 61 | public MultipleRegistration multipleRegistration(Collection registrations) { 62 | return new MultipleRegistration(registrations); 63 | } 64 | 65 | @Bean 66 | @Primary 67 | @ConditionalOnMissingBean 68 | public MultipleServiceRegistry multipleServiceRegistry(Map registriesMap) { 69 | return new MultipleServiceRegistry(registriesMap); 70 | } 71 | 72 | @ConditionalOnBean(AutoServiceRegistrationProperties.class) 73 | @Primary 74 | @Bean 75 | @ConditionalOnMissingBean 76 | public MultipleAutoServiceRegistration multipleAutoServiceRegistration(MultipleRegistration multipleRegistration, 77 | MultipleServiceRegistry multipleServiceRegistry, 78 | AutoServiceRegistrationProperties properties) { 79 | return new MultipleAutoServiceRegistration(multipleRegistration, multipleServiceRegistry, properties); 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/autoconfigure/SimpleAutoServiceRegistrationAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.service.registry.autoconfigure; 18 | 19 | import io.microsphere.spring.cloud.client.service.registry.DefaultRegistration; 20 | import io.microsphere.spring.cloud.client.service.registry.InMemoryServiceRegistry; 21 | import io.microsphere.spring.cloud.client.service.registry.SimpleAutoServiceRegistration; 22 | import io.microsphere.spring.cloud.client.service.registry.condition.ConditionalOnAutoServiceRegistrationEnabled; 23 | import org.springframework.beans.factory.annotation.Value; 24 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; 25 | import org.springframework.boot.autoconfigure.AutoConfigureBefore; 26 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 27 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 28 | import org.springframework.boot.autoconfigure.web.ServerProperties; 29 | import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration; 30 | import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration; 31 | import org.springframework.cloud.client.serviceregistry.Registration; 32 | import org.springframework.cloud.client.serviceregistry.ServiceRegistry; 33 | import org.springframework.cloud.commons.util.InetUtils; 34 | import org.springframework.cloud.commons.util.UtilAutoConfiguration; 35 | import org.springframework.context.annotation.Bean; 36 | import org.springframework.context.annotation.Configuration; 37 | import org.springframework.context.annotation.Import; 38 | 39 | import static io.microsphere.constants.PropertyConstants.ENABLED_PROPERTY_NAME; 40 | import static io.microsphere.spring.cloud.client.service.registry.autoconfigure.SimpleAutoServiceRegistrationAutoConfiguration.PROPERTY_NAME_PREFIX; 41 | import static io.microsphere.spring.cloud.commons.constants.CommonsPropertyConstants.MICROSPHERE_SPRING_CLOUD_PROPERTY_NAME_PREFIX; 42 | 43 | /** 44 | * Auto-Configuration class for {@link SimpleAutoServiceRegistration} 45 | * 46 | * @author Mercy 47 | * @see SimpleAutoServiceRegistration 48 | * @since 1.0.0 49 | */ 50 | @Configuration(proxyBeanMethods = false) 51 | @ConditionalOnProperty(prefix = PROPERTY_NAME_PREFIX, name = ENABLED_PROPERTY_NAME) 52 | @ConditionalOnAutoServiceRegistrationEnabled 53 | @AutoConfigureBefore(value = { 54 | AutoServiceRegistrationAutoConfiguration.class 55 | }) 56 | @AutoConfigureAfter(value = { 57 | UtilAutoConfiguration.class, 58 | AutoServiceRegistrationConfiguration.class 59 | }) 60 | @Import(value = { 61 | SimpleAutoServiceRegistration.class 62 | }) 63 | public class SimpleAutoServiceRegistrationAutoConfiguration { 64 | 65 | /** 66 | * The property name prefix : "microsphere.spring.cloud.service-registry.auto-registration.simple." 67 | */ 68 | public static final String PROPERTY_NAME_PREFIX = MICROSPHERE_SPRING_CLOUD_PROPERTY_NAME_PREFIX + "service-registry.auto-registration.simple."; 69 | 70 | @Bean 71 | public Registration registration( 72 | @Value("${spring.application.name:default}") String applicationName, 73 | ServerProperties serverProperties, 74 | InetUtils inetUtils 75 | ) { 76 | InetUtils.HostInfo hostInfo = inetUtils.findFirstNonLoopbackHostInfo(); 77 | String host = hostInfo.getIpAddress(); 78 | int port = serverProperties.getPort(); 79 | String instanceId = host + ":" + port; 80 | DefaultRegistration registration = new DefaultRegistration(); 81 | registration.setInstanceId(instanceId); 82 | registration.setServiceId(applicationName); 83 | registration.setHost(host); 84 | registration.setPort(serverProperties.getPort()); 85 | return registration; 86 | } 87 | 88 | @Bean 89 | @ConditionalOnMissingBean 90 | public ServiceRegistry serviceRegistry() { 91 | return new InMemoryServiceRegistry(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/autoconfigure/WebFluxServiceRegistryAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.service.registry.autoconfigure; 18 | 19 | import io.microsphere.spring.cloud.client.service.registry.condition.ConditionalOnAutoServiceRegistrationEnabled; 20 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; 21 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; 23 | import org.springframework.cloud.client.serviceregistry.ServiceRegistry; 24 | import org.springframework.context.annotation.Configuration; 25 | 26 | import static org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type.REACTIVE; 27 | 28 | /** 29 | * Auto-Configuration class for {@link ServiceRegistry ServiceRegistry} on the Spring WebFlux Application 30 | * 31 | * @author Mercy 32 | * @since 1.0.0 33 | */ 34 | @Configuration(proxyBeanMethods = false) 35 | @ConditionalOnClass(name = { 36 | "io.microsphere.spring.web.metadata.WebEndpointMapping", 37 | "io.microsphere.spring.web.event.WebEndpointMappingsReadyEvent" 38 | }) 39 | @ConditionalOnWebApplication(type = REACTIVE) 40 | @ConditionalOnAutoServiceRegistrationEnabled 41 | @AutoConfigureAfter(value = { 42 | ServiceRegistryAutoConfiguration.class 43 | }) 44 | public class WebFluxServiceRegistryAutoConfiguration { 45 | } 46 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/condition/ConditionalOnAutoServiceRegistrationEnabled.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.service.registry.condition; 18 | 19 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 20 | import org.springframework.cloud.client.serviceregistry.AutoServiceRegistration; 21 | import org.springframework.core.annotation.AliasFor; 22 | 23 | import java.lang.annotation.Documented; 24 | import java.lang.annotation.ElementType; 25 | import java.lang.annotation.Retention; 26 | import java.lang.annotation.RetentionPolicy; 27 | import java.lang.annotation.Target; 28 | 29 | import static io.microsphere.spring.cloud.commons.constants.CommonsPropertyConstants.SERVICE_REGISTRY_AUTO_REGISTRATION_ENABLED_PROPERTY_NAME; 30 | 31 | /** 32 | * The conditional annotation meta-annotates {@link ConditionalOnProperty @ConditionalOnProperty} for 33 | * {@link AutoServiceRegistration Service Registry Auto-Registration} enabled. 34 | * 35 | * @author Mercy 36 | * @see AutoServiceRegistration 37 | * @see ConditionalOnProperty 38 | * @since 1.0.0 39 | */ 40 | @Retention(RetentionPolicy.RUNTIME) 41 | @Target({ElementType.TYPE, ElementType.METHOD}) 42 | @Documented 43 | @ConditionalOnProperty(name = SERVICE_REGISTRY_AUTO_REGISTRATION_ENABLED_PROPERTY_NAME) 44 | public @interface ConditionalOnAutoServiceRegistrationEnabled { 45 | 46 | /** 47 | * Specify if the condition should match if the property is not set. Defaults to 48 | * {@code true}. 49 | * 50 | * @return if the condition should match if the property is missing 51 | */ 52 | @AliasFor(annotation = ConditionalOnProperty.class, attribute = "matchIfMissing") 53 | boolean matchIfMissing() default true; 54 | } 55 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/condition/ConditionalOnMultipleRegistrationEnabled.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.client.service.registry.condition; 2 | 3 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 4 | import org.springframework.context.annotation.Conditional; 5 | 6 | import java.lang.annotation.Documented; 7 | import java.lang.annotation.ElementType; 8 | import java.lang.annotation.Retention; 9 | import java.lang.annotation.RetentionPolicy; 10 | import java.lang.annotation.Target; 11 | 12 | import static io.microsphere.spring.cloud.commons.constants.CommonsPropertyConstants.MULTIPLE_REGISTRATION_ENABLED_PROPERTY_NAME; 13 | 14 | /** 15 | * {@link Conditional @Conditional} that checks whether the multiple service registry enabled 16 | * 17 | * @author 韩超 18 | * @author Mercy 19 | * @since 1.0 20 | */ 21 | @Retention(RetentionPolicy.RUNTIME) 22 | @Target({ElementType.TYPE, ElementType.METHOD}) 23 | @Documented 24 | @ConditionalOnProperty(name = MULTIPLE_REGISTRATION_ENABLED_PROPERTY_NAME) 25 | public @interface ConditionalOnMultipleRegistrationEnabled { 26 | 27 | } 28 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/constants/InstanceConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.service.registry.constants; 18 | 19 | /** 20 | * The constants for Service Instance 21 | * 22 | * @author Mercy 23 | * @since 1.0.0 24 | */ 25 | public interface InstanceConstants { 26 | 27 | /** 28 | * The meta-data name of Web Mappings 29 | */ 30 | String WEB_MAPPINGS_METADATA_NAME = "web.mappings"; 31 | 32 | /** 33 | * The meta-data name of Web Context Path 34 | */ 35 | String WEB_CONTEXT_PATH_METADATA_NAME = "web.context-path"; 36 | } 37 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/endpoint/AbstractServiceRegistrationEndpoint.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.client.service.registry.endpoint; 2 | 3 | import org.springframework.beans.factory.ObjectProvider; 4 | import org.springframework.beans.factory.SmartInitializingSingleton; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.boot.web.context.WebServerInitializedEvent; 8 | import org.springframework.boot.web.server.WebServer; 9 | import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration; 10 | import org.springframework.cloud.client.serviceregistry.Registration; 11 | import org.springframework.cloud.client.serviceregistry.ServiceRegistry; 12 | import org.springframework.context.ApplicationListener; 13 | 14 | /** 15 | * Abstract Endpoint for Service Registration 16 | * 17 | * @author Mercy 18 | * @since 1.0.0 19 | */ 20 | public class AbstractServiceRegistrationEndpoint implements SmartInitializingSingleton, ApplicationListener { 21 | 22 | @Value("${spring.application.name}") 23 | protected String applicationName; 24 | 25 | @Autowired 26 | private ObjectProvider registrationProvider; 27 | 28 | @Autowired 29 | private ObjectProvider serviceRegistryProvider; 30 | 31 | @Autowired 32 | private ObjectProvider autoServiceRegistrationProvider; 33 | 34 | protected Registration registration; 35 | 36 | protected ServiceRegistry serviceRegistry; 37 | 38 | protected AbstractAutoServiceRegistration serviceRegistration; 39 | 40 | protected int port; 41 | 42 | protected static boolean running; 43 | 44 | @Override 45 | public void afterSingletonsInstantiated() { 46 | this.registration = registrationProvider.getIfAvailable(); 47 | this.serviceRegistry = serviceRegistryProvider.getIfAvailable(); 48 | this.serviceRegistration = autoServiceRegistrationProvider.getIfAvailable(); 49 | } 50 | 51 | @Override 52 | public void onApplicationEvent(WebServerInitializedEvent event) { 53 | WebServer webServer = event.getWebServer(); 54 | this.port = webServer.getPort(); 55 | this.running = serviceRegistration == null ? true : serviceRegistration.isRunning(); 56 | } 57 | 58 | protected boolean isRunning() { 59 | return running; 60 | } 61 | 62 | public void setRunning(boolean running) { 63 | this.running = running; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/endpoint/ServiceDeregistrationEndpoint.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.client.service.registry.endpoint; 2 | 3 | import io.microsphere.logging.Logger; 4 | import io.microsphere.logging.LoggerFactory; 5 | import org.springframework.boot.actuate.endpoint.annotation.Endpoint; 6 | import org.springframework.boot.actuate.endpoint.annotation.WriteOperation; 7 | import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration; 8 | 9 | /** 10 | * The {@link Endpoint @Endpoint} for Service Deregistration 11 | * 12 | * @author Mercy 13 | * @see AbstractAutoServiceRegistration 14 | * @see Endpoint 15 | * @since 1.0.0 16 | */ 17 | @Endpoint(id = "serviceDeregistration") 18 | public class ServiceDeregistrationEndpoint extends AbstractServiceRegistrationEndpoint { 19 | 20 | private final Logger logger = LoggerFactory.getLogger(getClass()); 21 | 22 | @WriteOperation 23 | public boolean stop() { 24 | boolean isRunning = isRunning(); 25 | if (isRunning) { 26 | serviceRegistry.deregister(registration); 27 | if(logger.isInfoEnabled()) { 28 | logger.info("Service[name : '{}'] is deregistered!", applicationName); 29 | } 30 | setRunning(false); 31 | } else { 32 | if (logger.isWarnEnabled()) { 33 | logger.warn("Service[name : '{}'] is not registered, deregistration can't be executed!", applicationName); 34 | } 35 | } 36 | return isRunning; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/endpoint/ServiceRegistrationEndpoint.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.client.service.registry.endpoint; 2 | 3 | import io.microsphere.logging.Logger; 4 | import io.microsphere.logging.LoggerFactory; 5 | import org.springframework.boot.actuate.endpoint.annotation.Endpoint; 6 | import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; 7 | import org.springframework.boot.actuate.endpoint.annotation.WriteOperation; 8 | import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration; 9 | import org.springframework.util.ReflectionUtils; 10 | 11 | import java.lang.reflect.Method; 12 | import java.util.LinkedHashMap; 13 | import java.util.Map; 14 | 15 | /** 16 | * The {@link Endpoint @Endpoint} for Service Registration 17 | * 18 | * @author Mercy 19 | * @see AbstractAutoServiceRegistration 20 | * @see Endpoint 21 | * @since 1.0.0 22 | */ 23 | @Endpoint(id = "serviceRegistration") 24 | public class ServiceRegistrationEndpoint extends AbstractServiceRegistrationEndpoint { 25 | 26 | private final Logger logger = LoggerFactory.getLogger(getClass()); 27 | 28 | @ReadOperation 29 | public Map metadata() { 30 | 31 | Map metadata = new LinkedHashMap<>(); 32 | 33 | metadata.put("application-name", applicationName); 34 | metadata.put("registration", registration); 35 | metadata.put("port", port); 36 | metadata.put("status", serviceRegistry.getStatus(registration)); 37 | metadata.put("running", isRunning()); 38 | 39 | if (serviceRegistration != null) { 40 | metadata.put("enabled", invoke("isEnabled")); 41 | metadata.put("phase", serviceRegistration.getPhase()); 42 | metadata.put("order", serviceRegistration.getOrder()); 43 | if (Boolean.TRUE.equals(invoke("shouldRegisterManagement"))) { 44 | metadata.put("managementRegistration", invoke("getManagementRegistration")); 45 | } 46 | metadata.put("config", invoke("getConfiguration")); 47 | } 48 | 49 | return metadata; 50 | } 51 | 52 | @WriteOperation 53 | public boolean start() { 54 | boolean isRunning = isRunning(); 55 | if (!isRunning) { 56 | serviceRegistry.register(registration); 57 | setRunning(true); 58 | if(logger.isTraceEnabled()) { 59 | logger.trace("Service[name : '{}'] is registered!", applicationName); 60 | } 61 | } else { 62 | if(logger.isWarnEnabled()) { 63 | logger.warn("Service[name : '{}'] was registered!", applicationName); 64 | } 65 | } 66 | return isRunning; 67 | } 68 | 69 | private Object invoke(String methodName) { 70 | Object returnValue = null; 71 | try { 72 | Class serviceRegistrationClass = AbstractAutoServiceRegistration.class; 73 | Method method = serviceRegistrationClass.getDeclaredMethod(methodName); 74 | ReflectionUtils.makeAccessible(method); 75 | returnValue = method.invoke(serviceRegistration); 76 | } catch (Throwable e) { 77 | logger.error("Invocation on method :" + methodName + "is failed", e); 78 | } 79 | return returnValue; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/event/RegistrationDeregisteredEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.service.registry.event; 18 | 19 | import org.springframework.cloud.client.serviceregistry.Registration; 20 | import org.springframework.cloud.client.serviceregistry.ServiceRegistry; 21 | 22 | import static io.microsphere.spring.cloud.client.service.registry.event.RegistrationEvent.Type.DEREGISTERED; 23 | 24 | /** 25 | * The after-{@link ServiceRegistry#deregister(Registration) deregister} event. 26 | * 27 | * @author Mercy 28 | * @see ServiceRegistry 29 | * @since 1.0.0 30 | */ 31 | public class RegistrationDeregisteredEvent extends RegistrationEvent { 32 | 33 | public RegistrationDeregisteredEvent(ServiceRegistry registry, Registration source) { 34 | super(registry, source); 35 | } 36 | 37 | @Override 38 | public Type getType() { 39 | return DEREGISTERED; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/event/RegistrationPreDeregisteredEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.service.registry.event; 18 | 19 | import org.springframework.cloud.client.serviceregistry.Registration; 20 | import org.springframework.cloud.client.serviceregistry.ServiceRegistry; 21 | 22 | import static io.microsphere.spring.cloud.client.service.registry.event.RegistrationEvent.Type.PRE_DEREGISTERED; 23 | 24 | /** 25 | * The before-{@link ServiceRegistry#deregister(Registration) deregister} event. 26 | * 27 | * @author Mercy 28 | * @see ServiceRegistry 29 | * @since 1.0.0 30 | */ 31 | public class RegistrationPreDeregisteredEvent extends RegistrationEvent { 32 | 33 | public RegistrationPreDeregisteredEvent(ServiceRegistry registry, Registration source) { 34 | super(registry, source); 35 | } 36 | 37 | @Override 38 | public Type getType() { 39 | return PRE_DEREGISTERED; 40 | } 41 | } -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/event/RegistrationPreRegisteredEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.service.registry.event; 18 | 19 | import org.springframework.cloud.client.serviceregistry.Registration; 20 | import org.springframework.cloud.client.serviceregistry.ServiceRegistry; 21 | 22 | import static io.microsphere.spring.cloud.client.service.registry.event.RegistrationEvent.Type.PRE_REGISTERED; 23 | 24 | /** 25 | * The before-{@link ServiceRegistry#register(Registration) register} event. 26 | * 27 | * @author Mercy 28 | * @see ServiceRegistry 29 | * @since 1.0.0 30 | */ 31 | public class RegistrationPreRegisteredEvent extends RegistrationEvent { 32 | 33 | public RegistrationPreRegisteredEvent(ServiceRegistry registry, Registration source) { 34 | super(registry, source); 35 | } 36 | 37 | @Override 38 | public Type getType() { 39 | return PRE_REGISTERED; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/registry/event/RegistrationRegisteredEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.service.registry.event; 18 | 19 | import org.springframework.cloud.client.serviceregistry.Registration; 20 | import org.springframework.cloud.client.serviceregistry.ServiceRegistry; 21 | 22 | import static io.microsphere.spring.cloud.client.service.registry.event.RegistrationEvent.Type.REGISTERED; 23 | 24 | /** 25 | * The after-{@link ServiceRegistry#register(Registration) register} event. 26 | * 27 | * @author Mercy 28 | * @see ServiceRegistry 29 | * @since 1.0.0 30 | */ 31 | public class RegistrationRegisteredEvent extends RegistrationEvent { 32 | 33 | public RegistrationRegisteredEvent(ServiceRegistry registry, Registration source) { 34 | super(registry, source); 35 | } 36 | 37 | @Override 38 | public Type getType() { 39 | return REGISTERED; 40 | } 41 | } -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/client/service/util/ServiceInstanceUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.service.util; 18 | 19 | import com.fasterxml.jackson.core.type.TypeReference; 20 | import com.fasterxml.jackson.databind.ObjectMapper; 21 | import io.microsphere.logging.Logger; 22 | import io.microsphere.logging.LoggerFactory; 23 | import io.microsphere.spring.web.metadata.WebEndpointMapping; 24 | import io.microsphere.util.BaseUtils; 25 | import org.springframework.cloud.client.ServiceInstance; 26 | 27 | import java.util.Collection; 28 | import java.util.Collections; 29 | import java.util.List; 30 | import java.util.Map; 31 | import java.util.StringJoiner; 32 | 33 | import static io.microsphere.net.URLUtils.decode; 34 | import static io.microsphere.net.URLUtils.encode; 35 | import static io.microsphere.spring.cloud.client.service.registry.constants.InstanceConstants.WEB_CONTEXT_PATH_METADATA_NAME; 36 | import static io.microsphere.spring.cloud.client.service.registry.constants.InstanceConstants.WEB_MAPPINGS_METADATA_NAME; 37 | 38 | /** 39 | * {@link ServiceInstance} Utilities class 40 | * 41 | * @author Mercy 42 | * @since 1.0.0 43 | */ 44 | public class ServiceInstanceUtils extends BaseUtils { 45 | 46 | private static final Logger logger = LoggerFactory.getLogger(ServiceInstanceUtils.class); 47 | 48 | public static void attachMetadata(String contextPath, ServiceInstance serviceInstance, Collection webEndpointMappings) { 49 | Map metadata = serviceInstance.getMetadata(); 50 | StringJoiner jsonBuilder = new StringJoiner(",", "[", "]"); 51 | webEndpointMappings.stream().map(WebEndpointMapping::toJSON).forEach(jsonBuilder::add); 52 | String json = jsonBuilder.toString(); 53 | metadata.put(WEB_CONTEXT_PATH_METADATA_NAME, contextPath); 54 | try { 55 | String encodedJson = encode(json); 56 | metadata.put(WEB_MAPPINGS_METADATA_NAME, encodedJson); 57 | } catch (IllegalArgumentException e) { 58 | logger.error("The JSON content of WebEndpointMappings can't be encoded : {}", json, e); 59 | } 60 | } 61 | 62 | public static Collection getWebEndpointMappings(ServiceInstance serviceInstance) { 63 | List webEndpointMappings = Collections.emptyList(); 64 | Map metadata = serviceInstance.getMetadata(); 65 | String encodedJSON = metadata.get(WEB_MAPPINGS_METADATA_NAME); 66 | if (encodedJSON != null) { 67 | try { 68 | String json = decode(encodedJSON); 69 | ObjectMapper objectMapper = new ObjectMapper(); 70 | webEndpointMappings = objectMapper.readValue(json, new TypeReference>() { 71 | }); 72 | } catch (Throwable e) { 73 | logger.error("The encoded JSON content of WebEndpointMappings can't be parsed : {}", encodedJSON, e); 74 | } 75 | } 76 | return webEndpointMappings; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/commons/constants/CommonsPropertyConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.commons.constants; 18 | 19 | import org.springframework.cloud.client.CommonsClientAutoConfiguration; 20 | import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration; 21 | 22 | import static io.microsphere.constants.PropertyConstants.ENABLED_PROPERTY_NAME; 23 | import static io.microsphere.constants.PropertyConstants.MICROSPHERE_PROPERTY_NAME_PREFIX; 24 | 25 | /** 26 | * The property constants for Spring Cloud Commons 27 | * 28 | * @author Mercy 29 | * @since 1.0.0 30 | */ 31 | public interface CommonsPropertyConstants { 32 | 33 | /** 34 | * The property name prefix of Spring Cloud properties : "spring.cloud." 35 | */ 36 | String SPRING_CLOUD_PROPERTY_PREFIX = "spring.cloud."; 37 | 38 | /** 39 | * The property name prefix of Spring Cloud Service Registry : "spring.cloud.service-registry." 40 | */ 41 | String SERVICE_REGISTRY_PROPERTY_PREFIX = SPRING_CLOUD_PROPERTY_PREFIX + "service-registry."; 42 | 43 | /** 44 | * The property name for Spring Cloud Service Registry Auto-Registration Feature : 45 | * "spring.cloud.service-registry.auto-registration.enabled" 46 | * 47 | * @see AutoServiceRegistrationAutoConfiguration 48 | */ 49 | String SERVICE_REGISTRY_AUTO_REGISTRATION_ENABLED_PROPERTY_NAME = SERVICE_REGISTRY_PROPERTY_PREFIX + "auto-registration." + ENABLED_PROPERTY_NAME; 50 | 51 | /** 52 | * The property name for enabling Spring Cloud Features : "spring.cloud.features.enabled" 53 | * 54 | * @see CommonsClientAutoConfiguration.ActuatorConfiguration 55 | */ 56 | String FEATURES_ENABLED_PROPERTY_NAME = SPRING_CLOUD_PROPERTY_PREFIX + "features." + ENABLED_PROPERTY_NAME; 57 | 58 | /** 59 | * The property name prefix of Microsphere Cloud : "microsphere.spring.cloud." 60 | */ 61 | String MICROSPHERE_SPRING_CLOUD_PROPERTY_NAME_PREFIX = MICROSPHERE_PROPERTY_NAME_PREFIX + SPRING_CLOUD_PROPERTY_PREFIX; 62 | 63 | /** 64 | * The property name prefix of Microsphere Cloud Web MVC : "microsphere.spring.cloud.web.mvc." 65 | */ 66 | String MICROSPHERE_SPRING_CLOUD_WEB_MVC_PROPERTY_NAME_PREFIX = MICROSPHERE_SPRING_CLOUD_PROPERTY_NAME_PREFIX + "web.mvc."; 67 | 68 | /** 69 | * The property name for Multiple Service Registry Enabled Feature : "microsphere.spring.cloud.multiple-registration.enabled" 70 | */ 71 | String MULTIPLE_REGISTRATION_ENABLED_PROPERTY_NAME = MICROSPHERE_SPRING_CLOUD_PROPERTY_NAME_PREFIX + "multiple-registration." + ENABLED_PROPERTY_NAME; 72 | 73 | /** 74 | * The property name for Default Service Registry Type : "microsphere.spring.cloud.default-registration.type" 75 | */ 76 | String MULTIPLE_REGISTRATION_DEFAULT_REGISTRATION_PROPERTY_NAME = MICROSPHERE_SPRING_CLOUD_PROPERTY_NAME_PREFIX + "default-registration.type"; 77 | 78 | /** 79 | * The property name for Default Service Registry Type : "microsphere.spring.cloud.default-service-registry.type" 80 | */ 81 | String MULTIPLE_REGISTRATION_DEFAULT_REGISTRY_PROPERTY_NAME = MICROSPHERE_SPRING_CLOUD_PROPERTY_NAME_PREFIX + "default-service-registry.type"; 82 | 83 | /** 84 | * The property name for Composite Service Registry Enabled Feature : "microsphere.spring.cloud.composite-registration.enabled" 85 | */ 86 | String COMPOSITE_REGISTRATION_ENABLED_PROPERTY_NAME = MICROSPHERE_SPRING_CLOUD_PROPERTY_NAME_PREFIX + "composite-registration." + ENABLED_PROPERTY_NAME; 87 | 88 | } 89 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/fault/tolerance/constants/FaultTolerancePropertyConstants.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.fault.tolerance.constants; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import static io.microsphere.spring.cloud.commons.constants.CommonsPropertyConstants.MICROSPHERE_SPRING_CLOUD_PROPERTY_NAME_PREFIX; 6 | 7 | /** 8 | * Fault-Tolerance Property Constants 9 | * 10 | * @author Mercy 11 | * @since 1.0.0 12 | */ 13 | public interface FaultTolerancePropertyConstants { 14 | 15 | /** 16 | * Property name prefix 17 | */ 18 | String FAULT_TOLERANCE_PROPERTY_NAME_PREFIX = MICROSPHERE_SPRING_CLOUD_PROPERTY_NAME_PREFIX + "fault-tolerance."; 19 | 20 | /** 21 | * Load Balancers' property name prefix 22 | */ 23 | String LOAD_BALANCER_PROPERTY_PREFIX = FAULT_TOLERANCE_PROPERTY_NAME_PREFIX + "load-balancer."; 24 | 25 | /** 26 | * The metadata name of management 27 | */ 28 | String MANAGEMENT_PORT_METADATA_NAME = "management-port"; 29 | 30 | /** 31 | * The metadata name of start time 32 | */ 33 | String START_TIME_METADATA_NAME = "start-time"; 34 | 35 | /** 36 | * The metadata name of warm-up time 37 | */ 38 | String WARMUP_TIME_PROPERTY_NAME = FAULT_TOLERANCE_PROPERTY_NAME_PREFIX + "warmup-time"; 39 | 40 | /** 41 | * The property name of weight 42 | */ 43 | String WEIGHT_PROPERTY_NAME = FAULT_TOLERANCE_PROPERTY_NAME_PREFIX + "weight"; 44 | 45 | /** 46 | * The default property value of warm-up time :10 minutes 47 | */ 48 | long DEFAULT_WARMUP_TIME_PROPERTY_VALUE = TimeUnit.MINUTES.toMillis(10); 49 | 50 | /** 51 | * The default property value of weight : 100 52 | */ 53 | int DEFAULT_WEIGHT_PROPERTY_VALUE = 100; 54 | 55 | } 56 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/fault/tolerance/loadbalancer/WeightedRoundRobin.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.fault.tolerance.loadbalancer; 2 | 3 | import java.util.StringJoiner; 4 | import java.util.concurrent.atomic.LongAdder; 5 | 6 | /** 7 | * Weighed Round-Robin 8 | * 9 | * @author Mercy 10 | * @since 1.0.0 11 | */ 12 | public class WeightedRoundRobin { 13 | 14 | private final String id; 15 | 16 | private volatile int weight; 17 | 18 | private LongAdder current = new LongAdder(); 19 | 20 | private volatile long lastUpdate; 21 | 22 | public WeightedRoundRobin(String id) { 23 | this.id = id; 24 | } 25 | 26 | public String getId() { 27 | return id; 28 | } 29 | 30 | public int getWeight() { 31 | return weight; 32 | } 33 | 34 | public void setWeight(int weight) { 35 | this.weight = weight; 36 | current.reset(); 37 | } 38 | 39 | public long increaseCurrent() { 40 | current.add(weight); 41 | return current.longValue(); 42 | } 43 | 44 | public void sel(int total) { 45 | current.add(-1 * total); 46 | } 47 | 48 | public long getLastUpdate() { 49 | return lastUpdate; 50 | } 51 | 52 | public void setLastUpdate(long lastUpdate) { 53 | this.lastUpdate = lastUpdate; 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return new StringJoiner(", ", WeightedRoundRobin.class.getSimpleName() + "[", "]") 59 | .add("id='" + id + "'") 60 | .add("weight=" + weight) 61 | .add("current=" + current) 62 | .add("lastUpdate=" + lastUpdate) 63 | .toString(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/fault/tolerance/loadbalancer/util/LoadBalancerUtils.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.fault.tolerance.loadbalancer.util; 2 | 3 | /** 4 | * The utilities class of Load Balancer 5 | * 6 | * @author Mercy 7 | * @since 1.0.0 8 | */ 9 | public abstract class LoadBalancerUtils { 10 | 11 | private LoadBalancerUtils() { 12 | throw new UnsupportedOperationException(); 13 | } 14 | 15 | /** 16 | * Calculate the weight according to the uptime proportion of warmup time 17 | * the new weight will be within 1(inclusive) to weight(inclusive) 18 | * 19 | * @param uptime the uptime in milliseconds 20 | * @param warmup the warmup time in milliseconds 21 | * @param weight the weight of an invoker 22 | * @return weight which takes warmup into account 23 | */ 24 | public static int calculateWarmupWeight(long uptime, long warmup, int weight) { 25 | int ww = (int) (Math.round(Math.pow((uptime / (double) warmup), 2) * weight)); 26 | return ww < 1 ? 1 : (Math.min(ww, weight)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/java/io/microsphere/spring/cloud/fault/tolerance/tomcat/autoconfigure/TomcatFaultToleranceAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.fault.tolerance.tomcat.autoconfigure; 18 | 19 | import io.microsphere.spring.cloud.fault.tolerance.constants.FaultTolerancePropertyConstants; 20 | import io.microsphere.spring.cloud.fault.tolerance.tomcat.event.TomcatDynamicConfigurationListener; 21 | import org.apache.catalina.startup.Tomcat; 22 | import org.springframework.beans.factory.ObjectProvider; 23 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; 24 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 25 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 26 | import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; 27 | import org.springframework.boot.autoconfigure.web.ServerProperties; 28 | import org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration; 29 | import org.springframework.boot.web.context.ConfigurableWebServerApplicationContext; 30 | import org.springframework.boot.web.context.WebServerApplicationContext; 31 | import org.springframework.boot.web.context.WebServerInitializedEvent; 32 | import org.springframework.boot.web.embedded.tomcat.TomcatWebServer; 33 | import org.springframework.boot.web.server.WebServer; 34 | import org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration; 35 | import org.springframework.cloud.context.environment.EnvironmentChangeEvent; 36 | import org.springframework.context.event.EventListener; 37 | 38 | import static io.microsphere.constants.PropertyConstants.ENABLED_PROPERTY_NAME; 39 | import static io.microsphere.spring.cloud.fault.tolerance.tomcat.autoconfigure.TomcatFaultToleranceAutoConfiguration.TOMCAT_PROPERTY_PREFIX; 40 | import static org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type.SERVLET; 41 | 42 | /** 43 | * @author Mercy 44 | * @since 1.0.0 45 | */ 46 | @ConditionalOnProperty( 47 | prefix = TOMCAT_PROPERTY_PREFIX, 48 | name = ENABLED_PROPERTY_NAME, 49 | matchIfMissing = true 50 | ) 51 | @ConditionalOnClass(value = { 52 | EnvironmentChangeEvent.class, 53 | Tomcat.class 54 | }) 55 | @ConditionalOnWebApplication(type = SERVLET) 56 | @AutoConfigureAfter(value = { 57 | EmbeddedWebServerFactoryCustomizerAutoConfiguration.class, 58 | ConfigurationPropertiesRebinderAutoConfiguration.class 59 | }) 60 | public class TomcatFaultToleranceAutoConfiguration { 61 | 62 | public static final String TOMCAT_PROPERTY_PREFIX = FaultTolerancePropertyConstants.FAULT_TOLERANCE_PROPERTY_NAME_PREFIX + "tomcat"; 63 | 64 | @EventListener(WebServerInitializedEvent.class) 65 | public void onWebServerInitializedEvent(WebServerInitializedEvent event) { 66 | WebServerApplicationContext webServerApplicationContext = event.getApplicationContext(); 67 | if (webServerApplicationContext instanceof ConfigurableWebServerApplicationContext) { 68 | ConfigurableWebServerApplicationContext context = (ConfigurableWebServerApplicationContext) webServerApplicationContext; 69 | ObjectProvider beanProvider = context.getBeanProvider(ServerProperties.class); 70 | 71 | beanProvider.ifAvailable(serverProperties -> { 72 | WebServer webServer = event.getWebServer(); 73 | if (webServer instanceof TomcatWebServer) { 74 | TomcatWebServer tomcatWebServer = (TomcatWebServer) webServer; 75 | context.addApplicationListener(new TomcatDynamicConfigurationListener(tomcatWebServer, serverProperties, context)); 76 | } 77 | }); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/resources/META-INF/config/default/endpoints.properties: -------------------------------------------------------------------------------- 1 | # Spring Cloud Actuator Endpoints Default Properties 2 | 3 | ### Spring Cloud Endpoints 4 | management.endpoint.archaius.enabled = false 5 | management.endpoint.refresh.enabled = false 6 | management.endpoint.restart.enabled = false 7 | management.endpoint.pause.enabled = false 8 | management.endpoint.resume.enabled = false 9 | management.endpoint.features.enabled = false 10 | management.endpoint.service-registry.enabled = false 11 | 12 | ### Spring Cloud Env 13 | management.endpoint.env.post.enabled = false 14 | 15 | ## Microsphere Endpoints 16 | management.endpoint.serviceRegistration.enabled = false 17 | management.endpoint.serviceDeregistration.enabled = false 18 | 19 | ## Endpoint Web Path Mapping 20 | management.endpoints.web.path-mapping.serviceRegistration = microsphere/service/registration 21 | management.endpoints.web.path-mapping.serviceDeregistration = microsphere/service/deregistration -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | com.alibaba.cloud.nacos.registry.NacosServiceRegistry = com.alibaba.cloud.nacos.registry.NacosRegistration -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.microsphere.spring.cloud.client.discovery.autoconfigure.DiscoveryClientAutoConfiguration 2 | io.microsphere.spring.cloud.client.service.registry.autoconfigure.ServiceRegistryAutoConfiguration 3 | io.microsphere.spring.cloud.client.service.registry.autoconfigure.WebMvcServiceRegistryAutoConfiguration 4 | io.microsphere.spring.cloud.client.service.registry.autoconfigure.WebFluxServiceRegistryAutoConfiguration 5 | io.microsphere.spring.cloud.client.service.registry.autoconfigure.SimpleAutoServiceRegistrationAutoConfiguration 6 | io.microsphere.spring.cloud.client.service.registry.actuate.autoconfigure.ServiceRegistrationEndpointAutoConfiguration 7 | io.microsphere.spring.cloud.fault.tolerance.tomcat.autoconfigure.TomcatFaultToleranceAutoConfiguration -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/test/java/io/microsphere/spring/cloud/client/condition/ConditionalOnFeaturesEnabledTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.condition; 18 | 19 | /** 20 | * {@link ConditionalOnFeaturesEnabled} Test 21 | * 22 | * @author Mercy 23 | * @see ConditionalOnFeaturesEnabled 24 | * @since 1.0.0 25 | */ 26 | 27 | import org.junit.jupiter.api.Test; 28 | import org.junit.jupiter.api.extension.ExtendWith; 29 | import org.springframework.beans.factory.ObjectProvider; 30 | import org.springframework.beans.factory.annotation.Autowired; 31 | import org.springframework.test.context.ContextConfiguration; 32 | import org.springframework.test.context.TestPropertySource; 33 | import org.springframework.test.context.junit.jupiter.SpringExtension; 34 | 35 | import static org.junit.jupiter.api.Assertions.assertNotNull; 36 | 37 | @ExtendWith(SpringExtension.class) 38 | @ContextConfiguration(classes = { 39 | ConditionalOnFeaturesEnabledTest.FeaturesConfiguration.class 40 | }) 41 | @TestPropertySource( 42 | properties = { 43 | "spring.cloud.features.enabled=true" 44 | } 45 | ) 46 | public class ConditionalOnFeaturesEnabledTest { 47 | 48 | @ConditionalOnFeaturesEnabled 49 | static class FeaturesConfiguration { 50 | } 51 | 52 | @Autowired 53 | private ObjectProvider featuresConfigurationProvider; 54 | 55 | @Test 56 | public void test() { 57 | assertNotNull(featuresConfigurationProvider.getIfAvailable()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/test/java/io/microsphere/spring/cloud/client/discovery/autoconfigure/DiscoveryClientAutoConfigurationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.discovery.autoconfigure; 18 | 19 | import io.microsphere.spring.cloud.client.discovery.UnionDiscoveryClient; 20 | import io.microsphere.spring.cloud.client.discovery.UnionDiscoveryClientTest; 21 | import org.junit.jupiter.api.Test; 22 | import org.junit.jupiter.api.extension.ExtendWith; 23 | import org.springframework.beans.factory.annotation.Autowired; 24 | import org.springframework.boot.test.context.SpringBootTest; 25 | import org.springframework.cloud.client.discovery.DiscoveryClient; 26 | import org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClient; 27 | import org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClientAutoConfiguration; 28 | import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClient; 29 | import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration; 30 | import org.springframework.cloud.commons.util.UtilAutoConfiguration; 31 | import org.springframework.test.context.TestPropertySource; 32 | import org.springframework.test.context.junit.jupiter.SpringExtension; 33 | 34 | import java.util.Arrays; 35 | import java.util.List; 36 | 37 | import static org.junit.jupiter.api.Assertions.assertEquals; 38 | 39 | /** 40 | * {@link DiscoveryClientAutoConfiguration} Test 41 | * 42 | * @author Mercy 43 | * @see DiscoveryClientAutoConfiguration 44 | * @since 1.0.0 45 | */ 46 | @ExtendWith(SpringExtension.class) 47 | @SpringBootTest(classes = { 48 | UtilAutoConfiguration.class, 49 | SimpleDiscoveryClientAutoConfiguration.class, 50 | CompositeDiscoveryClientAutoConfiguration.class, 51 | DiscoveryClientAutoConfiguration.class, 52 | UnionDiscoveryClientTest.class 53 | }) 54 | @TestPropertySource( 55 | properties = { 56 | "microsphere.spring.cloud.client.discovery.mode=union", 57 | "spring.cloud.discovery.client.simple.instances.test[0].instanceId=1", 58 | "spring.cloud.discovery.client.simple.instances.test[0].serviceId=test", 59 | "spring.cloud.discovery.client.simple.instances.test[0].host=127.0.0.1", 60 | "spring.cloud.discovery.client.simple.instances.test[0].port=8080", 61 | "spring.cloud.discovery.client.simple.instances.test[0].metadata.key-1=value-1" 62 | } 63 | ) 64 | public class DiscoveryClientAutoConfigurationTest { 65 | 66 | @Autowired 67 | private DiscoveryClient discoveryClient; 68 | 69 | @Test 70 | public void test() { 71 | assertEquals(CompositeDiscoveryClient.class, discoveryClient.getClass()); 72 | CompositeDiscoveryClient compositeDiscoveryClient = CompositeDiscoveryClient.class.cast(discoveryClient); 73 | List discoveryClients = compositeDiscoveryClient.getDiscoveryClients(); 74 | assertEquals(2, discoveryClients.size()); 75 | assertEquals(UnionDiscoveryClient.class, discoveryClients.get(0).getClass()); 76 | assertEquals(SimpleDiscoveryClient.class, discoveryClients.get(1).getClass()); 77 | List services = compositeDiscoveryClient.getServices(); 78 | assertEquals(Arrays.asList("test"), services); 79 | assertEquals(services, discoveryClients.get(0).getServices()); 80 | assertEquals(services, discoveryClients.get(1).getServices()); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/test/java/io/microsphere/spring/cloud/client/discovery/autoconfigure/UnionDiscoveryClientTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.discovery; 18 | 19 | import org.junit.jupiter.api.Test; 20 | import org.junit.jupiter.api.extension.ExtendWith; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.cloud.client.discovery.DiscoveryClient; 23 | import org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClient; 24 | import org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClientAutoConfiguration; 25 | import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClient; 26 | import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration; 27 | import org.springframework.cloud.commons.util.UtilAutoConfiguration; 28 | import org.springframework.test.context.ContextConfiguration; 29 | import org.springframework.test.context.TestPropertySource; 30 | import org.springframework.test.context.junit.jupiter.SpringExtension; 31 | 32 | import java.util.Arrays; 33 | import java.util.List; 34 | 35 | import static org.junit.jupiter.api.Assertions.assertEquals; 36 | 37 | /** 38 | * {@link UnionDiscoveryClient} Test 39 | * 40 | * @author Mercy 41 | * @since 1.0.0 42 | */ 43 | @ExtendWith(SpringExtension.class) 44 | @ContextConfiguration(classes = { 45 | UtilAutoConfiguration.class, 46 | SimpleDiscoveryClientAutoConfiguration.class, 47 | CompositeDiscoveryClientAutoConfiguration.class, 48 | UnionDiscoveryClient.class, 49 | UnionDiscoveryClientTest.class 50 | }) 51 | @TestPropertySource( 52 | properties = { 53 | "spring.cloud.discovery.client.simple.instances.test[0].instanceId=1", 54 | "spring.cloud.discovery.client.simple.instances.test[0].serviceId=test", 55 | "spring.cloud.discovery.client.simple.instances.test[0].host=127.0.0.1", 56 | "spring.cloud.discovery.client.simple.instances.test[0].port=8080", 57 | "spring.cloud.discovery.client.simple.instances.test[0].metadata.key-1=value-1" 58 | } 59 | ) 60 | public class UnionDiscoveryClientTest { 61 | 62 | @Autowired 63 | private DiscoveryClient discoveryClient; 64 | 65 | @Test 66 | public void test() { 67 | assertEquals(CompositeDiscoveryClient.class, discoveryClient.getClass()); 68 | CompositeDiscoveryClient compositeDiscoveryClient = CompositeDiscoveryClient.class.cast(discoveryClient); 69 | List discoveryClients = compositeDiscoveryClient.getDiscoveryClients(); 70 | assertEquals(2, discoveryClients.size()); 71 | assertEquals(UnionDiscoveryClient.class, discoveryClients.get(0).getClass()); 72 | assertEquals(SimpleDiscoveryClient.class, discoveryClients.get(1).getClass()); 73 | List services = compositeDiscoveryClient.getServices(); 74 | assertEquals(Arrays.asList("test"), services); 75 | assertEquals(services, discoveryClients.get(0).getServices()); 76 | assertEquals(services, discoveryClients.get(1).getServices()); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/test/java/io/microsphere/spring/cloud/client/discovery/constants/DiscoveryClientConstantsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.discovery.constants; 18 | 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static io.microsphere.spring.cloud.client.discovery.constants.DiscoveryClientConstants.COMMONS_CLIENT_AUTO_CONFIGURATION_CLASS_NAME; 22 | import static io.microsphere.spring.cloud.client.discovery.constants.DiscoveryClientConstants.COMPOSITE_DISCOVERY_CLIENT_CLASS_NAME; 23 | import static io.microsphere.spring.cloud.client.discovery.constants.DiscoveryClientConstants.DISCOVERY_CLIENT_CLASS_NAME; 24 | import static io.microsphere.spring.cloud.client.discovery.constants.DiscoveryClientConstants.DISCOVERY_CLIENT_PROPERTY_PREFIX; 25 | import static io.microsphere.spring.cloud.client.discovery.constants.DiscoveryClientConstants.MODE_PROPERTY_NAME; 26 | import static io.microsphere.spring.cloud.client.discovery.constants.DiscoveryClientConstants.UNION_DISCOVERY_CLIENT_MODE; 27 | import static org.junit.jupiter.api.Assertions.assertEquals; 28 | 29 | /** 30 | * {@link DiscoveryClientConstants} Test 31 | * 32 | * @author Mercy 33 | * @see DiscoveryClientConstants 34 | * @since 1.0.0 35 | */ 36 | public class DiscoveryClientConstantsTest { 37 | 38 | @Test 39 | public void testConstants() { 40 | assertEquals("microsphere.spring.cloud.client.discovery.", DISCOVERY_CLIENT_PROPERTY_PREFIX); 41 | assertEquals("mode", MODE_PROPERTY_NAME); 42 | assertEquals("union", UNION_DISCOVERY_CLIENT_MODE); 43 | 44 | assertEquals("org.springframework.cloud.client.discovery.DiscoveryClient", DISCOVERY_CLIENT_CLASS_NAME); 45 | assertEquals("org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClient", COMPOSITE_DISCOVERY_CLIENT_CLASS_NAME); 46 | assertEquals("org.springframework.cloud.client.CommonsClientAutoConfiguration", COMMONS_CLIENT_AUTO_CONFIGURATION_CLASS_NAME); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/test/java/io/microsphere/spring/cloud/client/event/ServiceInstancesChangedEventTest.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.client.event; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.cloud.client.DefaultServiceInstance; 6 | import org.springframework.cloud.client.ServiceInstance; 7 | 8 | import java.net.URI; 9 | import java.util.Arrays; 10 | import java.util.UUID; 11 | 12 | import static org.junit.jupiter.api.Assertions.assertEquals; 13 | import static org.junit.jupiter.api.Assertions.assertFalse; 14 | import static org.junit.jupiter.api.Assertions.assertSame; 15 | import static org.junit.jupiter.api.Assertions.assertTrue; 16 | 17 | /** 18 | * {@link ServiceInstancesChangedEvent} Test 19 | * 20 | * @author Mercy 21 | * @see ServiceInstancesChangedEvent 22 | * @since 1.0.0 23 | */ 24 | public class ServiceInstancesChangedEventTest { 25 | 26 | private String serviceName = "testService"; 27 | 28 | private ServiceInstancesChangedEvent event; 29 | 30 | private ServiceInstance instance; 31 | 32 | @BeforeEach 33 | public void init() { 34 | this.instance = createInstance(serviceName); 35 | this.event = new ServiceInstancesChangedEvent(serviceName, Arrays.asList(instance)); 36 | } 37 | 38 | private ServiceInstance createInstance(String serviceName) { 39 | DefaultServiceInstance instance = new DefaultServiceInstance(); 40 | instance.setServiceId(serviceName); 41 | instance.setServiceId(UUID.randomUUID().toString()); 42 | instance.setHost("127.0.0.1"); 43 | instance.setPort(8080); 44 | instance.setUri(URI.create("http://127.0.0.1:8080/info")); 45 | return instance; 46 | } 47 | 48 | @Test 49 | public void testGetServiceName() { 50 | assertEquals(this.serviceName, this.event.getServiceName()); 51 | assertEquals(this.serviceName, this.event.getSource()); 52 | } 53 | 54 | @Test 55 | public void testGetServiceInstances() { 56 | assertEquals(Arrays.asList(this.instance), this.event.getServiceInstances()); 57 | assertEquals(this.instance, this.event.getServiceInstances().get(0)); 58 | assertSame(this.instance, this.event.getServiceInstances().get(0)); 59 | } 60 | 61 | @Test 62 | public void testProcessed() { 63 | assertFalse(this.event.isProcessed()); 64 | this.event.processed(); 65 | assertTrue(this.event.isProcessed()); 66 | } 67 | } -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/test/java/io/microsphere/spring/cloud/client/service/registry/MultipleServiceRegistryTest.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.client.service.registry; 2 | 3 | import com.alibaba.cloud.nacos.NacosServiceAutoConfiguration; 4 | import com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration; 5 | import com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration; 6 | import com.netflix.appinfo.ApplicationInfoManager; 7 | import com.netflix.appinfo.InstanceInfo; 8 | import io.microsphere.spring.cloud.client.service.registry.autoconfigure.ServiceRegistryAutoConfiguration; 9 | import io.microsphere.spring.cloud.client.service.registry.event.RegistrationPreRegisteredEvent; 10 | import org.junit.jupiter.api.Disabled; 11 | import org.junit.jupiter.api.Test; 12 | import org.junit.jupiter.api.extension.ExtendWith; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 15 | import org.springframework.cloud.client.CommonsClientAutoConfiguration; 16 | import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration; 17 | import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; 18 | import org.springframework.cloud.client.serviceregistry.Registration; 19 | import org.springframework.cloud.client.serviceregistry.ServiceRegistry; 20 | import org.springframework.cloud.commons.util.UtilAutoConfiguration; 21 | import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration; 22 | import org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration; 23 | import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration; 24 | import org.springframework.context.ApplicationListener; 25 | import org.springframework.test.context.ContextConfiguration; 26 | import org.springframework.test.context.TestPropertySource; 27 | import org.springframework.test.context.junit.jupiter.SpringExtension; 28 | 29 | import java.util.Map; 30 | 31 | import static org.junit.jupiter.api.Assertions.assertEquals; 32 | import static org.junit.jupiter.api.Assertions.assertNotNull; 33 | 34 | @Disabled 35 | @ExtendWith(SpringExtension.class) 36 | @ContextConfiguration(classes = { 37 | AutoServiceRegistrationAutoConfiguration.class, 38 | CommonsClientAutoConfiguration.class, 39 | EurekaClientAutoConfiguration.class, 40 | DiscoveryClientOptionalArgsConfiguration.class, 41 | NacosServiceRegistryAutoConfiguration.class, 42 | NacosServiceAutoConfiguration.class, 43 | NacosDiscoveryAutoConfiguration.class, 44 | UtilAutoConfiguration.class, 45 | MultipleServiceRegistryTest.class, 46 | ServiceRegistryAutoConfiguration.class, 47 | }) 48 | @TestPropertySource( 49 | properties = { 50 | "spring.application.name=test", 51 | "microsphere.spring.cloud.multiple-registration.enabled=true", 52 | "microsphere.spring.cloud.default-registration.type=com.alibaba.cloud.nacos.registry.NacosRegistration", 53 | "microsphere.spring.cloud.default-service-registry.type=com.alibaba.cloud.nacos.registry.NacosServiceRegistry", 54 | "spring.cloud.service-registry.auto-registration.enabled=true", 55 | "spring.cloud.nacos.discovery.namespace=f7ad23e0-f581-4516-9420-8c50aa6a7b89", 56 | "spring.cloud.nacos.discovery.metadata.key=value", 57 | "eureka.client.service-url.defaultZone=http://127.0.0.1:8080/eureka", 58 | } 59 | ) 60 | @EnableAutoConfiguration 61 | class MultipleServiceRegistryTest implements ApplicationListener { 62 | 63 | @Autowired 64 | private ServiceRegistry serviceRegistry; 65 | 66 | @Autowired 67 | private AutoServiceRegistrationProperties properties; 68 | 69 | @Autowired 70 | private Registration registration; 71 | 72 | @Autowired 73 | private MultipleAutoServiceRegistration autoServiceRegistration; 74 | 75 | @Override 76 | public void onApplicationEvent(RegistrationPreRegisteredEvent event) { 77 | this.registration.getMetadata().put("my-key", "my-value"); 78 | if (event.getRegistration() instanceof EurekaRegistration) { 79 | EurekaRegistration eurekaRegistration = (EurekaRegistration) event.getRegistration(); 80 | 81 | 82 | ApplicationInfoManager applicationInfoManager = eurekaRegistration.getApplicationInfoManager(); 83 | InstanceInfo instanceInfo = applicationInfoManager.getInfo(); 84 | Map metadata = registration.getMetadata(); 85 | // Sync metadata from Registration to InstanceInfo 86 | instanceInfo.getMetadata().putAll(metadata); 87 | } 88 | } 89 | 90 | @Test 91 | public void test() throws Exception { 92 | assertNotNull(serviceRegistry); 93 | assertNotNull(registration); 94 | autoServiceRegistration.start(); 95 | Thread.sleep(60 * 1000); 96 | 97 | autoServiceRegistration.stop(); 98 | } 99 | 100 | @Test 101 | public void testMetaData() throws Exception { 102 | assertNotNull(registration); 103 | 104 | autoServiceRegistration.start(); 105 | 106 | assertEquals(registration.getMetadata().get("my-key"), "my-value"); 107 | Thread.sleep(60 * 1000); 108 | 109 | autoServiceRegistration.stop(); 110 | } 111 | 112 | 113 | } -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/test/java/io/microsphere/spring/cloud/client/service/registry/actuate/autoconfigure/ServiceRegistrationEndpointAutoConfigurationTest.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.client.service.registry.actuate.autoconfigure; 2 | 3 | import io.microsphere.spring.cloud.client.service.registry.endpoint.ServiceDeregistrationEndpoint; 4 | import io.microsphere.spring.cloud.client.service.registry.endpoint.ServiceRegistrationEndpoint; 5 | import org.junit.jupiter.api.Test; 6 | import org.springframework.beans.factory.ObjectProvider; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | 11 | import static org.junit.jupiter.api.Assertions.assertNotNull; 12 | 13 | /** 14 | * {@link ServiceRegistrationEndpointAutoConfiguration} Test 15 | * 16 | * @author Mercy 17 | * @see ServiceRegistrationEndpointAutoConfiguration 18 | * @since 1.0.0 19 | */ 20 | @SpringBootTest( 21 | classes = { 22 | ServiceRegistrationEndpointAutoConfigurationTest.class 23 | }, 24 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 25 | properties = { 26 | "microsphere.spring.cloud.service-registry.auto-registration.simple.enabled=true", 27 | "management.endpoint.serviceRegistration.enabled=true", 28 | "management.endpoint.serviceDeregistration.enabled=true", 29 | } 30 | ) 31 | @EnableAutoConfiguration 32 | public class ServiceRegistrationEndpointAutoConfigurationTest { 33 | 34 | @Autowired 35 | private ObjectProvider serviceRegistrationEndpoint; 36 | 37 | @Autowired 38 | private ObjectProvider serviceDeregistrationEndpoint; 39 | 40 | @Test 41 | public void testEndpoints() { 42 | assertNotNull(serviceRegistrationEndpoint); 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/test/java/io/microsphere/spring/cloud/client/service/registry/autoconfigure/SimpleAutoServiceRegistrationAutoConfigurationTest.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.client.service.registry.autoconfigure; 2 | 3 | import io.microsphere.spring.cloud.client.service.registry.SimpleAutoServiceRegistration; 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.cloud.client.serviceregistry.Registration; 9 | import org.springframework.cloud.client.serviceregistry.ServiceRegistry; 10 | 11 | import static org.junit.jupiter.api.Assertions.assertEquals; 12 | import static org.junit.jupiter.api.Assertions.assertNotNull; 13 | 14 | /** 15 | * {@link SimpleAutoServiceRegistrationAutoConfiguration} Test 16 | * 17 | * @author Mercy 18 | * @see SimpleAutoServiceRegistrationAutoConfiguration 19 | * @since 1.0.0 20 | */ 21 | @SpringBootTest( 22 | classes = { 23 | SimpleAutoServiceRegistrationAutoConfigurationTest.class 24 | }, 25 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 26 | properties = { 27 | "microsphere.spring.cloud.service-registry.auto-registration.simple.enabled=true", 28 | "spring.application.name=test-service" 29 | } 30 | ) 31 | @EnableAutoConfiguration 32 | public class SimpleAutoServiceRegistrationAutoConfigurationTest { 33 | 34 | @Autowired 35 | private Registration registration; 36 | 37 | @Autowired 38 | private ServiceRegistry serviceRegistry; 39 | 40 | @Autowired 41 | private SimpleAutoServiceRegistration simpleAutoServiceRegistration; 42 | 43 | @Test 44 | public void test() { 45 | assertEquals("test-service", registration.getServiceId()); 46 | assertNotNull(registration.getHost()); 47 | assertNotNull(registration.getPort()); 48 | assertNotNull(registration.getUri()); 49 | assertNotNull(registration.getInstanceId()); 50 | assertNotNull(registration.getMetadata()); 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/test/java/io/microsphere/spring/cloud/client/service/registry/autoconfigure/WebMvcServiceRegistryAutoConfigurationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.client.service.registry.autoconfigure; 18 | 19 | import io.microsphere.spring.webmvc.annotation.EnableWebMvcExtension; 20 | import org.junit.jupiter.api.Test; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 23 | import org.springframework.boot.test.context.SpringBootTest; 24 | import org.springframework.cloud.client.serviceregistry.Registration; 25 | 26 | import java.util.Map; 27 | 28 | import static io.microsphere.spring.cloud.client.service.registry.constants.InstanceConstants.WEB_MAPPINGS_METADATA_NAME; 29 | import static org.junit.jupiter.api.Assertions.assertNotNull; 30 | 31 | /** 32 | * {@link WebMvcServiceRegistryAutoConfiguration} Test 33 | * 34 | * @author Mercy 35 | * @since 1.0.0 36 | */ 37 | @SpringBootTest( 38 | classes = {WebMvcServiceRegistryAutoConfigurationTest.class}, 39 | properties = { 40 | "microsphere.spring.cloud.service-registry.auto-registration.simple.enabled=true", 41 | "spring.cloud.service-registry.auto-registration.enabled=true", 42 | "spring.cloud.kubernetes.enabled=false", 43 | "kubernetes.informer.enabled=false", 44 | "kubernetes.manifests.enabled=false", 45 | "kubernetes.reconciler.enabled=false" 46 | }, 47 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT 48 | ) 49 | @EnableAutoConfiguration 50 | @EnableWebMvcExtension 51 | public class WebMvcServiceRegistryAutoConfigurationTest { 52 | 53 | @Autowired 54 | private Registration registration; 55 | 56 | @Test 57 | public void test() { 58 | Map metadata = registration.getMetadata(); 59 | assertNotNull(metadata.get(WEB_MAPPINGS_METADATA_NAME)); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/test/java/io/microsphere/spring/cloud/commons/constants/CommonsPropertyConstantsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.microsphere.spring.cloud.commons.constants; 18 | 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static io.microsphere.spring.cloud.commons.constants.CommonsPropertyConstants.COMPOSITE_REGISTRATION_ENABLED_PROPERTY_NAME; 22 | import static io.microsphere.spring.cloud.commons.constants.CommonsPropertyConstants.FEATURES_ENABLED_PROPERTY_NAME; 23 | import static io.microsphere.spring.cloud.commons.constants.CommonsPropertyConstants.MICROSPHERE_SPRING_CLOUD_PROPERTY_NAME_PREFIX; 24 | import static io.microsphere.spring.cloud.commons.constants.CommonsPropertyConstants.MICROSPHERE_SPRING_CLOUD_WEB_MVC_PROPERTY_NAME_PREFIX; 25 | import static io.microsphere.spring.cloud.commons.constants.CommonsPropertyConstants.MULTIPLE_REGISTRATION_DEFAULT_REGISTRATION_PROPERTY_NAME; 26 | import static io.microsphere.spring.cloud.commons.constants.CommonsPropertyConstants.MULTIPLE_REGISTRATION_DEFAULT_REGISTRY_PROPERTY_NAME; 27 | import static io.microsphere.spring.cloud.commons.constants.CommonsPropertyConstants.MULTIPLE_REGISTRATION_ENABLED_PROPERTY_NAME; 28 | import static io.microsphere.spring.cloud.commons.constants.CommonsPropertyConstants.SERVICE_REGISTRY_AUTO_REGISTRATION_ENABLED_PROPERTY_NAME; 29 | import static io.microsphere.spring.cloud.commons.constants.CommonsPropertyConstants.SERVICE_REGISTRY_PROPERTY_PREFIX; 30 | import static io.microsphere.spring.cloud.commons.constants.CommonsPropertyConstants.SPRING_CLOUD_PROPERTY_PREFIX; 31 | import static org.junit.jupiter.api.Assertions.assertEquals; 32 | 33 | /** 34 | * {@link CommonsPropertyConstants} Test 35 | * 36 | * @author Mercy 37 | * @see CommonsPropertyConstants 38 | * @since 1.0.0 39 | */ 40 | public class CommonsPropertyConstantsTest { 41 | 42 | @Test 43 | public void testConstants() { 44 | assertEquals("spring.cloud.", SPRING_CLOUD_PROPERTY_PREFIX); 45 | assertEquals("spring.cloud.service-registry.", SERVICE_REGISTRY_PROPERTY_PREFIX); 46 | assertEquals("spring.cloud.service-registry.auto-registration.enabled", SERVICE_REGISTRY_AUTO_REGISTRATION_ENABLED_PROPERTY_NAME); 47 | assertEquals("spring.cloud.features.enabled", FEATURES_ENABLED_PROPERTY_NAME); 48 | assertEquals("microsphere.spring.cloud.", MICROSPHERE_SPRING_CLOUD_PROPERTY_NAME_PREFIX); 49 | assertEquals("microsphere.spring.cloud.web.mvc.", MICROSPHERE_SPRING_CLOUD_WEB_MVC_PROPERTY_NAME_PREFIX); 50 | assertEquals("microsphere.spring.cloud.multiple-registration.enabled", MULTIPLE_REGISTRATION_ENABLED_PROPERTY_NAME); 51 | assertEquals("microsphere.spring.cloud.default-registration.type", MULTIPLE_REGISTRATION_DEFAULT_REGISTRATION_PROPERTY_NAME); 52 | assertEquals("microsphere.spring.cloud.default-service-registry.type", MULTIPLE_REGISTRATION_DEFAULT_REGISTRY_PROPERTY_NAME); 53 | assertEquals("microsphere.spring.cloud.composite-registration.enabled", COMPOSITE_REGISTRATION_ENABLED_PROPERTY_NAME); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-commons/src/test/resources/application.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: microsphere-spring-cloud-commons-application 4 | 5 | # default disable all 6 | cloud: 7 | nacos: 8 | discovery: 9 | enabled: false 10 | register-enabled: false 11 | config: 12 | import-check.enabled: false 13 | zookeeper: 14 | enabled: false 15 | consul: 16 | enabled: false 17 | kubernetes: 18 | enabled: false 19 | config: 20 | enabled: false 21 | enableApi: false 22 | secrets: 23 | enabled: false 24 | 25 | eureka: 26 | client: 27 | enabled: false 28 | 29 | 30 | --- 31 | spring: 32 | config: 33 | activate: 34 | on-profile: nacos 35 | 36 | cloud: 37 | nacos: 38 | username: nacos 39 | password: nacos 40 | discovery: 41 | enabled: true 42 | register-enabled: true 43 | server-addr: 127.0.0.1:8848 44 | ephemeral: false 45 | 46 | 47 | --- 48 | spring: 49 | config: 50 | activate: 51 | on-profile: eureka 52 | 53 | eureka: 54 | client: 55 | enabled: true 56 | service-url: 57 | defaultZone: http://127.0.0.1:8761/eureka/ 58 | 59 | 60 | --- 61 | spring: 62 | config: 63 | activate: 64 | on-profile: zookeeper 65 | cloud: 66 | zookeeper: 67 | enabled: true 68 | connect-string: 127.0.0.1:2181 69 | 70 | 71 | --- 72 | spring: 73 | config: 74 | activate: 75 | on-profile: consul 76 | 77 | cloud: 78 | consul: 79 | enabled: true 80 | host: 127.0.0.1 81 | port: 8500 82 | 83 | 84 | --- 85 | spring: 86 | config: 87 | activate: 88 | on-profile: kubernetes 89 | 90 | cloud: 91 | kubernetes: 92 | enabled: true -------------------------------------------------------------------------------- /microsphere-spring-cloud-dependencies/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | io.github.microsphere-projects 7 | microsphere-spring-cloud-parent 8 | ${revision} 9 | ../microsphere-spring-cloud-parent/pom.xml 10 | 11 | 4.0.0 12 | 13 | io.github.microsphere-projects 14 | microsphere-spring-cloud-dependencies 15 | ${revision} 16 | pom 17 | 18 | Microsphere :: Spring Cloud :: Dependencies 19 | Microsphere Spring Cloud Dependencies 20 | 21 | 22 | 23 | 24 | 25 | io.github.microsphere-projects 26 | microsphere-spring-cloud-commons 27 | ${revision} 28 | 29 | 30 | 31 | io.github.microsphere-projects 32 | microsphere-spring-cloud-openfeign 33 | ${revision} 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | io.github.microsphere-projects 8 | microsphere-spring-cloud-parent 9 | ${revision} 10 | ../microsphere-spring-cloud-parent/pom.xml 11 | 12 | 13 | microsphere-spring-cloud-openfeign 14 | ${revision} 15 | 16 | io.github.microsphere-projects 17 | 18 | Microsphere :: Spring Cloud :: OpenFeign 19 | Microsphere Spring Cloud OpenFeign 20 | 21 | 22 | 8 23 | 8 24 | UTF-8 25 | 26 | 27 | 28 | 29 | 30 | 31 | io.github.microsphere-projects 32 | microsphere-spring-boot-core 33 | 34 | 35 | 36 | org.springframework.cloud 37 | spring-cloud-starter-openfeign 38 | true 39 | 40 | 41 | org.springframework.cloud 42 | spring-cloud-netflix-ribbon 43 | 44 | 45 | 46 | 47 | 48 | org.springframework.cloud 49 | spring-cloud-starter-loadbalancer 50 | true 51 | 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-starter-test 56 | test 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/main/java/io/microsphere/spring/cloud/openfeign/autoconfigure/EnableFeignAutoRefresh.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.autoconfigure; 2 | 3 | import org.springframework.context.annotation.Import; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Inherited; 8 | import java.lang.annotation.Retention; 9 | import java.lang.annotation.RetentionPolicy; 10 | import java.lang.annotation.Target; 11 | 12 | /** 13 | * Enable Feign Auto Refresh 14 | * 15 | * @author 韩超 16 | * @author Mercy 17 | * @see FeignClientAutoRefreshAutoConfiguration 18 | * @since 0.0.1 19 | */ 20 | @Retention(RetentionPolicy.RUNTIME) 21 | @Target({ElementType.TYPE}) 22 | @Documented 23 | @Inherited 24 | @Import(EnableFeignAutoRefresh.Marker.class) 25 | public @interface EnableFeignAutoRefresh { 26 | 27 | class Marker { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/main/java/io/microsphere/spring/cloud/openfeign/autoconfigure/FeignClientAutoRefreshAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.autoconfigure; 2 | 3 | import io.microsphere.spring.cloud.openfeign.autorefresh.FeignClientConfigurationChangedListener; 4 | import io.microsphere.spring.cloud.openfeign.autorefresh.FeignComponentRegistry; 5 | import io.microsphere.spring.cloud.openfeign.components.NoOpRequestInterceptor; 6 | import org.springframework.beans.factory.BeanFactory; 7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; 8 | import org.springframework.boot.context.event.ApplicationReadyEvent; 9 | import org.springframework.cloud.openfeign.FeignBuilderCustomizer; 10 | import org.springframework.cloud.openfeign.FeignClientProperties; 11 | import org.springframework.context.ConfigurableApplicationContext; 12 | import org.springframework.context.annotation.Bean; 13 | import org.springframework.context.event.EventListener; 14 | 15 | /** 16 | * The Auto-Configuration class for {@link EnableFeignAutoRefresh} 17 | * 18 | * @author 韩超 19 | * @author Mercy 20 | * @see EnableFeignAutoRefresh 21 | * @since 0.0.1 22 | */ 23 | @ConditionalOnBean(EnableFeignAutoRefresh.Marker.class) 24 | public class FeignClientAutoRefreshAutoConfiguration { 25 | 26 | @Bean 27 | public FeignBuilderCustomizer addDefaultRequestInterceptorCustomizer() { 28 | return builder -> { 29 | builder.requestInterceptor(NoOpRequestInterceptor.INSTANCE); 30 | }; 31 | } 32 | 33 | @EventListener(ApplicationReadyEvent.class) 34 | public void onApplicationReadyEvent(ApplicationReadyEvent event) { 35 | /** 36 | * Make sure the FeignClientConfigurationChangedListener is registered after the ConfigurationPropertiesRebinder 37 | */ 38 | registerFeignClientConfigurationChangedListener(event); 39 | } 40 | 41 | @Bean 42 | public FeignComponentRegistry feignClientRegistry(FeignClientProperties clientProperties, BeanFactory beanFactory) { 43 | return new FeignComponentRegistry(clientProperties.getDefaultConfig(), beanFactory); 44 | } 45 | 46 | @Bean 47 | public FeignClientSpecificationPostProcessor feignClientSpecificationPostProcessor() { 48 | return new FeignClientSpecificationPostProcessor(); 49 | } 50 | 51 | private void registerFeignClientConfigurationChangedListener(ApplicationReadyEvent event) { 52 | ConfigurableApplicationContext context = event.getApplicationContext(); 53 | FeignComponentRegistry feignComponentRegistry = context.getBean(FeignComponentRegistry.class); 54 | context.addApplicationListener(new FeignClientConfigurationChangedListener(feignComponentRegistry)); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/main/java/io/microsphere/spring/cloud/openfeign/autoconfigure/FeignClientSpecificationPostProcessor.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.autoconfigure; 2 | 3 | import io.microsphere.logging.Logger; 4 | import io.microsphere.spring.cloud.openfeign.autorefresh.AutoRefreshCapability; 5 | import org.springframework.beans.BeansException; 6 | import org.springframework.beans.factory.config.BeanPostProcessor; 7 | import org.springframework.cloud.context.named.NamedContextFactory; 8 | 9 | import java.lang.reflect.Method; 10 | import java.util.Arrays; 11 | 12 | import static io.microsphere.logging.LoggerFactory.getLogger; 13 | import static io.microsphere.reflect.MethodUtils.findMethod; 14 | import static io.microsphere.util.ArrayUtils.combine; 15 | import static org.springframework.aop.support.AopUtils.getTargetClass; 16 | import static org.springframework.util.ClassUtils.resolveClassName; 17 | 18 | /** 19 | * @author 韩超 20 | * @author Mercy 21 | * @see org.springframework.cloud.openfeign.FeignClientSpecification 22 | * @since 0.0.1 23 | */ 24 | public class FeignClientSpecificationPostProcessor implements BeanPostProcessor { 25 | 26 | private static final Logger logger = getLogger(FeignClientSpecificationPostProcessor.class); 27 | 28 | private static final Class AUTO_REFRESH_CAPABILITY_CLASS = AutoRefreshCapability.class; 29 | 30 | private static final String FEIGN_CLIENT_SPECIFICATION_CLASS_NAME = "org.springframework.cloud.openfeign.FeignClientSpecification"; 31 | 32 | private static final Class FEIGN_CLIENT_SPECIFICATION_CLASS = resolveClassName(FEIGN_CLIENT_SPECIFICATION_CLASS_NAME, null); 33 | 34 | private static final Method setConfigurationMethod = findMethod(FEIGN_CLIENT_SPECIFICATION_CLASS, "setConfiguration", Class[].class); 35 | 36 | @Override 37 | public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 38 | Class beanType = getTargetClass(bean); 39 | if (FEIGN_CLIENT_SPECIFICATION_CLASS.isAssignableFrom(beanType) && beanName.startsWith("default")) { 40 | injectAutoRefreshCapability((NamedContextFactory.Specification) bean); 41 | } 42 | return bean; 43 | } 44 | 45 | private void injectAutoRefreshCapability(NamedContextFactory.Specification defaultSpecification) { 46 | if (setConfigurationMethod != null) { 47 | Class[] originConfigurationClasses = defaultSpecification.getConfiguration(); 48 | Class[] newConfigurationClasses = combine(AUTO_REFRESH_CAPABILITY_CLASS, originConfigurationClasses); 49 | Object arg = newConfigurationClasses; 50 | try { 51 | setConfigurationMethod.setAccessible(true); 52 | setConfigurationMethod.invoke(defaultSpecification, arg); 53 | } catch (Throwable e) { 54 | if (logger.isWarnEnabled()) { 55 | logger.warn("FeignClientSpecification#setConfiguration(Class[]) can't be invoked , instance : {} , args : {}", 56 | defaultSpecification, Arrays.toString(newConfigurationClasses)); 57 | } 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/main/java/io/microsphere/spring/cloud/openfeign/autorefresh/FeignClientConfigurationChangedListener.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.autorefresh; 2 | 3 | import org.springframework.cloud.context.environment.EnvironmentChangeEvent; 4 | import org.springframework.context.ApplicationListener; 5 | 6 | import java.util.Map; 7 | import java.util.Set; 8 | import java.util.stream.Collectors; 9 | 10 | /** 11 | * @author 韩超 12 | * @since 0.0.1 13 | */ 14 | public class FeignClientConfigurationChangedListener implements ApplicationListener { 15 | 16 | private final FeignComponentRegistry registry; 17 | 18 | public FeignClientConfigurationChangedListener(FeignComponentRegistry registry) { 19 | this.registry = registry; 20 | } 21 | 22 | private final String PREFIX = "spring.cloud.openfeign.client.config."; 23 | 24 | @Override 25 | public void onApplicationEvent(EnvironmentChangeEvent event) { 26 | Map> effectiveClients = resolveChangedClient(event); 27 | if (!effectiveClients.isEmpty()) { 28 | effectiveClients.forEach(registry::refresh); 29 | } 30 | } 31 | 32 | protected Map> resolveChangedClient(EnvironmentChangeEvent event) { 33 | Set keys = event.getKeys(); 34 | return keys.stream() 35 | .filter(str -> str.startsWith(PREFIX)) 36 | .map(str -> str.replace(PREFIX, "")) 37 | .collect(Collectors.groupingBy(str -> { 38 | int index = str.indexOf("."); 39 | return str.substring(0, index); 40 | }, Collectors.toSet())); 41 | 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/main/java/io/microsphere/spring/cloud/openfeign/components/CompositedRequestInterceptor.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.components; 2 | 3 | import feign.RequestInterceptor; 4 | import feign.RequestTemplate; 5 | import org.springframework.beans.BeanUtils; 6 | import org.springframework.beans.factory.BeanFactory; 7 | import org.springframework.cloud.openfeign.FeignClientProperties; 8 | import org.springframework.util.CollectionUtils; 9 | 10 | import java.util.Collection; 11 | import java.util.Collections; 12 | import java.util.HashMap; 13 | import java.util.HashSet; 14 | import java.util.Map; 15 | import java.util.Set; 16 | 17 | /** 18 | * @author 韩超 19 | * @since 0.0.1 20 | */ 21 | public class CompositedRequestInterceptor implements RequestInterceptor, Refreshable { 22 | 23 | private final BeanFactory beanFactory; 24 | private final String contextId; 25 | 26 | private final Set set = new HashSet<>(); 27 | 28 | public CompositedRequestInterceptor(String contextId, BeanFactory beanFactory) { 29 | this.beanFactory = beanFactory; 30 | this.contextId = contextId; 31 | } 32 | 33 | public Set getRequestInterceptors() { 34 | return Collections.unmodifiableSet(set); 35 | } 36 | 37 | 38 | @Override 39 | public void apply(RequestTemplate template) { 40 | synchronized (this.set) { 41 | if (!this.set.isEmpty()) 42 | set.forEach(requestInterceptor -> requestInterceptor.apply(template)); 43 | } 44 | 45 | } 46 | 47 | public boolean addRequestInterceptor(RequestInterceptor requestInterceptor) { 48 | synchronized (this.set) { 49 | boolean isFirst = this.set.isEmpty(); 50 | this.set.add(requestInterceptor); 51 | return isFirst; 52 | } 53 | 54 | } 55 | 56 | private RequestInterceptor getInterceptorOrInstantiate(Class clazz) { 57 | try { 58 | return this.beanFactory.getBean(clazz); 59 | } catch (Exception e) { 60 | return BeanUtils.instantiateClass(clazz); 61 | } 62 | } 63 | 64 | @Override 65 | public void refresh() { 66 | FeignClientProperties properties = this.beanFactory.getBean(FeignClientProperties.class); 67 | Set> interceptors = new HashSet<>(); 68 | //headers 69 | Map> headers = new HashMap<>(); 70 | Map> params = new HashMap<>(); 71 | if (properties != null) { 72 | FeignClientProperties.FeignClientConfiguration defaultConfiguration = properties.getConfig().get(properties.getDefaultConfig()); 73 | FeignClientProperties.FeignClientConfiguration current = properties.getConfig().get(contextId); 74 | if (defaultConfiguration != null && defaultConfiguration.getRequestInterceptors() != null) 75 | interceptors.addAll(defaultConfiguration.getRequestInterceptors()); 76 | if (current != null && current.getRequestInterceptors() != null) 77 | interceptors.addAll(current.getRequestInterceptors()); 78 | 79 | if (defaultConfiguration != null && defaultConfiguration.getDefaultRequestHeaders() != null) 80 | headers.putAll(defaultConfiguration.getDefaultRequestHeaders()); 81 | 82 | if (current != null && current.getDefaultRequestHeaders() != null) { 83 | current.getDefaultRequestHeaders().forEach(headers::putIfAbsent); 84 | } 85 | 86 | if (defaultConfiguration != null && defaultConfiguration.getDefaultQueryParameters() != null) 87 | params.putAll(defaultConfiguration.getDefaultRequestHeaders()); 88 | 89 | if (current != null && current.getDefaultQueryParameters() != null) { 90 | current.getDefaultQueryParameters().forEach(params::putIfAbsent); 91 | } 92 | 93 | } 94 | 95 | synchronized (this.set) { 96 | this.set.clear(); 97 | for (Class interceptorClass : interceptors) 98 | set.add(getInterceptorOrInstantiate(interceptorClass)); 99 | 100 | if (!CollectionUtils.isEmpty(headers)) 101 | set.add(requestTemplate -> { 102 | Map> requestHeader = requestTemplate.headers(); 103 | headers.keySet().forEach(key -> { 104 | if (!requestHeader.containsKey(key)) { 105 | requestTemplate.header(key, headers.get(key)); 106 | } 107 | }); 108 | }); 109 | 110 | if (!CollectionUtils.isEmpty(params)) 111 | set.add(requestTemplate -> { 112 | Map> requestQueries = requestTemplate.queries(); 113 | params.keySet().forEach(key -> { 114 | if (!requestQueries.containsKey(key)) { 115 | requestTemplate.query(key, params.get(key)); 116 | } 117 | }); 118 | }); 119 | } 120 | 121 | 122 | 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/main/java/io/microsphere/spring/cloud/openfeign/components/DecoratedContract.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.components; 2 | 3 | import feign.Contract; 4 | import feign.MethodMetadata; 5 | import org.springframework.cloud.context.named.NamedContextFactory; 6 | import org.springframework.cloud.openfeign.FeignClientProperties; 7 | import org.springframework.cloud.openfeign.FeignClientSpecification; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * @author 韩超 13 | * @since 0.0.1 14 | */ 15 | public class DecoratedContract extends DecoratedFeignComponent implements Contract { 16 | 17 | public DecoratedContract(String contextId, NamedContextFactory contextFactory, FeignClientProperties clientProperties, Contract delegate) { 18 | super(contextId, contextFactory, clientProperties, delegate); 19 | } 20 | 21 | @Override 22 | protected Class componentType() { 23 | Class contractClass = null; 24 | if (getDefaultConfiguration() != null && getDefaultConfiguration().getContract() != null) 25 | contractClass = getDefaultConfiguration().getContract(); 26 | 27 | if (getCurrentConfiguration() != null && getCurrentConfiguration().getContract() != null) 28 | contractClass = getCurrentConfiguration().getContract(); 29 | 30 | if (contractClass != null) 31 | return contractClass; 32 | return Contract.class; 33 | } 34 | 35 | @Override 36 | public List parseAndValidateMetadata(Class targetType) { 37 | return delegate().parseAndValidateMetadata(targetType); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/main/java/io/microsphere/spring/cloud/openfeign/components/DecoratedDecoder.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.components; 2 | 3 | import feign.FeignException; 4 | import feign.Response; 5 | import feign.codec.DecodeException; 6 | import feign.codec.Decoder; 7 | import org.springframework.cloud.context.named.NamedContextFactory; 8 | import org.springframework.cloud.openfeign.FeignClientProperties; 9 | import org.springframework.cloud.openfeign.FeignClientSpecification; 10 | 11 | import java.io.IOException; 12 | import java.lang.reflect.Type; 13 | 14 | /** 15 | * @author 韩超 16 | * @since 0.0.1 17 | */ 18 | public class DecoratedDecoder extends DecoratedFeignComponent implements Decoder { 19 | 20 | public DecoratedDecoder(String contextId, NamedContextFactory contextFactory, FeignClientProperties clientProperties, Decoder delegate) { 21 | super(contextId, contextFactory, clientProperties, delegate); 22 | } 23 | 24 | @Override 25 | protected Class componentType() { 26 | Class decoderClass = null; 27 | if (getDefaultConfiguration() != null && getDefaultConfiguration().getDecoder() != null) 28 | decoderClass = getDefaultConfiguration().getDecoder(); 29 | 30 | if (getCurrentConfiguration() != null && getCurrentConfiguration().getDecoder() != null) 31 | decoderClass = getCurrentConfiguration().getDecoder(); 32 | 33 | if (decoderClass != null) 34 | return decoderClass; 35 | return Decoder.class; 36 | } 37 | 38 | @Override 39 | public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException { 40 | return delegate().decode(response, type); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/main/java/io/microsphere/spring/cloud/openfeign/components/DecoratedEncoder.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.components; 2 | 3 | import feign.RequestTemplate; 4 | import feign.codec.EncodeException; 5 | import feign.codec.Encoder; 6 | import org.springframework.cloud.context.named.NamedContextFactory; 7 | import org.springframework.cloud.openfeign.FeignClientProperties; 8 | import org.springframework.cloud.openfeign.FeignClientSpecification; 9 | 10 | import java.lang.reflect.Type; 11 | 12 | /** 13 | * @author 韩超 14 | * @since 0.0.1 15 | */ 16 | public class DecoratedEncoder extends DecoratedFeignComponent implements Encoder { 17 | 18 | public DecoratedEncoder(String contextId, NamedContextFactory contextFactory, FeignClientProperties clientProperties, Encoder delegate) { 19 | super(contextId, contextFactory, clientProperties, delegate); 20 | } 21 | 22 | @Override 23 | protected Class componentType() { 24 | Class encoderClass = null; 25 | if (getDefaultConfiguration() != null && getDefaultConfiguration().getEncoder() != null) 26 | encoderClass = getDefaultConfiguration().getEncoder(); 27 | 28 | if (getCurrentConfiguration() != null && getCurrentConfiguration().getEncoder() != null) 29 | encoderClass = getCurrentConfiguration().getEncoder(); 30 | 31 | if (encoderClass != null) 32 | return encoderClass; 33 | return Encoder.class; 34 | } 35 | 36 | @Override 37 | public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException { 38 | delegate().encode(object, bodyType, template); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/main/java/io/microsphere/spring/cloud/openfeign/components/DecoratedErrorDecoder.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.components; 2 | 3 | import feign.Response; 4 | import feign.codec.ErrorDecoder; 5 | import org.springframework.cloud.context.named.NamedContextFactory; 6 | import org.springframework.cloud.openfeign.FeignClientProperties; 7 | import org.springframework.cloud.openfeign.FeignClientSpecification; 8 | 9 | /** 10 | * @author 韩超 11 | * @since 0.0.1 12 | */ 13 | public class DecoratedErrorDecoder extends DecoratedFeignComponent implements ErrorDecoder { 14 | 15 | public DecoratedErrorDecoder(String contextId, NamedContextFactory contextFactory, FeignClientProperties clientProperties, ErrorDecoder delegate) { 16 | super(contextId, contextFactory, clientProperties, delegate); 17 | } 18 | 19 | @Override 20 | protected Class componentType() { 21 | Class errorDecoderClass = null; 22 | if (getDefaultConfiguration() != null && getDefaultConfiguration().getErrorDecoder() != null) 23 | errorDecoderClass = getDefaultConfiguration().getErrorDecoder(); 24 | 25 | if (getCurrentConfiguration() != null && getCurrentConfiguration().getErrorDecoder() != null) 26 | errorDecoderClass = getCurrentConfiguration().getErrorDecoder(); 27 | 28 | if (errorDecoderClass != null) 29 | return errorDecoderClass; 30 | return ErrorDecoder.class; 31 | } 32 | 33 | @Override 34 | public Exception decode(String methodKey, Response response) { 35 | return delegate().decode(methodKey, response); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/main/java/io/microsphere/spring/cloud/openfeign/components/DecoratedFeignComponent.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.components; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.BeanInstantiationException; 6 | import org.springframework.beans.BeanUtils; 7 | import org.springframework.cloud.context.named.NamedContextFactory; 8 | import org.springframework.cloud.openfeign.FeignClientProperties; 9 | import org.springframework.cloud.openfeign.FeignClientSpecification; 10 | import org.springframework.lang.NonNull; 11 | 12 | import java.lang.reflect.Constructor; 13 | import java.util.concurrent.locks.ReentrantReadWriteLock; 14 | 15 | /** 16 | * @author 韩超 17 | * @since 0.0.1 18 | */ 19 | public abstract class DecoratedFeignComponent implements Refreshable { 20 | 21 | private final Logger log = LoggerFactory.getLogger(getClass()); 22 | 23 | //private final FeignClientFactory feignClientFactory; 24 | private final NamedContextFactory contextFactory; 25 | private final String contextId; 26 | 27 | private final FeignClientProperties clientProperties; 28 | 29 | 30 | protected volatile T delegate; 31 | 32 | private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); 33 | 34 | private final ReentrantReadWriteLock.ReadLock readLock = lock.readLock(); 35 | private final ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock(); 36 | 37 | public DecoratedFeignComponent(String contextId, NamedContextFactory contextFactory, FeignClientProperties clientProperties, T delegate) { 38 | this.contextId = contextId; 39 | this.contextFactory = contextFactory; 40 | this.clientProperties = clientProperties; 41 | this.delegate = delegate; 42 | } 43 | 44 | public T delegate() { 45 | readLock.lock(); 46 | if (delegate == null) { 47 | log.trace("the component {} - Creating delegate instance for contextId: {}", componentType().getSimpleName(), contextId); 48 | readLock.unlock(); 49 | return loadInstance(); 50 | } 51 | 52 | readLock.unlock(); 53 | return this.delegate; 54 | } 55 | 56 | @NonNull 57 | public T loadInstanceFromContextFactory(String contextId, Class componentType) { 58 | T component = this.contextFactory.getInstance(contextId, componentType); 59 | if (component == null) 60 | return this.contextFactory.getParent().getAutowireCapableBeanFactory().createBean(componentType); 61 | return component; 62 | } 63 | 64 | @NonNull 65 | public String contextId() { 66 | return this.contextId; 67 | } 68 | 69 | public void refresh() { 70 | writeLock.lock(); 71 | log.debug("the component {} - Refreshing delegate instance for contextId: {}", componentType().getSimpleName(), contextId); 72 | this.delegate = null; 73 | writeLock.unlock(); 74 | } 75 | 76 | protected abstract Class componentType(); 77 | 78 | public FeignClientProperties.FeignClientConfiguration getDefaultConfiguration() { 79 | return this.clientProperties.getConfig().get(this.clientProperties.getDefaultConfig()); 80 | } 81 | 82 | public FeignClientProperties.FeignClientConfiguration getCurrentConfiguration() { 83 | return this.clientProperties.getConfig().get(contextId); 84 | } 85 | 86 | protected T loadInstance() { 87 | Class componentType = componentType(); 88 | String contextId = contextId(); 89 | writeLock.lock(); 90 | try { 91 | T component = loadInstanceFromContextFactory(contextId, componentType); 92 | this.delegate = component; 93 | return component; 94 | } catch (Throwable ex) { 95 | this.delegate = BeanUtils.instantiateClass(componentType); 96 | return delegate; 97 | } finally { 98 | writeLock.unlock(); 99 | } 100 | } 101 | 102 | @Override 103 | public int hashCode() { 104 | return delegate().hashCode(); 105 | } 106 | 107 | @Override 108 | public boolean equals(Object obj) { 109 | return delegate().equals(obj); 110 | } 111 | 112 | @Override 113 | public String toString() { 114 | return delegate().toString(); 115 | } 116 | 117 | public static , T> W instantiate(Class decoratedClass, Class componentClass, 118 | String contextId, NamedContextFactory contextFactory, FeignClientProperties clientProperties, T delegate) { 119 | try { 120 | Constructor constructor = decoratedClass.getConstructor(String.class, NamedContextFactory.class, FeignClientProperties.class, componentClass); 121 | return BeanUtils.instantiateClass(constructor, contextId, contextFactory, clientProperties, delegate); 122 | } catch (NoSuchMethodException noSuchMethodException) { 123 | throw new BeanInstantiationException(decoratedClass, noSuchMethodException.getLocalizedMessage()); 124 | } 125 | 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/main/java/io/microsphere/spring/cloud/openfeign/components/DecoratedQueryMapEncoder.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.components; 2 | 3 | import feign.QueryMapEncoder; 4 | import io.microsphere.logging.Logger; 5 | import org.springframework.cloud.context.named.NamedContextFactory; 6 | import org.springframework.cloud.openfeign.FeignClientProperties; 7 | import org.springframework.cloud.openfeign.FeignClientSpecification; 8 | 9 | import java.lang.invoke.MethodHandle; 10 | import java.util.Map; 11 | 12 | import static io.microsphere.invoke.MethodHandleUtils.findVirtual; 13 | import static io.microsphere.logging.LoggerFactory.getLogger; 14 | 15 | /** 16 | * @author 韩超 17 | * @since 0.0.1 18 | */ 19 | public class DecoratedQueryMapEncoder extends DecoratedFeignComponent implements QueryMapEncoder { 20 | 21 | private static final Logger logger = getLogger(DecoratedQueryMapEncoder.class); 22 | 23 | private static final String getQueryMapEncoderMethodName = "getQueryMapEncoder"; 24 | 25 | private static final MethodHandle getQueryMapEncoderMethodHandle = findVirtual(FeignClientProperties.FeignClientConfiguration.class, getQueryMapEncoderMethodName); 26 | 27 | public DecoratedQueryMapEncoder(String contextId, NamedContextFactory contextFactory, FeignClientProperties clientProperties, QueryMapEncoder delegate) { 28 | super(contextId, contextFactory, clientProperties, delegate); 29 | } 30 | 31 | @Override 32 | protected Class componentType() { 33 | Class queryMapEncoderClass = getQueryMapEncoder(getCurrentConfiguration()); 34 | if (queryMapEncoderClass == null) { 35 | queryMapEncoderClass = getQueryMapEncoder(getDefaultConfiguration()); 36 | } 37 | return queryMapEncoderClass == null ? QueryMapEncoder.class : queryMapEncoderClass; 38 | } 39 | 40 | private Class getQueryMapEncoder(FeignClientProperties.FeignClientConfiguration feignClientConfiguration) { 41 | if (feignClientConfiguration == null || getQueryMapEncoderMethodHandle == null) { 42 | return null; 43 | } 44 | Class queryMapEncoderClass = null; 45 | try { 46 | queryMapEncoderClass = (Class) getQueryMapEncoderMethodHandle.invokeExact(feignClientConfiguration); 47 | } catch (Throwable e) { 48 | if (logger.isWarnEnabled()) { 49 | logger.warn("FeignClientProperties.FeignClientConfiguration#getQueryMapEncoder() method can't be invoked , instance : {}", feignClientConfiguration); 50 | } 51 | } 52 | return queryMapEncoderClass; 53 | } 54 | 55 | @Override 56 | public Map encode(Object object) { 57 | return delegate().encode(object); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/main/java/io/microsphere/spring/cloud/openfeign/components/DecoratedRetryer.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.components; 2 | 3 | import feign.RetryableException; 4 | import feign.Retryer; 5 | import org.springframework.cloud.context.named.NamedContextFactory; 6 | import org.springframework.cloud.openfeign.FeignClientProperties; 7 | import org.springframework.cloud.openfeign.FeignClientSpecification; 8 | 9 | /** 10 | * @author 韩超 11 | * @since 0.0.1 12 | */ 13 | public class DecoratedRetryer extends DecoratedFeignComponent implements Retryer { 14 | 15 | public DecoratedRetryer(String contextId, NamedContextFactory contextFactory, FeignClientProperties clientProperties, Retryer delegate) { 16 | super(contextId, contextFactory, clientProperties, delegate); 17 | } 18 | 19 | @Override 20 | protected Class componentType() { 21 | Class retryerClass = null; 22 | if (getDefaultConfiguration() != null && getDefaultConfiguration().getRetryer() != null) 23 | retryerClass = getDefaultConfiguration().getRetryer(); 24 | 25 | if (getCurrentConfiguration() != null && getCurrentConfiguration().getRetryer() != null) 26 | retryerClass = getCurrentConfiguration().getRetryer(); 27 | 28 | if (retryerClass != null) 29 | return retryerClass; 30 | return Retryer.class; 31 | } 32 | 33 | @Override 34 | public void continueOrPropagate(RetryableException e) { 35 | Retryer retryer = delegate(); 36 | if (retryer != null) 37 | retryer.continueOrPropagate(e); 38 | } 39 | 40 | @Override 41 | public Retryer clone() { 42 | return delegate().clone(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/main/java/io/microsphere/spring/cloud/openfeign/components/NoOpRequestInterceptor.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.components; 2 | 3 | import feign.RequestInterceptor; 4 | import feign.RequestTemplate; 5 | 6 | /** 7 | * @author 韩超 8 | * @since 0.0.1 9 | */ 10 | public class NoOpRequestInterceptor implements RequestInterceptor { 11 | 12 | public static final NoOpRequestInterceptor INSTANCE = new NoOpRequestInterceptor(); 13 | 14 | private NoOpRequestInterceptor() {}; 15 | 16 | @Override 17 | public void apply(RequestTemplate template) { 18 | //no op 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/main/java/io/microsphere/spring/cloud/openfeign/components/Refreshable.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.components; 2 | 3 | /** 4 | * @author 韩超 5 | * @since 0.0.1 6 | */ 7 | @FunctionalInterface 8 | public interface Refreshable { 9 | void refresh(); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.microsphere.spring.cloud.openfeign.autoconfigure.FeignClientAutoRefreshAutoConfiguration -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/BaseClient.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign; 2 | 3 | import org.springframework.cloud.openfeign.FeignClient; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RequestBody; 6 | import org.springframework.web.bind.annotation.RequestParam; 7 | 8 | /** 9 | * @author 韩超 10 | * @since 0.0.1 11 | */ 12 | @FeignClient(contextId = "my-client", name = "my-client", configuration = {MockCapability.class}) 13 | public interface BaseClient { 14 | 15 | @GetMapping("echo") 16 | public String echo(@RequestBody String value, @RequestParam("version") String version); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/BaseTest.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign; 2 | 3 | import io.microsphere.spring.cloud.openfeign.autoconfigure.EnableFeignAutoRefresh; 4 | import org.junit.jupiter.api.Test; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.cloud.context.environment.EnvironmentChangeEvent; 9 | import org.springframework.cloud.endpoint.event.RefreshEvent; 10 | import org.springframework.cloud.openfeign.EnableFeignClients; 11 | import org.springframework.context.ApplicationEventPublisher; 12 | import org.springframework.context.annotation.ComponentScan; 13 | import org.springframework.core.env.ConfigurableEnvironment; 14 | import org.springframework.core.env.Environment; 15 | import org.springframework.core.env.MapPropertySource; 16 | import org.springframework.core.env.MutablePropertySources; 17 | import org.springframework.test.context.TestPropertySource; 18 | 19 | import java.util.Collections; 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | import java.util.Set; 23 | 24 | /** 25 | * @author 韩超 26 | * @since 0.0.1 27 | */ 28 | @TestPropertySource(properties = { 29 | "spring.main.allow-bean-definition-overriding=true", 30 | "spring.cloud.openfeign.client.config.default.encoder=io.microsphere.spring.cloud.openfeign.encoder.AEncoder", 31 | "spring.cloud.openfeign.client.config.default.error-decoder=io.microsphere.spring.cloud.openfeign.errordecoder.AErrorDecoder", 32 | "spring.cloud.openfeign.client.config.default.query-map-encoder=io.microsphere.spring.cloud.openfeign.querymapencoder.AQueryMapEncoder", 33 | "spring.cloud.openfeign.client.config.default.retryer=io.microsphere.spring.cloud.openfeign.retryer.ARetry", 34 | "spring.cloud.openfeign.client.config.default.decoder=io.microsphere.spring.cloud.openfeign.decoder.ADecoder", 35 | "spring.cloud.openfeign.client.config.default.request-interceptors[0]=io.microsphere.spring.cloud.openfeign.requestInterceptor.ARequestInterceptor", 36 | "spring.cloud.openfeign.client.config.default.default-request-headers.app=my-app", 37 | "spring.cloud.openfeign.client.config.default.default-query-parameters.sign=my-sign", 38 | }) 39 | @ComponentScan(basePackages = "io.microsphere.spring.cloud.openfeign") 40 | @EnableFeignClients(clients = BaseClient.class) 41 | @EnableFeignAutoRefresh 42 | public abstract class BaseTest { 43 | 44 | private static final Logger log = LoggerFactory.getLogger(BaseTest.class); 45 | @Autowired 46 | private ApplicationEventPublisher publisher; 47 | @Autowired 48 | private Environment environment; 49 | @Autowired 50 | private BaseClient client; 51 | 52 | protected abstract String afterTestComponentConfigKey(); 53 | protected abstract Class beforeTestComponentClass(); 54 | protected abstract Class afterTestComponent(); 55 | protected abstract FeignComponentAssert loadFeignComponentAssert(); 56 | 57 | public void replaceConfig() { 58 | final String key = afterTestComponentConfigKey(); 59 | Set keys = Collections.singleton(key); 60 | final Class className = afterTestComponent(); 61 | MutablePropertySources propertySources = ((ConfigurableEnvironment)this.environment).getPropertySources(); 62 | Map map = new HashMap<>(); 63 | log.trace("replacing config key {} with value {}", key, className.getName()); 64 | map.put(key, className); 65 | propertySources.addFirst(new MapPropertySource("after", map)); 66 | 67 | EnvironmentChangeEvent event = new EnvironmentChangeEvent(keys); 68 | 69 | triggerRefreshEvent(); 70 | 71 | this.publisher.publishEvent(event); 72 | } 73 | 74 | @Test 75 | public void testInternal() { 76 | ObservableFeignInvocationHandler.componentAssert = loadFeignComponentAssert(); 77 | 78 | ObservableFeignInvocationHandler.expectComponentClass = beforeTestComponentClass(); 79 | try { 80 | this.client.echo("hello", "1.0"); 81 | } catch (Exception ignored) { 82 | } 83 | replaceConfig(); 84 | 85 | ObservableFeignInvocationHandler.expectComponentClass = afterTestComponent(); 86 | try { 87 | this.client.echo("world", "1.0"); 88 | } catch (Exception ignored) { 89 | 90 | } 91 | } 92 | 93 | protected void triggerRefreshEvent() { 94 | this.publisher.publishEvent(new RefreshEvent(new Object(), new Object(), "test")); 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/FeignComponentAssert.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign; 2 | 3 | import feign.ResponseHandler; 4 | 5 | /** 6 | * @author 韩超 7 | * @since 0.0.1 8 | */ 9 | public abstract class FeignComponentAssert { 10 | 11 | 12 | protected abstract T loadCurrentComponent(Object configuration, ResponseHandler responseHandler) throws Exception; 13 | 14 | public boolean expect(Object configuration, ResponseHandler responseHandler, Class expectedClass) throws Exception { 15 | T component = loadCurrentComponent(configuration, responseHandler); 16 | return expectedClass.equals(component.getClass()); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/MockCapability.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign; 2 | 3 | import feign.Capability; 4 | import feign.InvocationHandlerFactory; 5 | 6 | /** 7 | * @author 韩超 8 | * @since 0.0.1 9 | */ 10 | public class MockCapability implements Capability { 11 | 12 | @Override 13 | public InvocationHandlerFactory enrich(InvocationHandlerFactory invocationHandlerFactory) { 14 | return ObservableFeignInvocationHandler::new; 15 | } 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/ObservableFeignInvocationHandler.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign; 2 | 3 | import feign.InvocationHandlerFactory; 4 | import feign.ResponseHandler; 5 | import feign.Target; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.util.Assert; 9 | import org.springframework.util.ClassUtils; 10 | 11 | import java.lang.reflect.Field; 12 | import java.lang.reflect.InvocationHandler; 13 | import java.lang.reflect.Method; 14 | import java.lang.reflect.Proxy; 15 | import java.util.Map; 16 | 17 | import static feign.Util.checkNotNull; 18 | 19 | /** 20 | * @author 韩超 21 | * @since 0.0.1 22 | */ 23 | public class ObservableFeignInvocationHandler implements InvocationHandler { 24 | 25 | 26 | private static final Logger log = LoggerFactory.getLogger(ObservableFeignInvocationHandler.class); 27 | public static FeignComponentAssert componentAssert; 28 | public static Class expectComponentClass; 29 | 30 | private final Target target; 31 | private final Map dispatch; 32 | 33 | ObservableFeignInvocationHandler(Target target, Map dispatch) { 34 | this.target = checkNotNull(target, "target"); 35 | this.dispatch = checkNotNull(dispatch, "dispatch for %s", target); 36 | } 37 | 38 | @Override 39 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 40 | if ("equals".equals(method.getName())) { 41 | try { 42 | Object otherHandler = 43 | args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null; 44 | return equals(otherHandler); 45 | } catch (IllegalArgumentException e) { 46 | return false; 47 | } 48 | } else if ("hashCode".equals(method.getName())) { 49 | return hashCode(); 50 | } else if ("toString".equals(method.getName())) { 51 | return toString(); 52 | } else if (!dispatch.containsKey(method)) { 53 | throw new UnsupportedOperationException( 54 | String.format("Method \"%s\" should not be called", method.getName())); 55 | } 56 | 57 | InvocationHandlerFactory.MethodHandler methodHandler = dispatch.get(method); 58 | Object methodHandlerConfiguration = loadMethodHandlerConfiguration(methodHandler); 59 | ResponseHandler responseHandler = loadResponseHandler(methodHandler); 60 | Assert.isTrue(componentAssert.expect(methodHandlerConfiguration, responseHandler, expectComponentClass), "unexpected component"); 61 | log.info("component validation is True"); 62 | return dispatch.get(method).invoke(args); 63 | } 64 | 65 | protected Object loadMethodHandlerConfiguration(InvocationHandlerFactory.MethodHandler methodHandler) throws Exception { 66 | if (ClassUtils.isPresent("feign.MethodHandlerConfiguration", ObservableFeignInvocationHandler.class.getClassLoader())) { 67 | Class configurationType = methodHandler.getClass(); 68 | Field field = configurationType.getDeclaredField("methodHandlerConfiguration"); 69 | field.setAccessible(true); 70 | return field.get(methodHandler); 71 | } 72 | return methodHandler; 73 | 74 | } 75 | 76 | protected ResponseHandler loadResponseHandler(InvocationHandlerFactory.MethodHandler methodHandler) throws Exception { 77 | Class configurationType = methodHandler.getClass(); 78 | Field field = configurationType.getDeclaredField("responseHandler"); 79 | field.setAccessible(true); 80 | return (ResponseHandler) field.get(methodHandler); 81 | } 82 | 83 | @Override 84 | public boolean equals(Object obj) { 85 | if (obj instanceof ObservableFeignInvocationHandler) { 86 | ObservableFeignInvocationHandler other = (ObservableFeignInvocationHandler) obj; 87 | return target.equals(other.target); 88 | } 89 | return false; 90 | } 91 | 92 | @Override 93 | public int hashCode() { 94 | return target.hashCode(); 95 | } 96 | 97 | @Override 98 | public String toString() { 99 | return target.toString(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/decoder/ADecoder.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.decoder; 2 | 3 | import feign.FeignException; 4 | import feign.Response; 5 | import feign.codec.DecodeException; 6 | import feign.codec.Decoder; 7 | 8 | import java.io.IOException; 9 | import java.lang.reflect.Type; 10 | 11 | /** 12 | * @author 韩超 13 | * @since 0.0.1 14 | */ 15 | public class ADecoder implements Decoder { 16 | 17 | @Override 18 | public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException { 19 | return null; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/decoder/BDecoder.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.decoder; 2 | 3 | import feign.FeignException; 4 | import feign.Response; 5 | import feign.codec.DecodeException; 6 | import feign.codec.Decoder; 7 | 8 | import java.io.IOException; 9 | import java.lang.reflect.Type; 10 | 11 | /** 12 | * @author 韩超 13 | * @since 0.0.1 14 | */ 15 | public class BDecoder implements Decoder { 16 | 17 | @Override 18 | public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException { 19 | return null; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/decoder/DecoderChangedTest.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.decoder; 2 | 3 | import feign.codec.Decoder; 4 | import io.microsphere.spring.cloud.openfeign.BaseTest; 5 | import io.microsphere.spring.cloud.openfeign.FeignComponentAssert; 6 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | 9 | /** 10 | * @author 韩超 11 | * @since 0.0.1 12 | */ 13 | @SpringBootTest(classes = DecoderChangedTest.class) 14 | @EnableAutoConfiguration 15 | public class DecoderChangedTest extends BaseTest { 16 | 17 | @Override 18 | protected String afterTestComponentConfigKey() { 19 | return "spring.cloud.openfeign.client.config.my-client.decoder"; 20 | } 21 | 22 | @Override 23 | protected Class beforeTestComponentClass() { 24 | return ADecoder.class; 25 | } 26 | 27 | @Override 28 | protected Class afterTestComponent() { 29 | return BDecoder.class; 30 | } 31 | 32 | @Override 33 | protected FeignComponentAssert loadFeignComponentAssert() { 34 | return new DecoderComponentAssert(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/decoder/DecoderComponentAssert.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.decoder; 2 | 3 | import feign.ResponseHandler; 4 | import feign.codec.Decoder; 5 | import io.microsphere.spring.cloud.openfeign.FeignComponentAssert; 6 | import io.microsphere.spring.cloud.openfeign.components.DecoratedDecoder; 7 | 8 | import java.lang.reflect.Field; 9 | 10 | /** 11 | * @author 韩超 12 | * @since 0.0.1 13 | */ 14 | public class DecoderComponentAssert extends FeignComponentAssert { 15 | 16 | @Override 17 | protected Decoder loadCurrentComponent(Object configuration, ResponseHandler responseHandler) throws Exception { 18 | Class responseHandlerClass = ResponseHandler.class; 19 | Field decoderField = responseHandlerClass.getDeclaredField("decoder"); 20 | decoderField.setAccessible(true); 21 | DecoratedDecoder decoder = (DecoratedDecoder)decoderField.get(responseHandler); 22 | return decoder.delegate(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/encoder/AEncoder.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.encoder; 2 | 3 | import feign.RequestTemplate; 4 | import feign.codec.EncodeException; 5 | import feign.codec.Encoder; 6 | 7 | import java.lang.reflect.Type; 8 | 9 | /** 10 | * @author 韩超 11 | * @since 0.0.1 12 | */ 13 | public class AEncoder implements Encoder { 14 | 15 | @Override 16 | public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException { 17 | template.body(object.toString()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/encoder/BEncoder.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.encoder; 2 | 3 | import feign.RequestTemplate; 4 | import feign.codec.EncodeException; 5 | import feign.codec.Encoder; 6 | 7 | import java.lang.reflect.Type; 8 | 9 | /** 10 | * @author 韩超 11 | * @since 0.0.1 12 | */ 13 | public class BEncoder implements Encoder { 14 | 15 | @Override 16 | public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException { 17 | template.body(object.toString()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/encoder/EncoderChangedTest.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.encoder; 2 | 3 | import feign.codec.Encoder; 4 | import io.microsphere.spring.cloud.openfeign.BaseTest; 5 | import io.microsphere.spring.cloud.openfeign.FeignComponentAssert; 6 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | 9 | /** 10 | * @author 韩超 11 | * @since 0.0.1 12 | */ 13 | @SpringBootTest(classes = EncoderChangedTest.class) 14 | @EnableAutoConfiguration 15 | public class EncoderChangedTest extends BaseTest { 16 | 17 | 18 | @Override 19 | protected Class beforeTestComponentClass() { 20 | return AEncoder.class; 21 | } 22 | 23 | @Override 24 | protected FeignComponentAssert loadFeignComponentAssert() { 25 | return EncoderComponentAssert.INSTANCE; 26 | } 27 | 28 | @Override 29 | protected String afterTestComponentConfigKey() { 30 | return "spring.cloud.openfeign.client.config.my-client.encoder"; 31 | } 32 | 33 | @Override 34 | protected Class afterTestComponent() { 35 | return BEncoder.class; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/encoder/EncoderComponentAssert.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.encoder; 2 | 3 | import feign.ResponseHandler; 4 | import feign.codec.Encoder; 5 | import io.microsphere.spring.cloud.openfeign.FeignComponentAssert; 6 | import io.microsphere.spring.cloud.openfeign.components.DecoratedEncoder; 7 | 8 | import java.lang.reflect.Field; 9 | 10 | /** 11 | * @author 韩超 12 | * @since 0.0.1 13 | */ 14 | public class EncoderComponentAssert extends FeignComponentAssert { 15 | 16 | public static final EncoderComponentAssert INSTANCE = new EncoderComponentAssert(); 17 | 18 | private EncoderComponentAssert() { 19 | 20 | } 21 | 22 | @Override 23 | protected Encoder loadCurrentComponent(Object configuration, ResponseHandler responseHandler) throws Exception { 24 | Class configurationClass = configuration.getClass(); 25 | Field buildTemplateFromArgs = configurationClass.getDeclaredField("buildTemplateFromArgs"); 26 | buildTemplateFromArgs.setAccessible(true); 27 | Object buildTemplateFromArgsValue = buildTemplateFromArgs.get(configuration); 28 | Class buildTemplateFromArgsType = buildTemplateFromArgsValue.getClass(); 29 | Field encoderField = buildTemplateFromArgsType.getDeclaredField("encoder"); 30 | encoderField.setAccessible(true); 31 | DecoratedEncoder encoder = (DecoratedEncoder)encoderField.get(buildTemplateFromArgsValue); 32 | return encoder.delegate(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/errordecoder/AErrorDecoder.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.errordecoder; 2 | 3 | import feign.Response; 4 | import feign.codec.ErrorDecoder; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | /** 9 | * @author 韩超 10 | * @since 1.0 11 | */ 12 | public class AErrorDecoder implements ErrorDecoder { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(AErrorDecoder.class); 15 | 16 | @Override 17 | public Exception decode(String methodKey, Response response) { 18 | return new IllegalArgumentException(""); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/errordecoder/BErrorEncoder.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.errordecoder; 2 | 3 | import feign.Response; 4 | import feign.codec.ErrorDecoder; 5 | 6 | /** 7 | * @author 韩超 8 | * @since 0.0.1 9 | */ 10 | public class BErrorEncoder implements ErrorDecoder { 11 | 12 | @Override 13 | public Exception decode(String methodKey, Response response) { 14 | return null; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/errordecoder/ErrorDecoderChangedTest.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.errordecoder; 2 | 3 | import feign.codec.ErrorDecoder; 4 | import io.microsphere.spring.cloud.openfeign.BaseTest; 5 | import io.microsphere.spring.cloud.openfeign.FeignComponentAssert; 6 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | 9 | /** 10 | * @author 韩超 11 | * @since 1.0 12 | */ 13 | @SpringBootTest(classes = ErrorDecoderChangedTest.class) 14 | @EnableAutoConfiguration 15 | public class ErrorDecoderChangedTest extends BaseTest { 16 | 17 | @Override 18 | protected Class beforeTestComponentClass() { 19 | return AErrorDecoder.class; 20 | } 21 | 22 | @Override 23 | protected FeignComponentAssert loadFeignComponentAssert() { 24 | return new ErrorDecoderComponentAssert(); 25 | } 26 | 27 | @Override 28 | protected String afterTestComponentConfigKey() { 29 | return "spring.cloud.openfeign.client.config.my-client.error-decoder"; 30 | } 31 | 32 | @Override 33 | protected Class afterTestComponent() { 34 | return BErrorEncoder.class; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/errordecoder/ErrorDecoderComponentAssert.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.errordecoder; 2 | 3 | import feign.ResponseHandler; 4 | import feign.codec.ErrorDecoder; 5 | import io.microsphere.spring.cloud.openfeign.FeignComponentAssert; 6 | import io.microsphere.spring.cloud.openfeign.components.DecoratedErrorDecoder; 7 | 8 | import java.lang.reflect.Field; 9 | 10 | /** 11 | * @author 韩超 12 | * @since 0.0.1 13 | */ 14 | public class ErrorDecoderComponentAssert extends FeignComponentAssert { 15 | 16 | @Override 17 | protected ErrorDecoder loadCurrentComponent(Object configuration, ResponseHandler responseHandler) throws Exception { 18 | Class responseHandlerClass = ResponseHandler.class; 19 | Field errorDecoderField = responseHandlerClass.getDeclaredField("errorDecoder"); 20 | errorDecoderField.setAccessible(true); 21 | DecoratedErrorDecoder errorDecoder = (DecoratedErrorDecoder)errorDecoderField.get(responseHandler); 22 | return errorDecoder.delegate(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/querymapencoder/AQueryMapEncoder.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.querymapencoder; 2 | 3 | import feign.QueryMapEncoder; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * @author 韩超 12 | * @since 1.0 13 | */ 14 | public class AQueryMapEncoder implements QueryMapEncoder { 15 | 16 | 17 | private static final Logger log = LoggerFactory.getLogger(AQueryMapEncoder.class); 18 | 19 | @Override 20 | public Map encode(Object object) { 21 | return new HashMap<>(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/querymapencoder/BQueryMapEncoder.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.querymapencoder; 2 | 3 | import feign.QueryMapEncoder; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * @author 韩超 12 | * @since 1.0 13 | */ 14 | public class BQueryMapEncoder implements QueryMapEncoder { 15 | 16 | 17 | private static final Logger log = LoggerFactory.getLogger(BQueryMapEncoder.class); 18 | 19 | @Override 20 | public Map encode(Object object) { 21 | return new HashMap<>(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/querymapencoder/QueryMapEncoderChangedTest.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.querymapencoder; 2 | 3 | import feign.QueryMapEncoder; 4 | import io.microsphere.spring.cloud.openfeign.BaseTest; 5 | import io.microsphere.spring.cloud.openfeign.FeignComponentAssert; 6 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | 9 | /** 10 | * @author 韩超 11 | * @since 1.0 12 | */ 13 | @SpringBootTest(classes = QueryMapEncoderChangedTest.class) 14 | @EnableAutoConfiguration 15 | public class QueryMapEncoderChangedTest extends BaseTest { 16 | 17 | @Override 18 | protected Class beforeTestComponentClass() { 19 | return AQueryMapEncoder.class; 20 | } 21 | 22 | @Override 23 | protected FeignComponentAssert loadFeignComponentAssert() { 24 | return new QueryMapEncoderComponentAssert(); 25 | } 26 | 27 | @Override 28 | protected String afterTestComponentConfigKey() { 29 | return "spring.cloud.openfeign.client.config.my-client.query-map-encoder"; 30 | } 31 | 32 | @Override 33 | protected Class afterTestComponent() { 34 | return BQueryMapEncoder.class; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/querymapencoder/QueryMapEncoderComponentAssert.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.querymapencoder; 2 | 3 | import feign.QueryMapEncoder; 4 | import feign.ResponseHandler; 5 | import io.microsphere.spring.cloud.openfeign.FeignComponentAssert; 6 | import io.microsphere.spring.cloud.openfeign.components.DecoratedQueryMapEncoder; 7 | 8 | import java.lang.reflect.Field; 9 | 10 | /** 11 | * @author 韩超 12 | * @since 0.0.1 13 | */ 14 | public class QueryMapEncoderComponentAssert extends FeignComponentAssert { 15 | 16 | @Override 17 | protected QueryMapEncoder loadCurrentComponent(Object configuration, ResponseHandler responseHandler) throws Exception { 18 | Class configurationClass = configuration.getClass(); 19 | Field buildTemplateFromArgs = configurationClass.getDeclaredField("buildTemplateFromArgs"); 20 | buildTemplateFromArgs.setAccessible(true); 21 | Object buildTemplateFromArgsValue = buildTemplateFromArgs.get(configuration); 22 | Class buildTemplateFromArgsType = buildTemplateFromArgsValue.getClass().getSuperclass(); 23 | Field encoderField = buildTemplateFromArgsType.getDeclaredField("queryMapEncoder"); 24 | encoderField.setAccessible(true); 25 | DecoratedQueryMapEncoder encoder = (DecoratedQueryMapEncoder)encoderField.get(buildTemplateFromArgsValue); 26 | return encoder.delegate(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/requestInterceptor/ARequestInterceptor.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.requestInterceptor; 2 | 3 | import feign.RequestInterceptor; 4 | import feign.RequestTemplate; 5 | 6 | /** 7 | * @author 韩超 8 | * @since 0.0.1 9 | */ 10 | public class ARequestInterceptor implements RequestInterceptor { 11 | 12 | @Override 13 | public void apply(RequestTemplate template) { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/requestInterceptor/BRequestInterceptor.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.requestInterceptor; 2 | 3 | import feign.RequestInterceptor; 4 | import feign.RequestTemplate; 5 | 6 | /** 7 | * @author 韩超 8 | * @since 0.0.1 9 | */ 10 | public class BRequestInterceptor implements RequestInterceptor { 11 | 12 | @Override 13 | public void apply(RequestTemplate template) { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/requestInterceptor/RequestInterceptorChangedTest.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.requestInterceptor; 2 | 3 | import feign.RequestInterceptor; 4 | import io.microsphere.spring.cloud.openfeign.BaseTest; 5 | import io.microsphere.spring.cloud.openfeign.FeignComponentAssert; 6 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | 9 | /** 10 | * @author 韩超 11 | * @since 0.0.1 12 | */ 13 | @SpringBootTest(classes = RequestInterceptorChangedTest.class, webEnvironment = SpringBootTest.WebEnvironment.NONE) 14 | @EnableAutoConfiguration 15 | public class RequestInterceptorChangedTest extends BaseTest { 16 | 17 | @Override 18 | protected Class beforeTestComponentClass() { 19 | return ARequestInterceptor.class; 20 | } 21 | 22 | @Override 23 | protected FeignComponentAssert loadFeignComponentAssert() { 24 | return new RequestInterceptorComponentAssert(); 25 | } 26 | 27 | @Override 28 | protected String afterTestComponentConfigKey() { 29 | return "spring.cloud.openfeign.client.config.my-client.request-interceptors[0]"; 30 | } 31 | 32 | @Override 33 | protected Class afterTestComponent() { 34 | return BRequestInterceptor.class; 35 | } 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/requestInterceptor/RequestInterceptorComponentAssert.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.requestInterceptor; 2 | 3 | import feign.RequestInterceptor; 4 | import feign.ResponseHandler; 5 | import io.microsphere.spring.cloud.openfeign.FeignComponentAssert; 6 | import io.microsphere.spring.cloud.openfeign.components.CompositedRequestInterceptor; 7 | 8 | import java.lang.reflect.Field; 9 | import java.util.List; 10 | 11 | /** 12 | * @author 韩超 13 | * @since 0.0.1 14 | */ 15 | public class RequestInterceptorComponentAssert extends FeignComponentAssert { 16 | 17 | @Override 18 | protected CompositedRequestInterceptor loadCurrentComponent(Object configuration, ResponseHandler responseHandler) throws Exception { 19 | Class configurationClass = configuration.getClass(); 20 | Field retryField = configurationClass.getDeclaredField("requestInterceptors"); 21 | retryField.setAccessible(true); 22 | List retryer = (List) retryField.get(configuration); 23 | for (RequestInterceptor interceptor : retryer) { 24 | if (interceptor instanceof CompositedRequestInterceptor) { 25 | return (CompositedRequestInterceptor) interceptor; 26 | } 27 | } 28 | return null; 29 | } 30 | 31 | @Override 32 | public boolean expect(Object configuration, ResponseHandler responseHandler, Class expectedClass) throws Exception { 33 | CompositedRequestInterceptor requestInterceptor = loadCurrentComponent(configuration, responseHandler); 34 | for(RequestInterceptor interceptor : requestInterceptor.getRequestInterceptors()) { 35 | if (expectedClass.equals(interceptor.getClass())) 36 | return true; 37 | } 38 | return false; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/retryer/ARetry.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.retryer; 2 | 3 | import feign.RetryableException; 4 | import feign.Retryer; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | /** 9 | * @author 韩超 10 | * @since 1.0 11 | */ 12 | public class ARetry implements Retryer { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(ARetry.class); 15 | 16 | @Override 17 | public void continueOrPropagate(RetryableException e) { 18 | log.trace("Attempting to propagate exception", e); 19 | } 20 | 21 | @Override 22 | public Retryer clone() { 23 | return this; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/retryer/BRetry.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.retryer; 2 | 3 | import feign.RetryableException; 4 | import feign.Retryer; 5 | 6 | /** 7 | * @author 韩超 8 | * @since 0.0.1 9 | */ 10 | public class BRetry implements Retryer { 11 | 12 | @Override 13 | public void continueOrPropagate(RetryableException e) { 14 | 15 | } 16 | 17 | @Override 18 | public Retryer clone() { 19 | return this; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/retryer/RetryerChangedTest.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.retryer; 2 | 3 | import feign.Retryer; 4 | import io.microsphere.spring.cloud.openfeign.BaseTest; 5 | import io.microsphere.spring.cloud.openfeign.FeignComponentAssert; 6 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | 9 | /** 10 | * @author 韩超 11 | * @since 1.0 12 | */ 13 | @SpringBootTest(classes = RetryerChangedTest.class) 14 | @EnableAutoConfiguration 15 | public class RetryerChangedTest extends BaseTest { 16 | 17 | @Override 18 | protected Class beforeTestComponentClass() { 19 | return ARetry.class; 20 | } 21 | 22 | @Override 23 | protected FeignComponentAssert loadFeignComponentAssert() { 24 | return new RetryerComponentAssert(); 25 | } 26 | 27 | @Override 28 | protected String afterTestComponentConfigKey() { 29 | return "spring.cloud.openfeign.client.config.my-client.retryer"; 30 | } 31 | 32 | @Override 33 | protected Class afterTestComponent() { 34 | return BRetry.class; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /microsphere-spring-cloud-openfeign/src/test/java/io/microsphere/spring/cloud/openfeign/retryer/RetryerComponentAssert.java: -------------------------------------------------------------------------------- 1 | package io.microsphere.spring.cloud.openfeign.retryer; 2 | 3 | import feign.ResponseHandler; 4 | import feign.Retryer; 5 | import io.microsphere.spring.cloud.openfeign.FeignComponentAssert; 6 | import io.microsphere.spring.cloud.openfeign.components.DecoratedRetryer; 7 | 8 | import java.lang.reflect.Field; 9 | 10 | /** 11 | * @author 韩超 12 | * @since 0.0.1 13 | */ 14 | public class RetryerComponentAssert extends FeignComponentAssert { 15 | 16 | @Override 17 | protected Retryer loadCurrentComponent(Object configuration, ResponseHandler responseHandler) throws Exception { 18 | Class configurationClass = configuration.getClass(); 19 | Field retryField = configurationClass.getDeclaredField("retryer"); 20 | retryField.setAccessible(true); 21 | DecoratedRetryer retryer = (DecoratedRetryer) retryField.get(configuration); 22 | return retryer.delegate(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | io.github.microsphere-projects 7 | microsphere-build 8 | 0.1.1 9 | 10 | 4.0.0 11 | 12 | io.github.microsphere-projects 13 | microsphere-spring-cloud 14 | ${revision} 15 | pom 16 | 17 | Microsphere :: Spring Cloud 18 | Microsphere Spring Cloud 19 | https://github.com/microsphere-projects/microsphere-spring-cloud 20 | 21 | 22 | Microsphere 23 | https://github.com/microsphere-projects 24 | 25 | 26 | 27 | 28 | Apache License, Version 2.0 29 | http://www.apache.org/licenses/LICENSE-2.0 30 | repo 31 | 32 | 33 | 34 | 35 | 36 | mercyblitz 37 | Mercy Ma 38 | mercyblitz@gmail.com 39 | Microsphere 40 | 41 | lead 42 | architect 43 | developer 44 | 45 | 46 | 47 | 48 | 49 | git@github.com/microsphere-projects/microsphere-spring-cloud.git 50 | scm:git:${project.scm.url} 51 | scm:git:ssh://${project.scm.url} 52 | 53 | 54 | 55 | 2.0.0-SNAPSHOT 56 | 17 57 | 58 | 59 | 60 | microsphere-spring-cloud-parent 61 | microsphere-spring-cloud-dependencies 62 | microsphere-spring-cloud-commons 63 | microsphere-spring-cloud-openfeign 64 | 65 | 66 | 67 | 68 | ossrh 69 | https://s01.oss.sonatype.org/content/repositories/snapshots 70 | 71 | 72 | ossrh 73 | https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ 74 | 75 | 76 | 77 | 78 | 79 | snapshot 80 | 81 | true 82 | 83 | 84 | false 85 | 86 | https://s01.oss.sonatype.org/content/repositories/snapshots 87 | 88 | 89 | 90 | --------------------------------------------------------------------------------