From d40555eff464b8b8e28ce8393ff83c6adf856ee6 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 11 Jan 2019 13:04:34 +0800 Subject: [PATCH] Polish spring-cloud-incubator/spring-cloud-alibaba#269 --- spring-cloud-alibaba-dubbo/pom.xml | 158 +++++++ .../DubboRestAutoConfiguration.java | 30 ++ ...oServiceRegistrationAutoConfiguration.java | 46 ++ .../dubbo/registry/DubboRegistration.java | 72 ++++ .../dubbo/registry/SpringCloudRegistry.java | 405 ++++++++++++++++++ .../registry/SpringCloudRegistryFactory.java | 49 +++ ...com.alibaba.dubbo.registry.RegistryFactory | 1 + .../main/resources/META-INF/spring.factories | 3 + ...viceRegistrationAutoConfigurationTest.java | 28 ++ .../bootstrap/DubboSpringCloudBootstrap.java | 52 +++ .../dubbo/service/DefaultEchoService.java | 39 ++ .../alibaba/dubbo/service/EchoService.java | 27 ++ .../src/test/resources/application.yaml | 9 + .../src/test/resources/bootstrap.yaml | 26 ++ 14 files changed, 945 insertions(+) create mode 100644 spring-cloud-alibaba-dubbo/pom.xml create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DubboRegistration.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistryFactory.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory create mode 100644 spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories create mode 100644 spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfigurationTest.java create mode 100644 spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java create mode 100644 spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java create mode 100644 spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/EchoService.java create mode 100644 spring-cloud-alibaba-dubbo/src/test/resources/application.yaml create mode 100644 spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml diff --git a/spring-cloud-alibaba-dubbo/pom.xml b/spring-cloud-alibaba-dubbo/pom.xml new file mode 100644 index 00000000..1a7d27ac --- /dev/null +++ b/spring-cloud-alibaba-dubbo/pom.xml @@ -0,0 +1,158 @@ + + + + spring-cloud-alibaba + org.springframework.cloud + 0.2.2.BUILD-SNAPSHOT + ../pom.xml + + 4.0.0 + + spring-cloud-alibaba-dubbo + Spring Cloud Alibaba Dubbo + + + + + + org.springframework.boot + spring-boot-actuator + true + + + + org.springframework.boot + spring-boot-actuator-autoconfigure + true + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.springframework.boot + spring-boot + true + + + + org.springframework.boot + spring-boot-autoconfigure + true + + + + + org.springframework.cloud + spring-cloud-commons + true + + + + org.springframework.cloud + spring-cloud-context + true + + + + org.springframework.cloud + spring-cloud-starter-openfeign + true + + + + + com.alibaba.boot + dubbo-spring-boot-starter + + + + com.alibaba + dubbo + + + + + io.netty + netty-all + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + io.github.openfeign + feign-jaxrs2 + 9.7.0 + + + + + junit + junit + test + + + + org.springframework + spring-test + test + + + + org.springframework.boot + spring-boot-starter-web + test + + + + org.springframework.boot + spring-boot-test + test + + + + + org.springframework.cloud + spring-cloud-starter-alibaba-nacos-discovery + test + + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + test + + + + \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java new file mode 100644 index 00000000..7108cbbf --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboRestAutoConfiguration.java @@ -0,0 +1,30 @@ +/* + * 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 org.springframework.cloud.alibaba.dubbo.autoconfigure; + +import org.springframework.context.annotation.Configuration; + +/** + * Spring Boot Auto-Configuration class for Dubbo REST + * + * @author Mercy + */ +@Configuration +public class DubboRestAutoConfiguration { + + +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java new file mode 100644 index 00000000..b9bae981 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java @@ -0,0 +1,46 @@ +/* + * 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 org.springframework.cloud.alibaba.dubbo.autoconfigure; + +import com.alibaba.boot.dubbo.autoconfigure.DubboAutoConfiguration; + +import org.springframework.beans.BeansException; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistryFactory; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.Configuration; + +/** + * {@link DubboServiceRegistrationAutoConfiguration} will register the Dubbo services as the specified Spring cloud + * applications that will not be considered normal ones, but only are used to Dubbo's service discovery even if it is + * based on Spring Cloud Commons abstraction. However, current application will be registered by other + * DiscoveryClientAutoConfiguration. + * + * @author Mercy + */ +@Configuration +@AutoConfigureBefore({AutoServiceRegistrationAutoConfiguration.class, DubboAutoConfiguration.class}) +public class DubboServiceRegistrationAutoConfiguration implements ApplicationContextAware { + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + // Set ApplicationContext into SpringCloudRegistryFactory before Dubbo Service Register + SpringCloudRegistryFactory.setApplicationContext(applicationContext); + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DubboRegistration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DubboRegistration.java new file mode 100644 index 00000000..9a435ff2 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DubboRegistration.java @@ -0,0 +1,72 @@ +/* + * 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 org.springframework.cloud.alibaba.dubbo.registry; + +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.serviceregistry.Registration; + +import java.net.URI; +import java.util.Map; + +/** + * The {@link Registration} of Dubbo uses an external of {@link ServiceInstance} instance as the delegate. + * + * @author Mercy + */ +class DubboRegistration implements Registration { + + private final ServiceInstance delegate; + + public DubboRegistration(ServiceInstance delegate) { + this.delegate = delegate; + } + + @Override + public String getServiceId() { + return delegate.getServiceId(); + } + + @Override + public String getHost() { + return delegate.getHost(); + } + + @Override + public int getPort() { + return delegate.getPort(); + } + + @Override + public boolean isSecure() { + return delegate.isSecure(); + } + + @Override + public URI getUri() { + return delegate.getUri(); + } + + @Override + public Map getMetadata() { + return delegate.getMetadata(); + } + + @Override + public String getScheme() { + return delegate.getScheme(); + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java new file mode 100644 index 00000000..aa93c7e5 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java @@ -0,0 +1,405 @@ +/* + * 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 org.springframework.cloud.alibaba.dubbo.registry; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.common.utils.UrlUtils; +import com.alibaba.dubbo.registry.NotifyListener; +import com.alibaba.dubbo.registry.RegistryFactory; +import com.alibaba.dubbo.registry.support.FailbackRegistry; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.client.DefaultServiceInstance; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.util.StringUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import static com.alibaba.dubbo.common.Constants.CONFIGURATORS_CATEGORY; +import static com.alibaba.dubbo.common.Constants.CONSUMERS_CATEGORY; +import static com.alibaba.dubbo.common.Constants.PROVIDERS_CATEGORY; +import static com.alibaba.dubbo.common.Constants.ROUTERS_CATEGORY; + +/** + * Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud" + * + * @author Mercy + */ +public class SpringCloudRegistry extends FailbackRegistry { + + /** + * All supported categories + */ + private static final String[] ALL_SUPPORTED_CATEGORIES = of( + PROVIDERS_CATEGORY, + CONSUMERS_CATEGORY, + ROUTERS_CATEGORY, + CONFIGURATORS_CATEGORY + ); + + private static final int CATEGORY_INDEX = 0; + + private static final int SERVICE_INTERFACE_INDEX = 1; + + private static final int SERVICE_VERSION_INDEX = 2; + + private static final int SERVICE_GROUP_INDEX = 3; + + private static final String WILDCARD = "*"; + + /** + * The separator for service name + */ + private static final String SERVICE_NAME_SEPARATOR = ":"; + + private final ServiceRegistry serviceRegistry; + + private final DiscoveryClient discoveryClient; + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + /** + * {@link ScheduledExecutorService} lookup service names(only for Dubbo-OPS) + */ + private volatile ScheduledExecutorService scheduledExecutorService; + + /** + * The interval in second of lookup service names(only for Dubbo-OPS) + */ + private static final long LOOKUP_INTERVAL = Long.getLong("dubbo.service.names.lookup.interval", 30); + + public SpringCloudRegistry(URL url, ServiceRegistry serviceRegistry, + DiscoveryClient discoveryClient) { + super(url); + this.serviceRegistry = serviceRegistry; + this.discoveryClient = discoveryClient; + } + + @Override + protected void doRegister(URL url) { + final String serviceName = getServiceName(url); + final Registration registration = createRegistration(serviceName, url); + serviceRegistry.register(registration); + } + + @Override + protected void doUnregister(URL url) { + final String serviceName = getServiceName(url); + final Registration registration = createRegistration(serviceName, url); + this.serviceRegistry.deregister(registration); + } + + @Override + protected void doSubscribe(URL url, NotifyListener listener) { + List serviceNames = getServiceNames(url, listener); + doSubscribe(url, listener, serviceNames); + } + + @Override + protected void doUnsubscribe(URL url, NotifyListener listener) { + if (isAdminProtocol(url)) { + shutdownServiceNamesLookup(); + } + } + + @Override + public boolean isAvailable() { + return false; + } + + private void shutdownServiceNamesLookup() { + if (scheduledExecutorService != null) { + scheduledExecutorService.shutdown(); + } + } + + private Registration createRegistration(String serviceName, URL url) { + return new DubboRegistration(createServiceInstance(serviceName, url)); + } + + private ServiceInstance createServiceInstance(String serviceName, URL url) { + // Append default category if absent + String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY); + URL newURL = url.addParameter(Constants.CATEGORY_KEY, category); + newURL = newURL.addParameter(Constants.PROTOCOL_KEY, url.getProtocol()); + String ip = NetUtils.getLocalHost(); + int port = newURL.getParameter(Constants.BIND_PORT_KEY, url.getPort()); + DefaultServiceInstance serviceInstance = new DefaultServiceInstance(serviceName, ip, port, false); + serviceInstance.getMetadata().putAll(new LinkedHashMap<>(newURL.getParameters())); + return serviceInstance; + } + + private String getServiceName(URL url) { + String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY); + return getServiceName(url, category); + } + + private String getServiceName(URL url, String category) { + StringBuilder serviceNameBuilder = new StringBuilder(category); + appendIfPresent(serviceNameBuilder, url, Constants.INTERFACE_KEY); + appendIfPresent(serviceNameBuilder, url, Constants.VERSION_KEY); + appendIfPresent(serviceNameBuilder, url, Constants.GROUP_KEY); + return serviceNameBuilder.toString(); + } + + private void appendIfPresent(StringBuilder target, URL url, String parameterName) { + String parameterValue = url.getParameter(parameterName); + if (StringUtils.hasText(parameterValue)) { + target.append(SERVICE_NAME_SEPARATOR).append(parameterValue); + } + } + + private void filterServiceNames(List serviceNames, URL url) { + + final String[] categories = getCategories(url); + + final String targetServiceInterface = url.getServiceInterface(); + + final String targetVersion = url.getParameter(Constants.VERSION_KEY); + + final String targetGroup = url.getParameter(Constants.GROUP_KEY); + + filter(serviceNames, new Filter() { + @Override + public boolean accept(String serviceName) { + // split service name to segments + // (required) segments[0] = category + // (required) segments[1] = serviceInterface + // (required) segments[2] = version + // (optional) segments[3] = group + String[] segments = StringUtils.split(serviceName, SERVICE_NAME_SEPARATOR); + int length = segments.length; + if (length < 3) { // must present 3 segments or more + return false; + } + + String category = segments[CATEGORY_INDEX]; + if (Arrays.binarySearch(categories, category) > -1) { // no match category + return false; + } + + String serviceInterface = segments[SERVICE_INTERFACE_INDEX]; + if (!WILDCARD.equals(targetServiceInterface) && + !Objects.equals(targetServiceInterface, serviceInterface)) { // no match service interface + return false; + } + + String version = segments[SERVICE_VERSION_INDEX]; + if (!WILDCARD.equals(targetVersion) && + !Objects.equals(targetVersion, version)) { // no match service version + return false; + } + + String group = length > 3 ? segments[SERVICE_GROUP_INDEX] : null; + if (group != null && !WILDCARD.equals(targetGroup) + && !Objects.equals(targetGroup, group)) { // no match service group + return false; + } + + return true; + } + }); + } + + /** + * Get the categories from {@link URL} + * + * @param url {@link URL} + * @return non-null array + */ + private String[] getCategories(URL url) { + return Constants.ANY_VALUE.equals(url.getServiceInterface()) ? + ALL_SUPPORTED_CATEGORIES : of(Constants.DEFAULT_CATEGORY); + } + + private List getAllServiceNames() { + return discoveryClient.getServices(); + } + + /** + * Get the service names from the specified {@link URL url} + * + * @param url {@link URL} + * @param listener {@link NotifyListener} + * @return non-null + */ + private List getServiceNames(URL url, NotifyListener listener) { + if (isAdminProtocol(url)) { + scheduleServiceNamesLookup(url, listener); + return getServiceNamesForOps(url); + } else { + return doGetServiceNames(url); + } + } + + + private boolean isAdminProtocol(URL url) { + return Constants.ADMIN_PROTOCOL.equals(url.getProtocol()); + } + + private void scheduleServiceNamesLookup(final URL url, final NotifyListener listener) { + if (scheduledExecutorService == null) { + scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + scheduledExecutorService.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + List serviceNames = getAllServiceNames(); + filter(serviceNames, new Filter() { + @Override + public boolean accept(String serviceName) { + boolean accepted = false; + for (String category : ALL_SUPPORTED_CATEGORIES) { + String prefix = category + SERVICE_NAME_SEPARATOR; + if (StringUtils.startsWithIgnoreCase(serviceName, prefix)) { + accepted = true; + break; + } + } + return accepted; + } + }); + doSubscribe(url, listener, serviceNames); + } + }, LOOKUP_INTERVAL, LOOKUP_INTERVAL, TimeUnit.SECONDS); + } + } + + private void doSubscribe(final URL url, final NotifyListener listener, final List serviceNames) { + for (String serviceName : serviceNames) { + List serviceInstances = discoveryClient.getInstances(serviceName); + notifySubscriber(url, listener, serviceInstances); + // TODO Support Update notification event + } + } + + private List doGetServiceNames(URL url) { + String[] categories = getCategories(url); + List serviceNames = new ArrayList(categories.length); + for (String category : categories) { + final String serviceName = getServiceName(url, category); + serviceNames.add(serviceName); + } + return serviceNames; + } + + /** + * Notify the Healthy {@link ServiceInstance service instance} to subscriber. + * + * @param url {@link URL} + * @param listener {@link NotifyListener} + * @param serviceInstances all {@link ServiceInstance instances} + */ + private void notifySubscriber(URL url, NotifyListener listener, List serviceInstances) { + List healthyInstances = new LinkedList(serviceInstances); + // Healthy Instances + filterHealthyInstances(healthyInstances); + List urls = buildURLs(url, healthyInstances); + this.notify(url, listener, urls); + } + + private void filterHealthyInstances(Collection instances) { + filter(instances, new Filter() { + @Override + public boolean accept(ServiceInstance data) { + // TODO check the details of status + return serviceRegistry.getStatus(new DubboRegistration(data)) != null; + } + }); + } + + private List buildURLs(URL consumerURL, Collection serviceInstances) { + if (serviceInstances.isEmpty()) { + return Collections.emptyList(); + } + List urls = new LinkedList(); + for (ServiceInstance serviceInstance : serviceInstances) { + URL url = buildURL(serviceInstance); + if (UrlUtils.isMatch(consumerURL, url)) { + urls.add(url); + } + } + return urls; + } + + private URL buildURL(ServiceInstance serviceInstance) { + URL url = new URL(serviceInstance.getMetadata().get(Constants.PROTOCOL_KEY), + serviceInstance.getHost(), + serviceInstance.getPort(), + serviceInstance.getMetadata()); + return url; + } + + /** + * Get the service names for Dubbo OPS + * + * @param url {@link URL} + * @return non-null + */ + private List getServiceNamesForOps(URL url) { + List serviceNames = getAllServiceNames(); + filterServiceNames(serviceNames, url); + return serviceNames; + } + + private void filter(Collection collection, Filter filter) { + Iterator iterator = collection.iterator(); + while (iterator.hasNext()) { + T data = iterator.next(); + if (!filter.accept(data)) { // remove if not accept + iterator.remove(); + } + } + } + + private static T[] of(T... values) { + return values; + } + + /** + * A filter + */ + private interface Filter { + + /** + * Tests whether or not the specified data should be accepted. + * + * @param data The data to be tested + * @return true if and only if data + * should be accepted + */ + boolean accept(T data); + + } + +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistryFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistryFactory.java new file mode 100644 index 00000000..7402ff97 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistryFactory.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.registry; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.registry.Registry; +import com.alibaba.dubbo.registry.RegistryFactory; + +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.context.ApplicationContext; + +/** + * Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud" + * + * @author Mercy + * @see RegistryFactory + * @see SpringCloudRegistry + */ +public class SpringCloudRegistryFactory implements RegistryFactory { + + private static ApplicationContext applicationContext; + + @Override + public Registry getRegistry(URL url) { + ServiceRegistry serviceRegistry = applicationContext.getBean(ServiceRegistry.class); + DiscoveryClient discoveryClient = applicationContext.getBean(DiscoveryClient.class); + return new SpringCloudRegistry(url, serviceRegistry, discoveryClient); + } + + public static void setApplicationContext(ApplicationContext applicationContext) { + SpringCloudRegistryFactory.applicationContext = applicationContext; + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory new file mode 100644 index 00000000..77ac945a --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory @@ -0,0 +1 @@ +spring-cloud=org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistryFactory \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..3af4c939 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestAutoConfiguration,\ + org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfigurationTest.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfigurationTest.java new file mode 100644 index 00000000..ce32e641 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfigurationTest.java @@ -0,0 +1,28 @@ +/* + * 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 org.springframework.cloud.alibaba.dubbo.autoconfigure; + +import org.springframework.boot.test.context.SpringBootTest; + +/** + * {@link DubboServiceRegistrationAutoConfiguration} Test + * + * @author Mercy + */ +@SpringBootTest +public class DubboServiceRegistrationAutoConfigurationTest { +} diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java new file mode 100644 index 00000000..72bd95cf --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java @@ -0,0 +1,52 @@ +/* + * 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 org.springframework.cloud.alibaba.dubbo.bootstrap; + +import com.alibaba.dubbo.config.annotation.Reference; + +import org.springframework.boot.ApplicationRunner; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.cloud.alibaba.dubbo.service.EchoService; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.context.annotation.Bean; + +/** + * Dubbo Spring Cloud Bootstrap + */ +@EnableDiscoveryClient +@EnableAutoConfiguration +public class DubboSpringCloudBootstrap { + + @Reference(version = "1.0.0") + private EchoService echoService; + + @Bean + public ApplicationRunner applicationRunner() { + return arguments -> { + System.out.println(echoService.echo("mercyblitz")); + }; + } + + public static void main(String[] args) { + new SpringApplicationBuilder(DubboSpringCloudBootstrap.class) + .run(args); + } +} + + + diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java new file mode 100644 index 00000000..f0fc0ac0 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java @@ -0,0 +1,39 @@ +/* + * 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 org.springframework.cloud.alibaba.dubbo.service; + +import com.alibaba.dubbo.config.annotation.Service; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * Default {@link EchoService} + * + * @author Mercy + */ +@Service(version = "1.0.0") +@RestController +public class DefaultEchoService implements EchoService { + + @Override + @GetMapping("/echo") + public String echo(@RequestParam String message) { + return "[echo] : " + message; + } +} diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/EchoService.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/EchoService.java new file mode 100644 index 00000000..7bc249f4 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/EchoService.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cloud.alibaba.dubbo.service; + +/** + * Echo Service + * + * @author Mercy + */ +public interface EchoService { + + String echo(String message); +} diff --git a/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml b/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml new file mode 100644 index 00000000..65249ca9 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml @@ -0,0 +1,9 @@ + + +dubbo: + scan: + base-packages: org.springframework.cloud.alibaba.dubbo.service + protocol: + port: 12345 + registry: + address: spring-cloud://dummy \ No newline at end of file diff --git a/spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml b/spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml new file mode 100644 index 00000000..9a5062a1 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml @@ -0,0 +1,26 @@ +spring: + application: + name: spring-cloud-alibaba-dubbo + cloud: + nacos: + discovery: + server-addr: 127.0.0.1:8848 + port: 12345 +eureka: + client: + enabled: false + +--- +spring: + profiles: eureka + cloud: + nacos: + discovery: + enabled: false + register-enabled: false + +eureka: + client: + enabled: true + service-url: + defaultZone: http://127.0.0.1:8761/eureka/ \ No newline at end of file