一个系统原来是使用dubbo的,现在想把微服务架构转为Spring Cloud。但是这个系统已经在使用中了,希望一步步的把dubbo服务一个个的转为Spring Cloud,转换一个使用一个,转换的过程中尽量少影响原系统。
比如现在要转换dubbo服务D1成Spring Cloud服务C1,D1又需要调用dubbo服务D2。怎么办呢?如果同时转换D1,D2的话,D2可能又会调用D3,这样可能引用一大堆服务。这种做法肯定不可取。一种更好的解决方案是:提供一个Spring Cloud的代理服务,这个代理服务同时是一个Spring Cloud服务和dubbo客户端,其作用就是将对Spring Cloud服务的调用转为对dubbo服务的调用。这样Spring Cloud服务C1需要调用的Spring Cloud服务C2就先以代理的方式实现。等服务C1测试完成后,再停掉代理中的C2,将D2转换为真正的Spring Cloud服务C2。这样逐步把所有的dubbo服务都转换成Spring Cloud服务。这种方案的优点是原系统不用做任何修改,避免了修改带来的风险。
这个方案的关键就是代理服务的实现。
假设有两个dubbo服务,分别为Hello1Service和Hello2Service如下:
public interface Hello1Service {
String hello(String name);
}
public interface Hello2Service {
String hello(String name);
}
创建一个MAVEN项目。POM文件为:
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>CloudDubboProxy</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>CloudDubboProxy</name>
<description>Cloud Dubbo Proxy</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RC1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.8.4</version>
</dependency>
<!-- dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.15.0-GA</version>
</dependency-->
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>1.1.7</version>
</dependency>
<dependency>
<groupId>org.glassfish.grizzly</groupId>
<artifactId>grizzly-core</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.5</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.1.39</version>
</dependency>
<dependency>
<groupId>org.apache.bsf</groupId>
<artifactId>bsf-api</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<!-- dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.5.0</version>
</dependency-->
<dependency>
<groupId>com.googlecode.xmemcached</groupId>
<artifactId>xmemcached</artifactId>
<version>1.3.6</version>
</dependency>
<dependency>
<groupId>de.ruedigermoeller</groupId>
<artifactId>fst</artifactId>
<version>1.55</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-parent</artifactId>
<version>2.8.4</version>
<type>pom</type>
<scope>import</scope>
</dependency-->
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id> central</id>
<name> Maven Repository Switchboard</name>
<layout> default</layout>
<url> http://repo1.maven.org/maven2</url>
<snapshots>
<enabled> false</enabled>
</snapshots>
</repository>
</repositories>
</project>
dubbo的Spring配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="demo-consumer" owner="programmer" organization="dubbox"/>
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!--uncomment this if you want to test dubbo's monitor-->
<!--<dubbo:monitor protocol="registry"/>-->
<dubbo:reference id="hello1Service" interface="com.alibaba.dubbo.demo.hello.Hello1Service"/>
<dubbo:reference id="hello2Service" interface="com.alibaba.dubbo.demo.hello.Hello2Service"/>
</beans>
Spring Cloud的配置文件:
#debug: true
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 9999
spring:
application:
name: service-a
application:
name: service-b
注意:Spring Cloud 1.x中只支持一个服务,Spring Cloud 2.x中可以定义多个服务。
代理的启动类:
@SpringBootApplication
@EnableEurekaClient
@RestController
public class CloudDubboProxyApplication {
private static Hello1Service hello1Service;
private static Hello2Service hello2Service;
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:application-context.xml");
context.start();
hello1Service = context.getBean(Hello1Service.class);
hello2Service = context.getBean(Hello2Service.class);
SpringApplication.run(CloudDubboProxyApplication.class, args);
}
@RequestMapping("/a")
public String ma(@RequestParam String name) {
String s = hello1Service.hello("world");
return "From Cloud service A: "+name+"<br>"+s;
}
@RequestMapping("/b")
public String mb(@RequestParam String name) {
String s = hello2Service.hello("world");
return "From Cloud service B: "+name+"<br>"+s;
}
}
写个测试类:
@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class DemoRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(DemoRibbonApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
@Autowired
RestTemplate restTemplate;
@RequestMapping(value = "/a")
public String ha(@RequestParam String name){
return restTemplate.getForObject("http://SERVICE-A/a?name="+name,String.class);
}
@RequestMapping(value = "/b")
public String hb(@RequestParam String name){
return restTemplate.getForObject("http://SERVICE-B/b?name="+name,String.class);
}
}
可以验证确实实现了Spring Cloud调用dubbo功能。