Merge branch 'master' of github.com:spring-cloud-incubator/spring-cloud-alibaba

pull/350/head
xiaolongzuo 6 years ago
commit 5c26eb90e0

@ -94,6 +94,7 @@
<module>spring-cloud-alibaba-fescar</module>
<module>spring-cloud-stream-binder-rocketmq</module>
<module>spring-cloud-alibaba-nacos-config-server</module>
<module>spring-cloud-alibaba-dubbo</module>
<module>spring-cloud-alicloud-context</module>
<module>spring-cloud-alibaba-examples</module>
<module>spring-cloud-alibaba-test</module>
@ -110,6 +111,15 @@
<dependencyManagement>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>

@ -29,6 +29,9 @@
<aliyun.sdk.edas.version>2.16.0</aliyun.sdk.edas.version>
<rocketmq.version>4.3.1</rocketmq.version>
<schedulerX.client.version>2.1.6</schedulerX.client.version>
<dubbo.version>2.6.5</dubbo.version>
<dubbo-spring-boot.version>0.2.1.RELEASE</dubbo-spring-boot.version>
<dubbo-registry-nacos.version>0.0.2</dubbo-registry-nacos.version>
<aliyun.java.sdk.dysmsapi>1.1.0</aliyun.java.sdk.dysmsapi>
<aliyun.sdk.mns>1.1.8</aliyun.sdk.mns>
<aliyun.java.sdk.dysmsapi>1.1.0</aliyun.java.sdk.dysmsapi>
@ -207,6 +210,49 @@
<version>${oss.version}</version>
</dependency>
<!-- Apache Dubbo dependencies-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-dependencies-bom</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Dubbo -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Dubbo Spring Boot Starter -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo-spring-boot.version}</version>
</dependency>
<!-- Dubbo Nacos registry dependency -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>${dubbo-registry-nacos.version}</version>
</dependency>
<!-- Own dependencies -->
<dependency>

@ -0,0 +1,179 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-alibaba</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>0.2.2.BUILD-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-alibaba-dubbo</artifactId>
<name>Spring Cloud Alibaba Dubbo</name>
<dependencies>
<!-- Spring Boot dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator-autoconfigure</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<optional>true</optional>
</dependency>
<!-- Spring Cloud dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<optional>true</optional>
</dependency>
<!-- Dubbo Spring Boot Starter -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<!-- Netty -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
<!-- REST support dependencies -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-netty4</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxb-provider</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- Feign for JAX-RS 2-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jaxrs2</artifactId>
<version>9.7.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- Testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Nacos Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<scope>test</scope>
</dependency>
<!-- Eureka Service Discovery -->
<!--<dependency>-->
<!--<groupId>org.springframework.cloud</groupId>-->
<!--<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!--<scope>test</scope>-->
<!--</dependency>-->
</dependencies>
</project>

@ -0,0 +1,43 @@
/*
* 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.autoconfigure.condition.ConditionalOnBean;
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
import org.springframework.cloud.alibaba.dubbo.metadata.service.MetadataConfigService;
import org.springframework.cloud.alibaba.dubbo.metadata.service.NacosMetadataConfigService;
import org.springframework.cloud.alibaba.nacos.NacosConfigProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* Spring Boot Auto-Configuration class for Dubbo Metadata
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@Configuration
@Import(DubboServiceMetadataRepository.class)
public class DubboMetadataAutoConfiguration {
@Bean
@ConditionalOnBean(NacosConfigProperties.class)
public MetadataConfigService metadataConfigService() {
return new NacosMetadataConfigService();
}
}

@ -0,0 +1,54 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.alibaba.dubbo.autoconfigure;
import feign.Contract;
import feign.Feign;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.alibaba.dubbo.metadata.resolver.FeignMetadataResolver;
import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver;
import org.springframework.cloud.alibaba.dubbo.openfeign.DubboFeignClientsConfiguration;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Dubbo Feign Auto-{@link Configuration Configuration}
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@ConditionalOnClass(value = Feign.class)
@AutoConfigureAfter(FeignAutoConfiguration.class)
@EnableFeignClients(defaultConfiguration = DubboFeignClientsConfiguration.class)
@Configuration
public class DubboOpenFeignAutoConfiguration {
@Value("${spring.application.name}")
private String currentApplicationName;
@Bean
@ConditionalOnMissingBean
public MetadataResolver metadataJsonResolver(ObjectProvider<Contract> contract) {
return new FeignMetadataResolver(currentApplicationName, contract);
}
}

@ -0,0 +1,86 @@
/*
* 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.dubbo.config.spring.ServiceBean;
import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver;
import org.springframework.cloud.alibaba.dubbo.metadata.service.MetadataConfigService;
import org.springframework.cloud.client.discovery.event.InstancePreRegisteredEvent;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* The Auto-Configuration class for Dubbo REST metadata registration,
* REST metadata that is a part of {@link Registration#getMetadata() Spring Cloud service instances' metadata}
* will be registered Spring Cloud registry.
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
@ConditionalOnMissingBean(value = {
MetadataResolver.class,
MetadataConfigService.class
})
@AutoConfigureAfter(value = {DubboMetadataAutoConfiguration.class})
@Configuration
public class DubboRestMetadataRegistrationAutoConfiguration {
/**
* A Map to store REST metadata temporary, its' key is the special service name for a Dubbo service,
* the value is a JSON content of JAX-RS or Spring MVC REST metadata from the annotated methods.
*/
private final Set<ServiceRestMetadata> serviceRestMetadata = new LinkedHashSet<>();
@Autowired
private MetadataResolver metadataResolver;
@Autowired
private MetadataConfigService metadataConfigService;
@EventListener(ServiceBeanExportedEvent.class)
public void recordRestMetadata(ServiceBeanExportedEvent event) throws JsonProcessingException {
ServiceBean serviceBean = event.getServiceBean();
serviceRestMetadata.addAll(metadataResolver.resolveServiceRestMetadata(serviceBean));
}
/**
* Pre-handle Spring Cloud application service registered:
* <p>
* Put <code>restMetadata</code> with the JSON format into
* {@link Registration#getMetadata() service instances' metadata}
* <p>
*
* @param event {@link InstancePreRegisteredEvent} instance
*/
@EventListener(InstancePreRegisteredEvent.class)
public void registerRestMetadata(InstancePreRegisteredEvent event) throws Exception {
Registration registration = event.getRegistration();
metadataConfigService.publishServiceRestMetadata(registration.getServiceId(), serviceRestMetadata);
}
}

