Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
1d808c6
Bump project version to 0.2.4-SNAPSHOT
mercyblitz Oct 31, 2025
e8ff821
Add constants for reactive discovery client auto configs
mercyblitz Oct 31, 2025
e9c4aba
Add tests for new reactive discovery client constants
mercyblitz Oct 31, 2025
838b9f2
Add @AutoConfigureAfter to ReactiveDiscoveryClientAutoConfiguration
mercyblitz Oct 31, 2025
608b8f2
Add DiscoveryUtils utility class for service discovery
mercyblitz Oct 31, 2025
dca8d66
Add unit tests for DiscoveryUtils utility class
mercyblitz Oct 31, 2025
4cdf936
Add support for SimpleReactiveDiscoveryProperties
mercyblitz Oct 31, 2025
40ab6b8
Add constructor test for SimpleServiceRegistry
mercyblitz Oct 31, 2025
da39278
Add setProperties method to ServiceInstanceUtils
mercyblitz Oct 31, 2025
91605f7
Add test for setProperties in ServiceInstanceUtilsTest
mercyblitz Oct 31, 2025
d4ccf71
Set URI directly in setProperties method
mercyblitz Oct 31, 2025
dc714ce
Enhance DiscoveryUtils with property copying and null checks
mercyblitz Oct 31, 2025
7935f59
Default port in URL if ServiceInstance port is invalid
mercyblitz Oct 31, 2025
bcd555f
Add tests for getUriString and getUri without port
mercyblitz Oct 31, 2025
75aa901
Update property mapping in setProperties method
mercyblitz Oct 31, 2025
9e3928d
Remove unnecessary blank line in ServiceInstanceUtilsTest
mercyblitz Oct 31, 2025
e8920dd
Update pom.xml
mercyblitz Oct 31, 2025
cc321e8
Add constant for load balancer enabled property
mercyblitz Oct 31, 2025
55195f3
Add unit test for SpringCloudPropertyConstants
mercyblitz Oct 31, 2025
f49d2e4
Add ConditionalOnLoadBalancerEnabled annotation
mercyblitz Oct 31, 2025
4a73fd3
Add test for ConditionalOnLoadBalancerEnabled
mercyblitz Oct 31, 2025
2d51c53
Add property constant for Spring Cloud Util enablement
mercyblitz Oct 31, 2025
28df584
Add test for UTIL_ENABLED_PROPERTY_NAME constant
mercyblitz Oct 31, 2025
adf8b37
Refactor ConditionalOnLoadBalancerEnabledTest class usage
mercyblitz Oct 31, 2025
348a220
Add ConditionalOnUtilEnabled annotation
mercyblitz Oct 31, 2025
07a6b8b
Add test for ConditionalOnUtilEnabled annotation
mercyblitz Oct 31, 2025
1ae8929
Fix test class reference in condition test cases
mercyblitz Oct 31, 2025
37cb99c
Update ConditionalOnUtilEnabledTest.java
mercyblitz Oct 31, 2025
4a86a66
Update ConditionalOnLoadBalancerEnabledTest.java
mercyblitz Oct 31, 2025
0f8b69f
Update BeanUtils import to microsphere package in tests
mercyblitz Oct 31, 2025
754e504
Refactor conditional property tests to use shared base class
mercyblitz Oct 31, 2025
29641b9
Remove unused matchIfMissing attribute from annotation
mercyblitz Oct 31, 2025
3e9cf7c
Update ReactiveDiscoveryClientAdapter.java
mercyblitz Oct 31, 2025
9c96e04
Add tests for ReactiveDiscoveryClientAdapter.toList
mercyblitz Oct 31, 2025
367ef3b
Merge pull request #83 from microsphere-projects/dev
mercyblitz Oct 31, 2025
22bbdc4
Update README.md
mercyblitz Oct 31, 2025
fd1d5cd
Merge pull request #85 from microsphere-projects/dev
mercyblitz Oct 31, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ pom.xml:

| **Branches** | **Purpose** | **Latest Version** |
|--------------|--------------------------------------------------|--------------------|
| **0.2.x** | Compatible with Spring Cloud 2022.0.x - 2025.0.x | 0.2.3 |
| **0.1.x** | Compatible with Spring Cloud Hoxton - 2021.0.x | 0.1.3 |
| **0.2.x** | Compatible with Spring Cloud 2022.0.x - 2025.0.x | 0.2.4 |
| **0.1.x** | Compatible with Spring Cloud Hoxton - 2021.0.x | 0.1.4 |

