1
0
mirror of https://gitee.com/mirrors/Spring-Cloud-Alibaba.git synced 2021-06-26 13:25:11 +08:00

Temporary commit

This commit is contained in:
小马哥 2019-01-14 10:44:11 +08:00
parent 53b677f3b7
commit 7aa17d3760
11 changed files with 309 additions and 52 deletions

View File

@ -37,14 +37,14 @@ import javax.ws.rs.Path;
@Configuration
public class DubboRestAutoConfiguration {
/**
* A Feign Contract bean for JAX-RS if available
*/
@ConditionalOnClass(Path.class)
@Bean
public Contract jaxrs2Contract() {
return new JAXRS2Contract();
}
// /**
// * A Feign Contract bean for JAX-RS if available
// */
// @ConditionalOnClass(Path.class)
// @Bean
// public Contract jaxrs2Contract() {
// return new JAXRS2Contract();
// }
@Bean
@ConditionalOnMissingBean
@ -52,14 +52,14 @@ public class DubboRestAutoConfiguration {
return new ObjectMapper();
}
/**
* A Feign Contract bean for Spring MVC if available
*/
@ConditionalOnClass(RequestMapping.class)
@Bean
public Contract springMvcContract() {
return new SpringMvcContract();
}
// /**
// * A Feign Contract bean for Spring MVC if available
// */
// @ConditionalOnClass(RequestMapping.class)
// @Bean
// public Contract springMvcContract() {
// return new SpringMvcContract();
// }
@Bean
public RestMetadataResolver metadataJsonResolver(ObjectMapper objectMapper) {

View File

@ -16,10 +16,23 @@
*/
package org.springframework.cloud.alibaba.dubbo.autoconfigure;
import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.config.spring.ReferenceBean;
import feign.Client;
import feign.Request;
import feign.Response;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataResolver;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.context.named.NamedContextFactory;
import org.springframework.cloud.openfeign.FeignClient;
@ -27,8 +40,18 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* The Auto-Configuration class for Dubbo REST Discovery
@ -41,28 +64,148 @@ import java.util.Map;
DubboRestMetadataRegistrationAutoConfiguration.class})
public class DubboRestDiscoveryAutoConfiguration {
@Autowired
private DiscoveryClient discoveryClient;
// 1. Get all service names from Spring beans that was annotated by @FeignClient
// 2. Get all service instances by echo specified service name
// 3. Get Rest metadata from service instance
// 4. Resolve REST metadata from the @FeignClient instance
@Autowired
private RestMetadataResolver restMetadataResolver;
@Autowired(required = false)
private ObjectMapper objectMapper = new ObjectMapper();
/**
* Feign Request -> Dubbo ReferenceBean
*/
private Map<String, ReferenceBean> referenceBeanCache = new HashMap<>();
@Autowired
private ApplicationConfig applicationConfig;
@Value("${spring.cloud.nacos.discovery.server-addr}")
private String nacosServerAddress;
private volatile boolean initialized = false;
@Autowired
private ListableBeanFactory beanFactory;
@Scheduled(initialDelay = 10 * 1000, fixedRate = 5000)
public void init() {
if (initialized) {
return;
}
Map<String, NamedContextFactory.Specification> specifications =
beanFactory.getBeansOfType(NamedContextFactory.Specification.class);
ServiceAnnotationBeanPostProcessor
// 1. Get all service names from Spring beans that was annotated by @FeignClient
List<String> serviceNames = new LinkedList<>();
specifications.forEach((beanName, specification) -> {
String serviceName = beanName.substring(0, beanName.indexOf("."));
serviceNames.add(serviceName);
// 2. Get all service instances by echo specified service name
List<ServiceInstance> serviceInstances = discoveryClient.getInstances(serviceName);
if (!serviceInstances.isEmpty()) {
ServiceInstance serviceInstance = serviceInstances.get(0);
// 3. Get Rest metadata from service instance
Map<String, String> metadata = serviceInstance.getMetadata();
// 4. Resolve REST metadata from the @FeignClient instance
String restMetadataJson = metadata.get("restMetadata");
/**
* {
* "providers:org.springframework.cloud.alibaba.dubbo.service.EchoService:1.0.0": [
* "{\"method\":\"POST\",\"url\":\"/plus?a={a}&b={b}\",\"headers\":{}}",
* "{\"method\":\"GET\",\"url\":\"/echo?message={message}\",\"headers\":{}}"
* ]
* }
*/
try {
Map<String, List<String>> restMetadata = objectMapper.readValue(restMetadataJson, Map.class);
restMetadata.forEach((dubboServiceName, restJsons) -> {
restJsons.stream().map(restMetadataResolver::resolveRequest).forEach(request -> {
referenceBeanCache.put(request.toString(), buildReferenceBean(dubboServiceName));
});
});
} catch (IOException e) {
throw new RuntimeException(e);
}
//
}
});
initialized = true;
}
private ReferenceBean buildReferenceBean(String dubboServiceName) {
ReferenceBean referenceBean = new ReferenceBean();
applicationConfig.setName("service-consumer");
referenceBean.setApplication(applicationConfig);
RegistryConfig registryConfig = new RegistryConfig();
// requires dubbo-registry-nacos
registryConfig.setAddress("nacos://" + nacosServerAddress);
referenceBean.setRegistry(registryConfig);
String[] parts = StringUtils.delimitedListToStringArray(dubboServiceName, ":");
referenceBean.setInterface(parts[1]);
referenceBean.setVersion(parts[2]);
referenceBean.setGroup(parts.length > 3 ? parts[3] : null);
referenceBean.get();
return referenceBean;
}
@Bean
public SmartInitializingSingleton onBeansInitialized(ListableBeanFactory beanFactory) {
return () -> {
Map<String, Object> feignClientBeans = beanFactory.getBeansWithAnnotation(FeignClient.class);
feignClientBeans.forEach((beanName, bean) -> {
if (bean instanceof NamedContextFactory.Specification) {
NamedContextFactory.Specification specification = (NamedContextFactory.Specification) bean;
String serviceName = specification.getName();
public BeanPostProcessor wrapClientBeanPostProcessor() {
return new BeanPostProcessor() {
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof Client) {
Client client = (Client) bean;
// wrapper
return new DubboFeignClientProxy(client);
}
});
return bean;
}
};
}
class DubboFeignClientProxy implements Client {
private final Client delegate;
DubboFeignClientProxy(Client delegate) {
this.delegate = delegate;
}
@Override
public Response execute(Request request, Request.Options options) throws IOException {
ReferenceBean referenceBean = referenceBeanCache.get(request.toString());
if (referenceBean != null) {
Object dubboClient = referenceBean.get();
Method method = null;
Object[] params = null;
try {
Object result = method.invoke(dubboClient, params);
// wrapper as a Response
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return delegate.execute(request, options);
}
}
@EventListener(ContextRefreshedEvent.class)
public void onContextRefreshed(ContextRefreshedEvent event) {

View File

@ -23,17 +23,23 @@ import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import feign.Contract;
import feign.jaxrs2.JAXRS2Contract;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.cloud.alibaba.dubbo.rest.feign.RestMetadataResolver;
import org.springframework.cloud.client.discovery.event.InstancePreRegisteredEvent;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.openfeign.support.SpringMvcContract;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.util.ClassUtils;
import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -51,7 +57,7 @@ import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegist
@Configuration
@AutoConfigureAfter(value = {
DubboRestAutoConfiguration.class, DubboServiceRegistrationAutoConfiguration.class})
public class DubboRestMetadataRegistrationAutoConfiguration {
public class DubboRestMetadataRegistrationAutoConfiguration implements BeanClassLoaderAware {
/**
* A Map to store REST metadata temporary, its' key is the special service name for a Dubbo service,
@ -60,17 +66,38 @@ public class DubboRestMetadataRegistrationAutoConfiguration {
private final Map<String, Set<String>> restMetadata = new LinkedHashMap<>();
/**
* Autowire Feign Contract Beans
* Feign Contracts
*/
@Autowired(required = false)
private Collection<Contract> contracts = Collections.emptyList();
private ClassLoader classLoader;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private RestMetadataResolver restMetadataResolver;
@PostConstruct
public void init() {
contracts = initFeignContracts();
}
private Collection<Contract> initFeignContracts() {
Collection<Contract> contracts = new LinkedList<>();
if (ClassUtils.isPresent("javax.ws.rs.Path", classLoader)) {
contracts.add(new JAXRS2Contract());
}
if (ClassUtils.isPresent("org.springframework.web.bind.annotation.RequestMapping", classLoader)) {
contracts.add(new SpringMvcContract());
}
return contracts;
}
@EventListener(ServiceBeanExportedEvent.class)
public void recordRestMetadata(ServiceBeanExportedEvent event) {
ServiceBean serviceBean = event.getServiceBean();
@ -105,4 +132,9 @@ public class DubboRestMetadataRegistrationAutoConfiguration {
String restMetadataJson = objectMapper.writeValueAsString(restMetadata);
serviceInstanceMetadata.put("restMetadata", restMetadataJson);
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
}

View File

@ -1,3 +1,5 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestMetadataRegistrationAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestDiscoveryAutoConfiguration

View File

@ -29,8 +29,16 @@ 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.context.event.EventListener;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@ -39,18 +47,37 @@ import java.util.List;
*/
@EnableDiscoveryClient
@EnableAutoConfiguration
@EnableFeignClients
@EnableScheduling
@RestController
public class DubboSpringCloudBootstrap {
@Reference(version = "1.0.0")
private EchoService echoService;
@Reference(version = "1.0.0")
private EchoService echoServiceForRest;
@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"));
};
}

View File

@ -43,13 +43,14 @@ import javax.ws.rs.QueryParam;
public class DefaultEchoService implements EchoService {
@Override
@GetMapping(value = "/echo",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@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")
// @Consumes("application/json")
// @Produces("application/json;charset=UTF-8")
public String echo(@RequestParam @QueryParam("message") String message) {
return RpcContext.getContext().getUrl() + " [echo] : " + message;
}

View File

@ -10,4 +10,4 @@ dubbo:
port: 9090
server: netty
registry:
address: spring-cloud://dummy
address: spring-cloud://nacos

View File

@ -5,7 +5,6 @@ spring:
nacos:
discovery:
server-addr: 127.0.0.1:8848
port: 12345
eureka:
client:
enabled: false

View File

@ -16,15 +16,31 @@
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Dubbo Nacos registry dependency -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>0.0.2</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dubbo</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
@ -40,10 +56,10 @@
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.cloud</groupId>-->
<!--<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>-->
<!--</dependency>-->
</dependencies>

View File

@ -0,0 +1,42 @@
package org.springframework.cloud.alibaba.cloud.examples.demos;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
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;
@EnableAutoConfiguration // 激活自动装配
@EnableDiscoveryClient // 激活服务注册和发现
@EnableFeignClients // 激活 @FeignClients注册
public class SpringCloudRestClientBootstrap {
@FeignClient("spring-cloud-alibaba-dubbo")
public interface FeignEchoService {
@GetMapping(value = "/echo")
String echo(@RequestParam("message") String message);
}
@RestController
public static class EchoServiceController {
@Autowired
private FeignEchoService feignEchoService;
@GetMapping("/call/echo")
public String echo(@RequestParam("message") String message) {
return feignEchoService.echo(message);
}
}
public static void main(String[] args) {
SpringApplication.run(SpringCloudRestClientBootstrap.class, args);
}
}

View File

@ -3,10 +3,5 @@ server.port=18083
management.endpoints.web.exposure.include=*
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
feign.sentinel.enabled=true
dubbo.registry.address= spring-cloud://nacos
spring.cloud.sentinel.transport.dashboard=localhost:8080
spring.cloud.sentinel.eager=true
spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json
spring.cloud.sentinel.datasource.ds1.file.data-type=json