@ -0,0 +1,38 @@
/*
* 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.context;
import org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistryFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
/**
* The Dubbo services will be registered 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 <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class DubboServiceRegistrationApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// Set ApplicationContext into SpringCloudRegistryFactory before Dubbo Service Register
SpringCloudRegistryFactory.setApplicationContext(applicationContext);
}
}

@ -0,0 +1,122 @@
/*
* 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.metadata;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.apache.commons.lang3.ClassUtils;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
/**
* {@link Method} Metadata
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class MethodMetadata {
private String name;
private String returnType;
private List<MethodParameterMetadata> params;
@JsonIgnore
private Method method;
public MethodMetadata() {
this.params = new LinkedList<>();
}
public MethodMetadata(Method method) {
this.name = method.getName();
this.returnType = ClassUtils.getName(method.getReturnType());
this.params = initParameters(method);
this.method = method;
}
private List<MethodParameterMetadata> initParameters(Method method) {
int parameterCount = method.getParameterCount();
if (parameterCount < 1) {
return Collections.emptyList();
}
List<MethodParameterMetadata> params = new ArrayList<>(parameterCount);
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameterCount; i++) {
Parameter parameter = parameters[i];
MethodParameterMetadata param = toMethodParameterMetadata(i, parameter);
params.add(param);
}
return params;
}
private MethodParameterMetadata toMethodParameterMetadata(int index, Parameter parameter) {
MethodParameterMetadata metadata = new MethodParameterMetadata();
metadata.setIndex(index);
metadata.setName(parameter.getName());
metadata.setType(parameter.getType().getTypeName());
return metadata;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getReturnType() {
return returnType;
}
public void setReturnType(String returnType) {
this.returnType = returnType;
}
public List<MethodParameterMetadata> getParams() {
return params;
}
public void setParams(List<MethodParameterMetadata> params) {
this.params = params;
}
public Method getMethod() {
return method;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MethodMetadata that = (MethodMetadata) o;
return Objects.equals(name, that.name) &&
Objects.equals(returnType, that.returnType) &&
Objects.equals(params, that.params);
}
@Override
public int hashCode() {
return Objects.hash(name, returnType, params);
}
}

@ -0,0 +1,73 @@
/*
* 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.metadata;
import java.lang.reflect.Method;
import java.util.Objects;
/**
* {@link Method} Parameter Metadata
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class MethodParameterMetadata {
private int index;
private String name;
private String type;
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MethodParameterMetadata that = (MethodParameterMetadata) o;
return index == that.index &&
Objects.equals(name, that.name) &&
Objects.equals(type, that.type);
}
@Override
public int hashCode() {
return Objects.hash(index, name, type);
}
}

@ -0,0 +1,97 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.alibaba.dubbo.metadata;
import feign.RequestTemplate;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
/**
* Request Metadata
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class RequestMetadata {
private String method;
private String url;
private Map<String, Collection<String>> queries;
private Map<String, Collection<String>> headers;
public RequestMetadata() {
}
public RequestMetadata(RequestTemplate requestTemplate) {
this.method = requestTemplate.method();
this.url = requestTemplate.url();
this.queries = requestTemplate.queries();
this.headers = requestTemplate.headers();
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Map<String, Collection<String>> getHeaders() {
return headers;
}
public void setHeaders(Map<String, Collection<String>> headers) {
this.headers = headers;
}
public Map<String, Collection<String>> getQueries() {
return queries;
}
public void setQueries(Map<String, Collection<String>> queries) {
this.queries = queries;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RequestMetadata that = (RequestMetadata) o;
return Objects.equals(method, that.method) &&
Objects.equals(url, that.url) &&
Objects.equals(queries, that.queries) &&
Objects.equals(headers, that.headers);
}
@Override
public int hashCode() {
return Objects.hash(method, url, queries, headers);
}
}

@ -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.metadata;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
/**
* Method Request Metadata
*/
public class RestMethodMetadata {
private MethodMetadata method;
private RequestMetadata request;
private Map<Integer, Collection<String>> indexToName;
public MethodMetadata getMethod() {
return method;
}
public void setMethod(MethodMetadata method) {
this.method = method;
}
public RequestMetadata getRequest() {
return request;
}
public void setRequest(RequestMetadata request) {
this.request = request;
}
public Map<Integer, Collection<String>> getIndexToName() {
return indexToName;
}
public void setIndexToName(Map<Integer, Collection<String>> indexToName) {
this.indexToName = indexToName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RestMethodMetadata that = (RestMethodMetadata) o;
return Objects.equals(method, that.method) &&
Objects.equals(request, that.request) &&
Objects.equals(indexToName, that.indexToName);
}
@Override
public int hashCode() {
return Objects.hash(method, request, indexToName);
}
}

@ -0,0 +1,66 @@
/*
* 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.metadata;
import java.util.Set;
/**
* Service Rest Metadata
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @see RestMethodMetadata
*/
public class ServiceRestMetadata {
private String name;
private Set<RestMethodMetadata> meta;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<RestMethodMetadata> getMeta() {
return meta;
}
public void setMeta(Set<RestMethodMetadata> meta) {
this.meta = meta;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ServiceRestMetadata that = (ServiceRestMetadata) o;
if (name != null ? !name.equals(that.name) : that.name != null) return false;
return meta != null ? meta.equals(that.meta) : that.meta == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (meta != null ? meta.hashCode() : 0);
return result;
}
}

@ -0,0 +1,118 @@
/*
* 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.metadata.repository;
import com.alibaba.dubbo.config.spring.ReferenceBean;
import com.alibaba.dubbo.rpc.service.GenericService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.service.MetadataConfigService;
import org.springframework.stereotype.Repository;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceGroup;
import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceInterface;
import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceSegments;
import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceVersion;
/**
* Dubbo Service Metadata {@link Repository}
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@Repository
public class DubboServiceMetadataRepository {
/**
* Key is application name
* Value is Map<RequestMetadata, GenericService>
*/
private Map<String, Map<RequestMetadata, GenericService>> genericServicesRepository = new HashMap<>();
private Map<String, Map<RequestMetadata, MethodMetadata>> methodMetadataRepository = new HashMap<>();
@Autowired
private MetadataConfigService metadataConfigService;
@Value("${dubbo.target.protocol:dubbo}")
private String targetProtocol;
@Value("${dubbo.target.cluster:failover}")
private String targetCluster;
public void updateMetadata(String serviceName) {
Map<RequestMetadata, GenericService> genericServicesMap = genericServicesRepository.computeIfAbsent(serviceName, k -> new HashMap<>());
Map<RequestMetadata, MethodMetadata> methodMetadataMap = methodMetadataRepository.computeIfAbsent(serviceName, k -> new HashMap<>());
Set<ServiceRestMetadata> serviceRestMetadataSet = metadataConfigService.getServiceRestMetadata(serviceName);
for (ServiceRestMetadata serviceRestMetadata : serviceRestMetadataSet) {
ReferenceBean<GenericService> referenceBean = adaptReferenceBean(serviceRestMetadata);
serviceRestMetadata.getMeta().forEach(restMethodMetadata -> {
RequestMetadata requestMetadata = restMethodMetadata.getRequest();
genericServicesMap.put(requestMetadata, referenceBean.get());
methodMetadataMap.put(requestMetadata, restMethodMetadata.getMethod());
});
}
}
public GenericService getGenericService(String serviceName, RequestMetadata requestMetadata) {
return getGenericServicesMap(serviceName).get(requestMetadata);
}
public MethodMetadata getMethodMetadata(String serviceName, RequestMetadata requestMetadata) {
return getMethodMetadataMap(serviceName).get(requestMetadata);
}
private ReferenceBean<GenericService> adaptReferenceBean(ServiceRestMetadata serviceRestMetadata) {
String dubboServiceName = serviceRestMetadata.getName();
String[] segments = getServiceSegments(dubboServiceName);
String interfaceName = getServiceInterface(segments);
String version = getServiceVersion(segments);
String group = getServiceGroup(segments);
ReferenceBean<GenericService> referenceBean = new ReferenceBean<GenericService>();
referenceBean.setGeneric(true);
referenceBean.setInterface(interfaceName);
referenceBean.setVersion(version);
referenceBean.setGroup(group);
referenceBean.setProtocol(targetProtocol);
referenceBean.setCluster(targetCluster);
return referenceBean;
}
private Map<RequestMetadata, GenericService> getGenericServicesMap(String serviceName) {
return genericServicesRepository.getOrDefault(serviceName, Collections.emptyMap());
}
private Map<RequestMetadata, MethodMetadata> getMethodMetadataMap(String serviceName) {
return methodMetadataRepository.getOrDefault(serviceName, Collections.emptyMap());
}
}