Then add the specific modules you need:

Expand Down
5 changes: 5 additions & 0 deletions microsphere-spring-cloud-commons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
<optional>true</optional>
</dependency>

<!-- Netflix Eureka Client -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import org.springframework.cloud.client.CommonsClientAutoConfiguration;
import org.springframework.cloud.client.actuator.FeaturesEndpoint;
import org.springframework.cloud.client.actuator.HasFeatures;
import org.springframework.core.annotation.AliasFor;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
Expand All @@ -47,15 +46,6 @@
@Retention(RUNTIME)
@Target({TYPE, METHOD})
@Documented
@ConditionalOnProperty(name = FEATURES_ENABLED_PROPERTY_NAME)
@ConditionalOnProperty(name = FEATURES_ENABLED_PROPERTY_NAME, matchIfMissing = true)
public @interface ConditionalOnFeaturesEnabled {

/**
* Specify if the condition should match if the property is not set. Defaults to
* {@code true}.
*
* @return if the condition should match if the property is missing
*/
@AliasFor(annotation = ConditionalOnProperty.class, attribute = "matchIfMissing")
boolean matchIfMissing() default true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;

import static io.microsphere.lang.function.ThrowableSupplier.execute;
import static reactor.core.scheduler.Schedulers.isInNonBlockingThread;

/**
* An adapter {@link DiscoveryClient} class based on {@link ReactiveDiscoveryClient}
*
Expand Down Expand Up @@ -67,6 +71,10 @@ public int getOrder() {
}

static <T> List<T> toList(Flux<T> flux) {
return flux.collectList().block();
Mono<List<T>> mono = flux.collectList();
if (isInNonBlockingThread()) {
return execute(() -> mono.toFuture().get());
}
return mono.block();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package io.microsphere.spring.cloud.client.discovery.autoconfigure;

import io.microsphere.spring.cloud.client.discovery.ReactiveDiscoveryClientAdapter;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
Expand All @@ -30,6 +31,8 @@

import static io.microsphere.spring.cloud.client.discovery.constants.DiscoveryClientConstants.DISCOVERY_CLIENT_CLASS_NAME;
import static io.microsphere.spring.cloud.client.discovery.constants.DiscoveryClientConstants.REACTIVE_COMMONS_CLIENT_AUTO_CONFIGURATION_CLASS_NAME;
import static io.microsphere.spring.cloud.client.discovery.constants.DiscoveryClientConstants.REACTIVE_COMPOSITE_DISCOVERY_CLIENT_AUTO_CONFIGURATION_CLASS_NAME;
import static io.microsphere.spring.cloud.client.discovery.constants.DiscoveryClientConstants.SIMPLE_REACTIVE_DISCOVERY_CLIENT_AUTO_CONFIGURATION_CLASS_NAME;

/**
* The Auto-Configuration class for {@link ReactiveDiscoveryClient}
Expand All @@ -48,6 +51,10 @@
@AutoConfigureBefore(name = {
REACTIVE_COMMONS_CLIENT_AUTO_CONFIGURATION_CLASS_NAME
})
@AutoConfigureAfter(name = {
SIMPLE_REACTIVE_DISCOVERY_CLIENT_AUTO_CONFIGURATION_CLASS_NAME,
REACTIVE_COMPOSITE_DISCOVERY_CLIENT_AUTO_CONFIGURATION_CLASS_NAME
})
public class ReactiveDiscoveryClientAutoConfiguration {

@Configuration(proxyBeanMethods = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import org.springframework.cloud.client.ReactiveCommonsClientAutoConfiguration;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClient;
import org.springframework.cloud.client.discovery.composite.reactive.ReactiveCompositeDiscoveryClientAutoConfiguration;
import org.springframework.cloud.client.discovery.simple.reactive.SimpleReactiveDiscoveryClientAutoConfiguration;

/**
* The constants for {@link DiscoveryClient}
Expand Down Expand Up @@ -56,4 +58,18 @@ public interface DiscoveryClientConstants {
* @see org.springframework.cloud.client.ReactiveCommonsClientAutoConfiguration
*/
String REACTIVE_COMMONS_CLIENT_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.client.ReactiveCommonsClientAutoConfiguration";

/**
* The class name of {@link SimpleReactiveDiscoveryClientAutoConfiguration}
*
* @see org.springframework.cloud.client.discovery.simple.reactive.SimpleReactiveDiscoveryClientAutoConfiguration
*/
String SIMPLE_REACTIVE_DISCOVERY_CLIENT_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.client.discovery.simple.reactive.SimpleReactiveDiscoveryClientAutoConfiguration";

/**
* The class name of {@link ReactiveCompositeDiscoveryClientAutoConfiguration}
*
* @see org.springframework.cloud.client.discovery.composite.reactive.ReactiveCompositeDiscoveryClientAutoConfiguration
*/
String REACTIVE_COMPOSITE_DISCOVERY_CLIENT_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.client.discovery.composite.reactive.ReactiveCompositeDiscoveryClientAutoConfiguration";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.microsphere.spring.cloud.client.discovery.util;

import io.microsphere.annotation.Nonnull;
import io.microsphere.util.Utils;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryProperties;
import org.springframework.cloud.client.discovery.simple.reactive.SimpleReactiveDiscoveryProperties;

import java.util.List;
import java.util.Map;

import static io.microsphere.reflect.MethodUtils.invokeMethod;
import static io.microsphere.spring.cloud.client.service.util.ServiceInstanceUtils.setProperties;

/**
* The utilities class for Spring Cloud Discovery
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @see Utils
* @since 1.0.0
*/
public abstract class DiscoveryUtils implements Utils {

/**
* Get the instances map from {@link SimpleDiscoveryProperties}
*
* @param properties {@link SimpleDiscoveryProperties}
* @return the instances map
*/
@Nonnull
public static Map<String, List<DefaultServiceInstance>> getInstancesMap(@Nonnull SimpleDiscoveryProperties properties) {
return properties.getInstances();
}

/**
* Get the instances map from {@link SimpleReactiveDiscoveryProperties}
*
* @param properties {@link SimpleReactiveDiscoveryProperties}
* @return the instances map
*/
@Nonnull
public static Map<String, List<DefaultServiceInstance>> getInstancesMap(@Nonnull SimpleReactiveDiscoveryProperties properties) {
return invokeMethod(properties, "getInstances");
}

/**
* Convert {@link SimpleDiscoveryProperties} to {@link SimpleReactiveDiscoveryProperties}
*
* @param properties {@link SimpleDiscoveryProperties}
* @return {@link SimpleReactiveDiscoveryProperties}
*/
@Nonnull
public static SimpleReactiveDiscoveryProperties simpleReactiveDiscoveryProperties(@Nonnull SimpleDiscoveryProperties properties) {
SimpleReactiveDiscoveryProperties simpleReactiveDiscoveryProperties = new SimpleReactiveDiscoveryProperties();
simpleReactiveDiscoveryProperties.setOrder(properties.getOrder());

DefaultServiceInstance local = properties.getLocal();
DefaultServiceInstance targetLocal = simpleReactiveDiscoveryProperties.getLocal();
setProperties(targetLocal, local);

Map<String, List<DefaultServiceInstance>> instances = getInstancesMap(properties);
simpleReactiveDiscoveryProperties.setInstances(instances);

return simpleReactiveDiscoveryProperties;
}

/**
* Convert {@link SimpleReactiveDiscoveryProperties} to {@link SimpleDiscoveryProperties}
*
* @param properties {@link SimpleReactiveDiscoveryProperties}
* @return {@link SimpleDiscoveryProperties}
*/
@Nonnull
public static SimpleDiscoveryProperties simpleDiscoveryProperties(@Nonnull SimpleReactiveDiscoveryProperties properties) {
SimpleDiscoveryProperties simpleDiscoveryProperties = new SimpleDiscoveryProperties();
simpleDiscoveryProperties.setOrder(properties.getOrder());

DefaultServiceInstance local = properties.getLocal();
simpleDiscoveryProperties.setInstance(local.getServiceId(), local.getHost(), local.getPort());

Map<String, List<DefaultServiceInstance>> instances = invokeMethod(properties, "getInstances");
simpleDiscoveryProperties.setInstances(instances);

return simpleDiscoveryProperties;
}

private DiscoveryUtils() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,27 @@

import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryProperties;
import org.springframework.cloud.client.discovery.simple.reactive.SimpleReactiveDiscoveryProperties;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static io.microsphere.spring.cloud.client.discovery.util.DiscoveryUtils.getInstancesMap;
import static io.microsphere.spring.cloud.client.service.util.ServiceInstanceUtils.getMetadata;
import static io.microsphere.spring.cloud.client.service.util.ServiceInstanceUtils.setMetadata;

/**
* Simple {@link ServiceRegistry} class that is based on {@link SimpleDiscoveryProperties} to register
* Simple {@link ServiceRegistry} class that is based on {@link SimpleDiscoveryProperties}
* or {@link SimpleReactiveDiscoveryProperties} to register
* {@link DefaultRegistration}.
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @see ServiceRegistry
* @see DefaultRegistration
* @see SimpleDiscoveryProperties#getInstances()
* @see SimpleReactiveDiscoveryProperties#getInstances()
* @since 1.0.0
*/
public class SimpleServiceRegistry implements ServiceRegistry<DefaultRegistration> {
Expand All @@ -44,8 +48,16 @@ public class SimpleServiceRegistry implements ServiceRegistry<DefaultRegistratio

private final Map<String, List<DefaultServiceInstance>> instancesMap;

public SimpleServiceRegistry(SimpleDiscoveryProperties simpleDiscoveryProperties) {
this.instancesMap = simpleDiscoveryProperties.getInstances();
public SimpleServiceRegistry(SimpleDiscoveryProperties properties) {
this(getInstancesMap(properties));
}

public SimpleServiceRegistry(SimpleReactiveDiscoveryProperties properties) {
this(getInstancesMap(properties));
}

public SimpleServiceRegistry(Map<String, List<DefaultServiceInstance>> instancesMap) {
this.instancesMap = instancesMap;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import static io.microsphere.util.StringUtils.EMPTY_STRING;
import static io.microsphere.util.StringUtils.EMPTY_STRING_ARRAY;
import static io.microsphere.util.StringUtils.isBlank;
import static java.lang.String.valueOf;
import static java.net.URI.create;
import static java.util.Collections.emptyList;

Expand Down Expand Up @@ -102,12 +103,16 @@ public static String getUriString(ServiceInstance instance) {
boolean isSecure = instance.isSecure();
String prefix = isSecure ? "https://" : "http://";
String host = instance.getHost();
String port = String.valueOf(instance.getPort());
StringBuilder urlStringBuilder = new StringBuilder((isSecure ? 9 : 8) + host.length() + port.length());
int port = instance.getPort();
if (port <= 0) {
port = isSecure ? 443 : 80;
}
String portString = valueOf(port);
StringBuilder urlStringBuilder = new StringBuilder((isSecure ? 9 : 8) + host.length() + portString.length());
urlStringBuilder.append(prefix)
.append(host)
.append(COLON_CHAR)
.append(port);
.append(portString);
return urlStringBuilder.toString();
}

Expand Down Expand Up @@ -162,6 +167,23 @@ public static String removeMetadata(ServiceInstance serviceInstance, String meta
return metadata.remove(metadataName);
}

/**
* Set properties from source to target
*
* @param source source {@link ServiceInstance}
* @param target target {@link DefaultServiceInstance}
*/
public static void setProperties(ServiceInstance source, DefaultServiceInstance target) {
target.setInstanceId(source.getInstanceId());
target.setServiceId(source.getServiceId());
target.setSecure(source.isSecure());
target.setHost(source.getHost());
target.setPort(source.getPort());
Map<String, String> metadata = source.getMetadata();
metadata.clear();
metadata.putAll(source.getMetadata());
}

static List<WebEndpointMapping> parseWebEndpointMappings(String encodedJSON) {
if (isBlank(encodedJSON)) {
return emptyList();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.microsphere.spring.cloud.commons.condition;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.commons.util.UtilAutoConfiguration;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static io.microsphere.spring.cloud.commons.constants.SpringCloudPropertyConstants.UTIL_ENABLED_PROPERTY_NAME;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
* The conditional annotation meta-annotates {@link ConditionalOnProperty @ConditionalOnProperty} for
* {@link UtilAutoConfiguration} enabled.
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @see UtilAutoConfiguration
* @see ConditionalOnProperty
* @since 1.0.0
*/
@Retention(RUNTIME)
@Target({TYPE, METHOD})
@Documented
@ConditionalOnProperty(name = UTIL_ENABLED_PROPERTY_NAME, matchIfMissing = true)
public @interface ConditionalOnUtilEnabled {
}
Loading