@ -0,0 +1,190 @@
/*
* 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.metadata.resolver;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.config.spring.ServiceBean;
import feign.Contract;
import feign.Feign;
import feign.MethodMetadata;
import feign.Util;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
import org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry;
import org.springframework.util.ClassUtils;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* The metadata resolver for {@link Feign}
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class FeignMetadataResolver implements BeanClassLoaderAware, SmartInitializingSingleton, MetadataResolver {
private static final String[] CONTRACT_CLASS_NAMES = {
"feign.jaxrs2.JAXRS2Contract",
"org.springframework.cloud.openfeign.support.SpringMvcContract",
};
private final String currentApplicationName;
private final ObjectProvider<Contract> contract;
private ClassLoader classLoader;
/**
* Feign Contracts
*/
private Collection<Contract> contracts;
public FeignMetadataResolver(String currentApplicationName, ObjectProvider<Contract> contract) {
this.currentApplicationName = currentApplicationName;
this.contract = contract;
}
@Override
public void afterSingletonsInstantiated() {
LinkedList<Contract> contracts = new LinkedList<>();
// Add injected Contract if available, for example SpringMvcContract Bean under Spring Cloud Open Feign
contract.ifAvailable(contracts::add);
Stream.of(CONTRACT_CLASS_NAMES)
.filter(this::isClassPresent) // filter the existed classes
.map(this::loadContractClass) // load Contract Class
.map(this::createContract) // create instance by the specified class
.forEach(contracts::add); // add the Contract instance into contracts
this.contracts = Collections.unmodifiableCollection(contracts);
}
private Contract createContract(Class<?> contractClassName) {
return (Contract) BeanUtils.instantiateClass(contractClassName);
}
private Class<?> loadContractClass(String contractClassName) {
return ClassUtils.resolveClassName(contractClassName, classLoader);
}
private boolean isClassPresent(String className) {
return ClassUtils.isPresent(className, classLoader);
}
@Override
public Set<ServiceRestMetadata> resolveServiceRestMetadata(ServiceBean serviceBean) {
Object bean = serviceBean.getRef();
Class<?> beanType = bean.getClass();
Set<ServiceRestMetadata> serviceRestMetadata = new LinkedHashSet<>();
Set<RestMethodMetadata> methodRestMetadata = resolveMethodRestMetadata(beanType);
List<URL> urls = serviceBean.getExportedUrls();
urls.stream()
.map(SpringCloudRegistry::getServiceName)
.forEach(serviceName -> {
ServiceRestMetadata metadata = new ServiceRestMetadata();
metadata.setName(serviceName);
metadata.setMeta(methodRestMetadata);
serviceRestMetadata.add(metadata);
});
return serviceRestMetadata;
}
@Override
public Set<RestMethodMetadata> resolveMethodRestMetadata(Class<?> targetType) {
List<Method> feignContractMethods = selectFeignContractMethods(targetType);
return contracts.stream()
.map(contract -> contract.parseAndValidatateMetadata(targetType))
.flatMap(v -> v.stream())
.map(methodMetadata -> resolveMethodRestMetadata(methodMetadata, targetType, feignContractMethods))
.collect(Collectors.toSet());
}
/**
* Select feign contract methods
* <p>
* extract some code from {@link Contract.BaseContract#parseAndValidatateMetadata(java.lang.Class)}
*
* @param targetType
* @return non-null
*/
private List<Method> selectFeignContractMethods(Class<?> targetType) {
List<Method> methods = new LinkedList<>();
for (Method method : targetType.getMethods()) {
if (method.getDeclaringClass() == Object.class ||
(method.getModifiers() & Modifier.STATIC) != 0 ||
Util.isDefault(method)) {
continue;
}
methods.add(method);
}
return methods;
}
protected RestMethodMetadata resolveMethodRestMetadata(MethodMetadata methodMetadata, Class<?> targetType,
List<Method> feignContractMethods) {
String configKey = methodMetadata.configKey();
Method feignContractMethod = getMatchedFeignContractMethod(targetType, feignContractMethods, configKey);
RestMethodMetadata metadata = new RestMethodMetadata();
metadata.setRequest(new RequestMetadata(methodMetadata.template()));
metadata.setMethod(new org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata(feignContractMethod));
metadata.setIndexToName(methodMetadata.indexToName());
return metadata;
}
private Method getMatchedFeignContractMethod(Class<?> targetType, List<Method> methods, String expectedConfigKey) {
Method matchedMethod = null;
for (Method method : methods) {
String configKey = Feign.configKey(targetType, method);
if (expectedConfigKey.equals(configKey)) {
matchedMethod = method;
break;
}
}
return matchedMethod;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
}

@ -0,0 +1,47 @@
/*
* 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.metadata.resolver;
import com.alibaba.dubbo.config.spring.ServiceBean;
import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
import java.util.Set;
/**
* The REST metadata resolver
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public interface MetadataResolver {
/**
* Resolve the {@link ServiceRestMetadata} {@link Set set} from {@link ServiceBean}
*
* @param serviceBean {@link ServiceBean}
* @return non-null {@link Set}
*/
Set<ServiceRestMetadata> resolveServiceRestMetadata(ServiceBean serviceBean);
/**
* Resolve {@link RestMethodMetadata} {@link Set set} from {@link Class target type}
*
* @param targetType {@link Class target type}
* @return non-null {@link Set}
*/
Set<RestMethodMetadata> resolveMethodRestMetadata(Class<?> targetType);
}

@ -0,0 +1,33 @@
/*
* 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.metadata.service;
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
import java.util.Set;
/**
* Config Service for Metadata
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public interface MetadataConfigService {
void publishServiceRestMetadata(String serviceName, Set<ServiceRestMetadata> serviceRestMetadata);
Set<ServiceRestMetadata> getServiceRestMetadata(String serviceName);
}

@ -0,0 +1,97 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.alibaba.dubbo.metadata.service;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
import org.springframework.cloud.alibaba.nacos.NacosConfigProperties;
import javax.annotation.PostConstruct;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
/**
* Nacos {@link MetadataConfigService}
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class NacosMetadataConfigService implements MetadataConfigService {
private final ObjectMapper objectMapper = new ObjectMapper();
@Autowired
private NacosConfigProperties nacosConfigProperties;
private ConfigService configService;
@PostConstruct
public void init() {
this.configService = nacosConfigProperties.configServiceInstance();
this.objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
}
/**
* Get the data Id of service rest metadata
*/
private static String getServiceRestMetadataDataId(String serviceName) {
return "metadata:rest:" + serviceName + ".json";
}
@Override
public void publishServiceRestMetadata(String serviceName, Set<ServiceRestMetadata> serviceRestMetadata) {
String dataId = getServiceRestMetadataDataId(serviceName);
String json = writeValueAsString(serviceRestMetadata);
try {
configService.publishConfig(dataId, DEFAULT_GROUP, json);
} catch (NacosException e) {
throw new RuntimeException(e);
}
}
@Override
public Set<ServiceRestMetadata> getServiceRestMetadata(String serviceName) {
Set<ServiceRestMetadata> metadata = Collections.emptySet();
String dataId = getServiceRestMetadataDataId(serviceName);
try {
String json = configService.getConfig(dataId, DEFAULT_GROUP, 1000 * 3);
metadata = objectMapper.readValue(json,
TypeFactory.defaultInstance().constructCollectionType(LinkedHashSet.class, ServiceRestMetadata.class));
} catch (Exception e) {
throw new RuntimeException(e);
}
return metadata;
}
private String writeValueAsString(Object object) {
String content = null;
try {
content = objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new IllegalArgumentException(e);
}
return content;
}
}

@ -0,0 +1,65 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.alibaba.dubbo.openfeign;
import feign.Contract;
import feign.Feign;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration;
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.FeignClientsConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
/**
* Dubbo {@link Configuration} for {@link FeignClient FeignClients}
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @see DubboOpenFeignAutoConfiguration
* @see org.springframework.cloud.openfeign.FeignContext#setConfigurations(List)
* @see FeignClientsConfiguration
*/
@Configuration
public class DubboFeignClientsConfiguration {
@Autowired
private Contract contract;
@Autowired
private DubboServiceMetadataRepository dubboServiceRepository;
@Bean
public BeanPostProcessor beanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof Feign.Builder) {
Feign.Builder builder = (Feign.Builder) bean;
builder.invocationHandlerFactory(new DubboInvocationHandlerFactory(contract, dubboServiceRepository));
}
return bean;
}
};
}
}

@ -0,0 +1,69 @@
/*
* 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.openfeign;
import com.alibaba.dubbo.rpc.service.GenericService;
import org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.MethodParameterMetadata;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
/**
* Dubbo {@link GenericService} for {@link InvocationHandler}
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class DubboInvocationHandler implements InvocationHandler {
private final Map<Method, GenericService> genericServicesMap;
private final Map<Method, MethodMetadata> methodMetadata;
private final InvocationHandler defaultInvocationHandler;
public DubboInvocationHandler(Map<Method, GenericService> genericServicesMap,
Map<Method, MethodMetadata> methodMetadata,
InvocationHandler defaultInvocationHandler) {
this.genericServicesMap = genericServicesMap;
this.methodMetadata = methodMetadata;
this.defaultInvocationHandler = defaultInvocationHandler;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
GenericService genericService = genericServicesMap.get(method);
MethodMetadata methodMetadata = this.methodMetadata.get(method);
if (genericService == null || methodMetadata == null) {
return defaultInvocationHandler.invoke(proxy, method, args);
}
String methodName = methodMetadata.getName();
String[] parameterTypes = methodMetadata
.getParams()
.stream()
.map(MethodParameterMetadata::getType)
.toArray(String[]::new);
return genericService.$invoke(methodName, parameterTypes, args);
}
}

@ -0,0 +1,101 @@
/*
* 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.openfeign;
import com.alibaba.dubbo.rpc.service.GenericService;
import feign.Contract;
import feign.InvocationHandlerFactory;
import feign.MethodMetadata;
import feign.Target;
import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static feign.Feign.configKey;
/**
* Dubbo {@link InvocationHandlerFactory}
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class DubboInvocationHandlerFactory implements InvocationHandlerFactory {
private final static InvocationHandlerFactory DEFAULT_INVOCATION_HANDLER_FACTORY =
new InvocationHandlerFactory.Default();
private final Contract contract;
private final DubboServiceMetadataRepository dubboServiceRepository;
public DubboInvocationHandlerFactory(Contract contract, DubboServiceMetadataRepository dubboServiceRepository) {
this.contract = contract;
this.dubboServiceRepository = dubboServiceRepository;
}
@Override
public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
// The target class annotated @FeignClient
Class<?> targetType = target.type();
// Resolve metadata from current @FeignClient type
Map<Method, RequestMetadata> methodRequestMetadataMap = resolveMethodRequestMetadataMap(targetType, dispatch.keySet());
// @FeignClient specifies the service name
String serviceName = target.name();
// Update specified metadata
dubboServiceRepository.updateMetadata(serviceName);
Map<Method, GenericService> genericServicesMap = new HashMap<>();
Map<Method, org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata> methodMetadataMap = new HashMap<>();
methodRequestMetadataMap.forEach((method, requestMetadata) -> {
GenericService genericService = dubboServiceRepository.getGenericService(serviceName, requestMetadata);
org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata methodMetadata =
dubboServiceRepository.getMethodMetadata(serviceName, requestMetadata);
genericServicesMap.put(method, genericService);
methodMetadataMap.put(method, methodMetadata);
});
InvocationHandler defaultInvocationHandler = DEFAULT_INVOCATION_HANDLER_FACTORY.create(target, dispatch);
DubboInvocationHandler invocationHandler = new DubboInvocationHandler(genericServicesMap, methodMetadataMap,
defaultInvocationHandler);
return invocationHandler;
}
private Map<Method, RequestMetadata> resolveMethodRequestMetadataMap(Class<?> targetType, Set<Method> methods) {
Map<String, RequestMetadata> requestMetadataMap = resolveRequestMetadataMap(targetType);
return methods.stream().collect(Collectors.toMap(method -> method, method ->
requestMetadataMap.get(configKey(targetType, method))
));
}
private Map<String, RequestMetadata> resolveRequestMetadataMap(Class<?> targetType) {
return contract.parseAndValidatateMetadata(targetType)
.stream().collect(Collectors.toMap(MethodMetadata::configKey, this::requestMetadata));
}
private RequestMetadata requestMetadata(MethodMetadata methodMetadata) {
return new RequestMetadata(methodMetadata.template());
}
}

@ -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 <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
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<String, String> getMetadata() {
return delegate.getMetadata();
}
@Override
public String getScheme() {
return delegate.getScheme();
}
}

@ -0,0 +1,443 @@
/*
* 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.PROTOCOL_KEY;
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 <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
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 PROTOCOL_INDEX = CATEGORY_INDEX + 1;
private static final int SERVICE_INTERFACE_INDEX = PROTOCOL_INDEX + 1;
private static final int SERVICE_VERSION_INDEX = SERVICE_INTERFACE_INDEX + 1;
private static final int SERVICE_GROUP_INDEX = SERVICE_VERSION_INDEX + 1;
private static final String WILDCARD = "*";
/**
* The separator for service name
*/
private static final String SERVICE_NAME_SEPARATOR = ":";
private final ServiceRegistry<Registration> 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<Registration> 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<String> 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;
}
public static String getServiceName(URL url) {
String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
return getServiceName(url, category);
}
private static String getServiceName(URL url, String category) {
StringBuilder serviceNameBuilder = new StringBuilder(category);
appendIfPresent(serviceNameBuilder, url.getParameter(PROTOCOL_KEY, url.getProtocol()));
appendIfPresent(serviceNameBuilder, url, Constants.INTERFACE_KEY);
appendIfPresent(serviceNameBuilder, url, Constants.VERSION_KEY);
appendIfPresent(serviceNameBuilder, url, Constants.GROUP_KEY);
return serviceNameBuilder.toString();
}
private static void appendIfPresent(StringBuilder target, URL url, String parameterName) {
String parameterValue = url.getParameter(parameterName);
appendIfPresent(target, parameterValue);
}
private static void appendIfPresent(StringBuilder target, String parameterValue) {
if (StringUtils.hasText(parameterValue)) {
target.append(SERVICE_NAME_SEPARATOR).append(parameterValue);
}
}
private void filterServiceNames(List<String> 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<String>() {
@Override
public boolean accept(String serviceName) {
// split service name to segments
// (required) segments[0] = category
// (required) segments[1] = serviceInterface
// (required) segments[2] = protocol
// (required) segments[3] = version
// (optional) segments[4] = group
String[] segments = getServiceSegments(serviceName);
int length = segments.length;
if (length < 4) { // must present 4 segments or more
return false;
}
String category = getCategory(segments);
if (Arrays.binarySearch(categories, category) > -1) { // no match category
return false;
}
String protocol = getProtocol(segments);
if (StringUtils.hasText(protocol)) {
return false;
}
String serviceInterface = getServiceInterface(segments);
if (!WILDCARD.equals(targetServiceInterface) &&
!Objects.equals(targetServiceInterface, serviceInterface)) { // no match service interface
return false;
}
String version = getServiceVersion(segments);
if (!WILDCARD.equals(targetVersion) &&
!Objects.equals(targetVersion, version)) { // no match service version
return false;
}
String group = getServiceGroup(segments);
if (group != null && !WILDCARD.equals(targetGroup)
&& !Objects.equals(targetGroup, group)) { // no match service group
return false;
}
return true;
}
});
}
public static String[] getServiceSegments(String serviceName) {
return StringUtils.delimitedListToStringArray(serviceName, SERVICE_NAME_SEPARATOR);
}
public static String getCategory(String[] segments) {
return segments[CATEGORY_INDEX];
}
public static String getProtocol(String[] segments) {
return segments[PROTOCOL_INDEX];
}
public static String getServiceInterface(String[] segments) {
return segments[SERVICE_INTERFACE_INDEX];
}
public static String getServiceVersion(String[] segments) {
return segments[SERVICE_VERSION_INDEX];
}
public static String getServiceGroup(String[] segments) {
return segments.length > 4 ? segments[SERVICE_GROUP_INDEX] : null;
}
/**
* 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<String> 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<String> 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<String> serviceNames = getAllServiceNames();
filter(serviceNames, new Filter<String>() {
@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<String> serviceNames) {
for (String serviceName : serviceNames) {
List<ServiceInstance> serviceInstances = discoveryClient.getInstances(serviceName);
notifySubscriber(url, listener, serviceInstances);
// TODO Support Update notification event
}
}
private List<String> doGetServiceNames(URL url) {
String[] categories = getCategories(url);
List<String> serviceNames = new ArrayList<String>(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<ServiceInstance> serviceInstances) {
List<ServiceInstance> healthyInstances = new LinkedList<ServiceInstance>(serviceInstances);
// Healthy Instances
filterHealthyInstances(healthyInstances);
List<URL> urls = buildURLs(url, healthyInstances);
this.notify(url, listener, urls);
}
private void filterHealthyInstances(Collection<ServiceInstance> instances) {
filter(instances, new Filter<ServiceInstance>() {
@Override
public boolean accept(ServiceInstance data) {
// TODO check the details of status
// return serviceRegistry.getStatus(new DubboRegistration(data)) != null;
return true;
}
});
}
private List<URL> buildURLs(URL consumerURL, Collection<ServiceInstance> serviceInstances) {
if (serviceInstances.isEmpty()) {
return Collections.emptyList();
}
List<URL> urls = new LinkedList<URL>();
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<String> getServiceNamesForOps(URL url) {
List<String> serviceNames = getAllServiceNames();
filterServiceNames(serviceNames, url);
return serviceNames;
}
private <T> void filter(Collection<T> collection, Filter<T> filter) {
Iterator<T> iterator = collection.iterator();
while (iterator.hasNext()) {
T data = iterator.next();
if (!filter.accept(data)) { // remove if not accept
iterator.remove();
}
}
}
private static <T> T[] of(T... values) {
return values;
}
/**
* A filter
*/
private interface Filter<T> {
/**
* Tests whether or not the specified data should be accepted.
*
* @param data The data to be tested
* @return <code>true</code> if and only if <code>data</code>
* should be accepted
*/
boolean accept(T data);
}
}

@ -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 <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @see RegistryFactory
* @see SpringCloudRegistry
*/
public class SpringCloudRegistryFactory implements RegistryFactory {
private static ApplicationContext applicationContext;
@Override
public Registry getRegistry(URL url) {
ServiceRegistry<Registration> 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;
}
}

@ -0,0 +1 @@
spring-cloud=org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistryFactory

@ -0,0 +1,7 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboMetadataAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestMetadataRegistrationAutoConfiguration
org.springframework.context.ApplicationContextInitializer=\
org.springframework.cloud.alibaba.dubbo.context.DubboServiceRegistrationApplicationContextInitializer

@ -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 <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@SpringBootTest
public class DubboServiceRegistrationAutoConfigurationTest {
}

@ -0,0 +1,79 @@
/*
* 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.beans.factory.annotation.Autowired;
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.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* Dubbo Spring Cloud Bootstrap
*/
@EnableDiscoveryClient
@EnableAutoConfiguration
@EnableFeignClients
@RestController
public class DubboSpringCloudBootstrap {
@Reference(version = "1.0.0")
private EchoService echoService;
@Autowired
@Lazy
private FeignEchoService feignEchoService;
@GetMapping(value = "/call/echo")
public String echo(@RequestParam("message") String message) {
return feignEchoService.echo(message);
}
@FeignClient("spring-cloud-alibaba-dubbo")
public interface FeignEchoService {
@GetMapping(value = "/echo")
String echo(@RequestParam("message") String message);
}
@Bean
public ApplicationRunner applicationRunner() {
return arguments -> {
// Dubbo Service call
System.out.println(echoService.echo("mercyblitz"));
// Spring Cloud Open Feign REST Call
System.out.println(feignEchoService.echo("mercyblitz"));
};
}
public static void main(String[] args) {
new SpringApplicationBuilder(DubboSpringCloudBootstrap.class)
.run(args);
}
}

@ -0,0 +1,65 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.alibaba.dubbo.service;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.dubbo.rpc.RpcContext;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
/**
* Default {@link EchoService}
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@Service(version = "1.0.0", protocol = {"dubbo", "rest"})
@RestController
@Path("/")
public class DefaultEchoService implements EchoService {
@Override
@GetMapping(value = "/echo"
// consumes = MediaType.APPLICATION_JSON_VALUE,
// produces = MediaType.APPLICATION_JSON_UTF8_VALUE
)
@Path("/echo")
@GET
// @Consumes("application/json")
// @Produces("application/json;charset=UTF-8")
public String echo(@RequestParam @QueryParam("message") String message) {
return RpcContext.getContext().getUrl() + " [echo] : " + message;
}
@Override
@PostMapping("/plus")
@Path("/plus")
@POST
public String plus(@RequestParam @QueryParam("a") int a, @RequestParam @QueryParam("b") int b) {
return null;
}
}

@ -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.service;
/**
* Echo Service
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public interface EchoService {
String echo(String message);
String plus(int a, int b);
}

@ -0,0 +1,16 @@
dubbo:
scan:
base-packages: org.springframework.cloud.alibaba.dubbo.service
protocols:
dubbo:
name: dubbo
port: 12345
rest:
name: rest
port: 9090
server: netty
registry:
address: spring-cloud://nacos
server:
port: 8080

@ -0,0 +1,28 @@
spring:
application:
name: spring-cloud-alibaba-dubbo
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
config:
server-addr: 127.0.0.1:8848
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/

@ -1,7 +1,11 @@
package org.springframework.alicloud.env.extension;
import java.lang.annotation.*;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)

@ -30,7 +30,11 @@
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
</dependency>
</dependencies>

@ -29,8 +29,13 @@
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
</dependency>
</dependencies>
<build>

@ -30,7 +30,14 @@ import java.util.List;
import java.util.Objects;
import java.util.Properties;
import static com.alibaba.nacos.api.PropertyKeyConst.*;
import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY;
import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME;
import static com.alibaba.nacos.api.PropertyKeyConst.CONTEXT_PATH;
import static com.alibaba.nacos.api.PropertyKeyConst.ENCODE;
import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT;
import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE;
import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY;
import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
/**
* nacos properties

@ -26,7 +26,11 @@ import org.springframework.core.io.ByteArrayResource;
import org.springframework.util.StringUtils;
import java.io.StringReader;
import java.util.*;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* @author xiaojing

@ -16,10 +16,11 @@
package org.springframework.cloud.alibaba.nacos;
import org.springframework.boot.ApplicationRunner;
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;
import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.alibaba.nacos.registry.NacosAutoServiceRegistration;
@ -34,36 +35,54 @@ import org.springframework.context.annotation.Configuration;
/**
* @author xiaojing
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@Configuration
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled
@ConditionalOnClass(name = "org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent")
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
@AutoConfigureAfter(AutoServiceRegistrationAutoConfiguration.class)
@AutoConfigureBefore({AutoServiceRegistrationAutoConfiguration.class,
NacosDiscoveryClientAutoConfiguration.class})
@AutoConfigureAfter(AutoServiceRegistrationConfiguration.class)
public class NacosDiscoveryAutoConfiguration {
@Bean
public NacosServiceRegistry nacosServiceRegistry() {
return new NacosServiceRegistry();
}
@Bean
public NacosServiceRegistry nacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {
return new NacosServiceRegistry(nacosDiscoveryProperties);
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosRegistration nacosRegistration(
NacosDiscoveryProperties nacosDiscoveryProperties,
ApplicationContext context) {
return new NacosRegistration(nacosDiscoveryProperties, context);
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosRegistration nacosRegistration(
NacosDiscoveryProperties nacosDiscoveryProperties,
ApplicationContext context) {
return new NacosRegistration(nacosDiscoveryProperties, context);
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosAutoServiceRegistration nacosAutoServiceRegistration(
NacosServiceRegistry registry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties,
NacosRegistration registration) {
return new NacosAutoServiceRegistration(registry,
autoServiceRegistrationProperties, registration);
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosAutoServiceRegistration nacosAutoServiceRegistration(
NacosServiceRegistry registry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties,
NacosRegistration registration) {
return new NacosAutoServiceRegistration(registry,
autoServiceRegistrationProperties, registration);
}
@Bean
@ConditionalOnBean(NacosAutoServiceRegistration.class) // NacosAutoServiceRegistration should be present
@ConditionalOnNotWebApplication // Not Web Application
public ApplicationRunner applicationRunner(NacosAutoServiceRegistration nacosAutoServiceRegistration) {
return args -> {
// WebServerInitializedEvent should not be multicast in Non-Web environment.
// Whatever, NacosAutoServiceRegistration must be checked it's running or not.
if (!nacosAutoServiceRegistration.isRunning()) { // If it's not running, let it start.
// FIXME: Please make sure "spring.cloud.nacos.discovery.port" must be configured on an available port,
// or the startup or Nacos health check will be failed.
nacosAutoServiceRegistration.start();
// NacosAutoServiceRegistration will be stopped after its destroy() method is invoked.
// @PreDestroy destroy() -> stop()
}
};
}
}

@ -23,7 +23,11 @@ import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author xiaojing

@ -39,6 +39,7 @@ import static com.alibaba.nacos.api.PropertyKeyConst.*;
/**
* @author dungu.zpf
* @author xiaojing
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@ConfigurationProperties("spring.cloud.nacos.discovery")
@ -379,14 +380,13 @@ public class NacosDiscoveryProperties {
properties.put(CLUSTER_NAME, clusterName);
properties.put(NAMING_LOAD_CACHE_AT_START, namingLoadCacheAtStart);
try {
namingService = NacosFactory.createNamingService(properties);
return namingService;
}
catch (Exception e) {
try {
namingService = NacosFactory.createNamingService(properties);
} catch (Exception e) {
LOGGER.error("create naming service error!properties={},e=,", this, e);
return null;
}
return namingService;
}
}

@ -20,6 +20,7 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.condition.Conditi
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.alibaba.nacos.ConditionalOnNacosDiscoveryEnabled;
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -29,6 +30,7 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
@ConditionalOnClass(Endpoint.class)
@ConditionalOnNacosDiscoveryEnabled
public class NacosDiscoveryEndpointAutoConfiguration {
@Bean

@ -20,83 +20,85 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* @author xiaojing
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class NacosAutoServiceRegistration
extends AbstractAutoServiceRegistration<NacosRegistration> {
private static final Logger LOGGER = LoggerFactory
.getLogger(NacosAutoServiceRegistration.class);
extends AbstractAutoServiceRegistration<Registration> {
private static final Logger LOGGER = LoggerFactory
.getLogger(NacosAutoServiceRegistration.class);
private NacosRegistration registration;
private NacosRegistration registration;
public NacosAutoServiceRegistration(
ServiceRegistry<NacosRegistration> serviceRegistry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties,
NacosRegistration registration) {
super(serviceRegistry, autoServiceRegistrationProperties);
this.registration = registration;
}
public NacosAutoServiceRegistration(
ServiceRegistry<Registration> serviceRegistry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties,
NacosRegistration registration) {
super(serviceRegistry, autoServiceRegistrationProperties);
this.registration = registration;
}
@Deprecated
public void setPort(int port) {
getPort().set(port);
}
@Deprecated
public void setPort(int port) {
getPort().set(port);
}
@Override
protected NacosRegistration getRegistration() {
if (this.registration.getPort() < 0 && this.getPort().get() > 0) {
this.registration.setPort(this.getPort().get());
}
Assert.isTrue(this.registration.getPort() > 0, "service.port has not been set");
return this.registration;
}
@Override
protected NacosRegistration getRegistration() {
if (this.registration.getPort() < 0 && this.getPort().get() > 0) {
this.registration.setPort(this.getPort().get());
}
Assert.isTrue(this.registration.getPort() > 0, "service.port has not been set");
return this.registration;
}
@Override
protected NacosRegistration getManagementRegistration() {
return null;
}
@Override
protected NacosRegistration getManagementRegistration() {
return null;
}
@Override
protected void register() {
if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
LOGGER.debug("Registration disabled.");
return;
}
if (this.registration.getPort() < 0) {
this.registration.setPort(getPort().get());
}
super.register();
}
@Override
protected void register() {
if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
LOGGER.debug("Registration disabled.");
return;
}
if (this.registration.getPort() < 0) {
this.registration.setPort(getPort().get());
}
super.register();
}
@Override
protected void registerManagement() {
if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
return;
}
super.registerManagement();
@Override
protected void registerManagement() {
if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
return;
}
super.registerManagement();
}
}
@Override
protected Object getConfiguration() {
return this.registration.getNacosDiscoveryProperties();
}
@Override
protected Object getConfiguration() {
return this.registration.getNacosDiscoveryProperties();
}
@Override
protected boolean isEnabled() {
return this.registration.getNacosDiscoveryProperties().isRegisterEnabled();
}
@Override
protected boolean isEnabled() {
return this.registration.getNacosDiscoveryProperties().isRegisterEnabled();
}
@Override
@SuppressWarnings("deprecation")
protected String getAppName() {
String appName = registration.getNacosDiscoveryProperties().getService();
return StringUtils.isEmpty(appName) ? super.getAppName() : appName;
}
@Override
@SuppressWarnings("deprecation")
protected String getAppName() {
String appName = registration.getNacosDiscoveryProperties().getService();
return StringUtils.isEmpty(appName) ? super.getAppName() : appName;
}
}

@ -18,90 +18,97 @@ package org.springframework.cloud.alibaba.nacos.registry;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.util.StringUtils;
/**
* @author xiaojing
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class NacosServiceRegistry implements ServiceRegistry<NacosRegistration> {
private static Logger logger = LoggerFactory.getLogger(NacosServiceRegistry.class);
@Override
public void register(NacosRegistration registration) {
if (!registration.isRegisterEnabled()) {
logger.info("Nacos Registration is disabled...");
return;
}
if (StringUtils.isEmpty(registration.getServiceId())) {
logger.info("No service to register for nacos client...");
return;
}
NamingService namingService = registration.getNacosNamingService();
String serviceId = registration.getServiceId();
Instance instance = new Instance();
instance.setIp(registration.getHost());
instance.setPort(registration.getPort());
instance.setWeight(registration.getRegisterWeight());
instance.setClusterName(registration.getCluster());
instance.setMetadata(registration.getMetadata());
try {
namingService.registerInstance(serviceId, instance);
logger.info("nacos registry, {} {}:{} register finished", serviceId,
instance.getIp(), instance.getPort());
}
catch (Exception e) {
logger.error("nacos registry, {} register failed...{},", serviceId,
registration.toString(), e);
}
}
@Override
public void deregister(NacosRegistration registration) {
logger.info("De-registering from Nacos Server now...");
if (StringUtils.isEmpty(registration.getServiceId())) {
logger.info("No dom to de-register for nacos client...");
return;
}
NamingService namingService = registration.getNacosNamingService();
String serviceId = registration.getServiceId();
try {
namingService.deregisterInstance(serviceId, registration.getHost(),
registration.getPort(), registration.getCluster());
}
catch (Exception e) {
logger.error("ERR_NACOS_DEREGISTER, de-register failed...{},",
registration.toString(), e);
}
logger.info("De-registration finished.");
}
@Override
public void close() {
}
@Override
public void setStatus(NacosRegistration registration, String status) {
// nacos doesn't support set status of a particular registration.
}
@Override
public <T> T getStatus(NacosRegistration registration) {
// nacos doesn't support query status of a particular registration.
return null;
}
public class NacosServiceRegistry implements ServiceRegistry<Registration> {
private static Logger logger = LoggerFactory.getLogger(NacosServiceRegistry.class);
private final NacosDiscoveryProperties nacosDiscoveryProperties;
private final NamingService namingService;
public NacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {
this.nacosDiscoveryProperties = nacosDiscoveryProperties;
this.namingService = nacosDiscoveryProperties.namingServiceInstance();
}
@Override
public void register(Registration registration) {
if (StringUtils.isEmpty(registration.getServiceId())) {
logger.info("No service to register for nacos client...");
return;
}
String serviceId = registration.getServiceId();
Instance instance = new Instance();
instance.setIp(registration.getHost());
instance.setPort(registration.getPort());
instance.setWeight(nacosDiscoveryProperties.getWeight());
instance.setClusterName(nacosDiscoveryProperties.getClusterName());
instance.setMetadata(registration.getMetadata());
try {
namingService.registerInstance(serviceId, instance);
logger.info("nacos registry, {} {}:{} register finished", serviceId,
instance.getIp(), instance.getPort());
} catch (Exception e) {
logger.error("nacos registry, {} register failed...{},", serviceId,
registration.toString(), e);
}
}
@Override
public void deregister(Registration registration) {
logger.info("De-registering from Nacos Server now...");
if (StringUtils.isEmpty(registration.getServiceId())) {
logger.info("No dom to de-register for nacos client...");
return;
}
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
String serviceId = registration.getServiceId();
try {
namingService.deregisterInstance(serviceId, registration.getHost(),
registration.getPort(), nacosDiscoveryProperties.getClusterName());
} catch (Exception e) {
logger.error("ERR_NACOS_DEREGISTER, de-register failed...{},",
registration.toString(), e);
}
logger.info("De-registration finished.");
}
@Override
public void close() {
}
@Override
public void setStatus(Registration registration, String status) {
// nacos doesn't support set status of a particular registration.
}
@Override
public <T> T getStatus(Registration registration) {
// nacos doesn't support query status of a particular registration.
return null;
}
}

@ -16,6 +16,7 @@
package org.springframework.cloud.alibaba.nacos.ribbon;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractServerList;
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
@ -23,8 +24,6 @@ import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.nacos.api.naming.pojo.Instance;
/**
* @author xiaojing
* @author renhaojun

@ -2,6 +2,8 @@ package org.springframework.cloud.alibaba.sentinel.datasource.config;
import javax.validation.constraints.NotEmpty;
import org.springframework.cloud.alibaba.sentinel.datasource.RuleType;
import org.springframework.cloud.alibaba.sentinel.datasource.SentinelDataSourceConstants;
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.NacosDataSourceFactoryBean;
import org.springframework.util.StringUtils;

@ -1,13 +1,12 @@
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
import java.util.Properties;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.util.StringUtils;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.nacos.api.PropertyKeyConst;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.util.StringUtils;
import java.util.Properties;
/**
* A {@link FactoryBean} for creating {@link NacosDataSource} instance.

@ -16,18 +16,17 @@
package org.springframework.cloud.alibaba.sentinel;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.log.LogBase;
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.alibaba.sentinel.datasource.config.DataSourcePropertiesConfiguration;
import org.springframework.core.Ordered;
import org.springframework.validation.annotation.Validated;
import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.log.LogBase;
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* {@link ConfigurationProperties} for Sentinel.

@ -16,11 +16,7 @@
package org.springframework.cloud.alibaba.sentinel;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -31,7 +27,9 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.List;
/**
* @author xiaojing

@ -16,25 +16,6 @@
package org.springframework.cloud.alibaba.sentinel.custom;
import java.util.Optional;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
import org.springframework.cloud.alibaba.sentinel.datasource.converter.JsonConverter;
import org.springframework.cloud.alibaba.sentinel.datasource.converter.XmlConverter;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner;
@ -51,9 +32,25 @@ import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import com.alibaba.csp.sentinel.util.AppNameUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
import org.springframework.cloud.alibaba.sentinel.datasource.converter.JsonConverter;
import org.springframework.cloud.alibaba.sentinel.datasource.converter.XmlConverter;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct;
import java.util.Optional;
/**
* @author xiaojing

@ -16,10 +16,7 @@
package org.springframework.cloud.alibaba.sentinel.custom;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
@ -40,7 +37,9 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
/**
* PostProcessor handle @SentinelRestTemplate Annotation, add interceptor for RestTemplate

@ -16,11 +16,12 @@
package org.springframework.cloud.alibaba.sentinel.custom;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.alibaba.sentinel.annotation.SentinelRestTemplate;
@ -30,12 +31,10 @@ import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
/**
* Interceptor using by SentinelRestTemplate

@ -16,22 +16,21 @@
package org.springframework.cloud.alibaba.sentinel.endpoint;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig;
import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.log.LogBase;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
import java.util.HashMap;
import java.util.Map;
/**
* Endpoint for Sentinel, contains ans properties and rules

@ -16,15 +16,16 @@
package org.springframework.cloud.alibaba.sentinel;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
import java.util.Arrays;
import java.util.Map;
import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig;
import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.log.LogBase;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -50,16 +51,14 @@ import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig;
import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.log.LogBase;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import java.util.Arrays;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>

@ -16,14 +16,12 @@
package org.springframework.cloud.alibaba.sentinel;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner;
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
import com.alibaba.csp.sentinel.adapter.servlet.util.FilterUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@ -35,12 +33,12 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner;
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
import com.alibaba.csp.sentinel.adapter.servlet.util.FilterUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>

@ -16,10 +16,6 @@
package org.springframework.cloud.alibaba.sentinel;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@ -31,6 +27,10 @@ import org.springframework.cloud.alibaba.sentinel.datasource.RuleType;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/

@ -16,14 +16,9 @@
package org.springframework.cloud.alibaba.sentinel;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import java.util.Arrays;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -40,9 +35,13 @@ import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import java.util.Arrays;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>

@ -16,8 +16,7 @@
package org.springframework.cloud.alibaba.sentinel;
import static org.junit.Assert.assertEquals;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.cloud.alibaba.sentinel.annotation.SentinelRestTemplate;
@ -31,7 +30,7 @@ import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.web.client.RestTemplate;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import static org.junit.Assert.assertEquals;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>

@ -16,15 +16,14 @@
package org.springframework.cloud.alibaba.sentinel;
import java.io.IOException;
import java.util.List;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.List;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/

@ -21,7 +21,12 @@ import com.alibaba.ans.shaded.com.taobao.vipserver.client.core.Host;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author xiaolongzuo

@ -1,17 +1,15 @@
package org.springframework.cloud.alicloud.ans.migrate;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import com.netflix.loadbalancer.ILoadBalancer;
import org.springframework.cloud.context.named.NamedContextFactory;
import org.springframework.cloud.endpoint.event.RefreshEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import com.netflix.loadbalancer.ILoadBalancer;
import javax.annotation.PostConstruct;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* @author pbting

@ -1,15 +1,14 @@
package org.springframework.cloud.alicloud.ans.migrate;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.ServerList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.ServerList;
public class MigrateRibbonBeanPostProcessor
implements BeanPostProcessor, BeanClassLoaderAware {

@ -9,7 +9,12 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.alicloud.ans.ribbon.AnsServer;
import org.springframework.cloud.alicloud.ans.ribbon.AnsServerList;
import java.util.*;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListSet;

@ -16,11 +16,6 @@
package org.springframework.cloud.alicloud.ans.registry;
import java.net.URI;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.springframework.cloud.alicloud.context.ans.AnsProperties;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
@ -30,6 +25,10 @@ import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct;
import java.net.URI;
import java.util.Map;
/**
* @author xiaolongzuo
*/

@ -16,15 +16,14 @@
package org.springframework.cloud.alicloud.ans.ribbon;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ServerList;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.alicloud.ans.migrate.MigrateOnConditionMissingClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ServerList;
/**
* @author xiaolongzuo
*/

@ -1,13 +1,12 @@
package org.springframework.cloud.alicloud.ans.ribbon;
import org.springframework.cloud.alicloud.ans.migrate.MigrateRibbonBeanPostProcessor;
import com.netflix.client.config.IClientConfig;
import org.springframework.cloud.alicloud.ans.migrate.MigrateOnConditionClass;
import org.springframework.cloud.alicloud.ans.migrate.MigrateRibbonBeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import com.netflix.client.config.IClientConfig;
@Configuration
@Conditional(MigrateOnConditionClass.class)
public class MigrateRibbonCofiguration {

@ -16,6 +16,9 @@
package org.springframework.cloud.alicloud.context.scx;
import com.alibaba.cloud.context.edas.AliCloudEdasSdk;
import com.alibaba.cloud.context.scx.AliCloudScxInitializer;
import com.alibaba.edas.schedulerx.SchedulerXClient;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@ -27,10 +30,6 @@ import org.springframework.cloud.alicloud.context.edas.EdasProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.cloud.context.edas.AliCloudEdasSdk;
import com.alibaba.cloud.context.scx.AliCloudScxInitializer;
import com.alibaba.edas.schedulerx.SchedulerXClient;
/**
* @author xiaolongzuo
*/

@ -16,14 +16,6 @@
package org.springframework.cloud.stream.binder.rocketmq.integration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.ClassUtils;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.MessageSelector;
@ -56,6 +48,14 @@ import org.springframework.retry.support.RetryTemplate;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/

@ -16,10 +16,6 @@
package org.springframework.cloud.stream.binder.rocketmq.integration;
import java.time.Instant;
import java.util.Map;
import java.util.Optional;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
@ -48,6 +44,10 @@ import org.springframework.messaging.MessagingException;
import org.springframework.messaging.support.ErrorMessage;
import org.springframework.util.Assert;
import java.time.Instant;
import java.util.Map;
import java.util.Optional;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/

Loading…
Cancel
Save