1.为什么是SpringCloud
目前我们所有的服务都是基于阿里的Dubbo框架,目前Dubbo已经捐献给了Apache,处于孵化状态:https://github.com/apache/incubator-dubbo;
Github上,该项目有19K个Start,更新频率显示是最近一次更新是两个小时前(2018年6月29日15:51:47),上一次频繁更新是10天前.
总的来说Dubbo在国内的还是有较多公司在使用,其性能和可靠性是得到过验证的,但是由于SpringCloud社区这两年非常的火爆,SpringCloud为我们提供了很多组件,俗称的全家桶,可以很大程度满足我们对不同功能的需求,比如:服务的注册(Eureka),配置管理(Config),网关(Gateway),服务追踪(Sleuth),消息总线(Bus),消息队列(AMQP)等等….
对于一些造轮子能力不是很强的中小型公司而言,SpringCloud提供了全套的解决方案,有效的降低了开发的周期.
2.当前项目结构和环境
2.1.目前的Dubbo项目的结构(message-evr为例):
message-svr
└ message-svr-api
└ message-svr-main
这里message-svr-main是对外暴露服务的api,而message-svr-api则是具体的方法api实现.
2.2.关键环境依赖:
JDK1.8
Dubbo 2.5.10
Spring 4.3.8
2.3.配置
大部分配置在Resource目录下采用XML形式配置.
3.改造思路
使用SpringBoot对message-svr-main项目进行重构,使用SpringCloud服务注册中心Eureka,让重构后的服务可以注册到原来的Zookeeper上和Eureka上,这样不影响之前原有的Dubbo服务的调用,同时可以使用Feign调用,大体思路是这样,但是有个兼容问题,Dubbo使用的是阿里自己封装的RPC协议,而SpringCloud所有调用都使用的HTTP协议,这里涉及到协议转换问题,这里不表,下面再说解决方案.
4.SpringBoot重构message-svr-main
4.1.SpringBoot和Spring版本问题
这里我们现在的项目使用的Spring版本是4.2.X,相对版本较低.这里附一张SpringBoot对应的Spring版本.
这里我们使用的springBoot版本是1.5.3,所以spring版本最低也要是4.3.8.
4.2.配置信息修改
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>1.5.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web<artifactId>
<version>1.5.3.RELEASE</version>
</dependency>
springboot内置了Tomcat,SpringBoot都是使用一个代用main方法的启动类来启动项目的.
@SpringBootApplication
@ImportResource("classpath:spring/*.xml")
@EnableTransactionManagement
@EnableDubboConfiguration
public class MessageSvrMainBootApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MessageSvrMainBootApplication.class);
app.run(args);
}
}
使用@ImportResource注解引入之前配置的项目中的XML配置文件,当然SpringBoot官方提倡使用类的方式配置Bean,你也可以重构一下配置文件.
在resources目录下新增application.yml配置文件,添加如下配置:
server:
#这个服务端口是Tomcat启动后使用的端口 非dubbo暴露接口
port: 15000
spring:
application:
name: message-svr
4.3.SpringBoot对原Dubbo服务兼容
这里我们使用springboot是为了减少我们开发的步骤,很多东西springboot都做了很好的封装,比如说事务管理,我们只需要在启动类上加入一个@EnableTransactionManagement
注解,在需要控制事务的方法上加一个@Transaction
注解就能达到方法报错事务回滚的操作.
添加pom
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
这是阿里巴巴提供的一个SpringBoot开发Dubbo项目的包,官方中文文档:https://github.com/alibaba/dubbo-spring-boot-starter/blob/master/README_zh.md
启动类添加@EnableDubboConfiguration
注解
在application.yml加入相应的dubbo配置:
spring:
dubbo:
application:
name: message-svr
registry:
address: zookeeper://xxx.xxx.xxx.xxx:2181
protocol:
name: dubbo
#这个端口是通过dubbo服务调用,api暴露给外面的端口
port: xxx
#需要暴露服务api的路径
scan: com.xxx.messagesvr.messagesvrmainboot.service
module:
default: false
项目启动时,看到@EnableDubboConfiguration
注解这里我们配置的这些参数会在项目启动时被加载到一个DubboProperties类(是刚才dubbo-spring-boot-starter包引入的)中:
这里直接启动改造后的springboot项目的Main()方法就可以.
5.SpringCloud和Dubbo共存方法方案分析
5.1.原始结构
5.2.兼容方案一
5.3.使用feign兼容
这里采用feign兼容的方案.
5.4.准备工作
首先准备一个springCloud的注册中心 Eureka
eureka的application.yml内容:
server:
port: 8761
spring:
application:
name: registry-service
eureka:
instance:
hostname: master
preferIpAddress: true
client:
register-with-eureka: false
fetch-registry: false
serviceUrl:
defaultZone: http://localhost:8761/eureka
server:
enableSelfPreservation: true
在Eureka服务启动类,添加@EnableEurekaServer注解,
启动服务,打开localhost:8761
这是Eureka的可视化页面,说明Eureka启动成功,现在修改之前的message-svr服务.
5.5.改造message-svr让其注册到Eureka上
在meessage-svr的pom中添加包依赖:
<!-- feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.5.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>1.5.3.RELEASE</version>
</dependency>
<!-- spring boot集成eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.3.5.RELEASE</version>
</dependency>
在message-svr的main方法启动类上添加注解@EnableEurekaClient,@EnableDiscoveryClient,@EnableFeignClients
在application.yml中添加相应的配置:
eureka:
client:
# 是否注册到eureka
register-with-eureka: false
serviceUrl:
defaultZone: http://localhost:8761/eureka
instance:
prefer-ip-address: true
server:
port: 15000
spring:
application:
name: message-svr
这里是添加的这个port:15000是服务注册到eureka的端口号
启动message-svr服务:
控制台日志显示启动成功.查看eureka注册中心:
也已经注册上来了.
现在的问题是如何使用http请求来调用到message-svr提供的接口.
5.6.使用http请求调用原来的Dubbo服务接口
使用feign对原有的接口进行改造:
5.6.1在message-svr-main项目 引入支持feign的jar包
5.6.2.在项目的启动类上加入@EnableFeignClients注解,支持feign调用
5.6.3.对原来的对外提供的service interface类加入@FeignClient注解,支持外部调用,将对外暴露接口加上@RequestMapping注解 并且把接口改成rest风格的.
5.6.4.对相对应的接口实现类进行改造:
首先类上加入@RestController(value = xxx),取代Spring框架提供的Service(xxx),其次使用Dubbo框架提供的@service注解,这里特别注意,是Dubbo框架提供的@Service注解,这是为什么呢,等会说,
5.6.5.改造注册在Eureka上的其他项目.
首先在启动类上加入@EnableEurekaClient注解,这里我们用interface的方式调用message-svr提供的接口,现在我们创建一个interface类:
接口类上上加入@FeignClient(name=’XXX’) 注意,name要写你要调用的服务的名字,这里是我们之前改造的message-svr服务,而下面要写上你要调用接口的名,返回参数,参数列表,@RequestMapping要写上这个方法对应的路径和调用方式.
这里我们写的这个方法对应的是message-svr的这个接口:
然后,使用的时候,消费方只要用@AutoWired,注入我们写好的这个interface就可以了.
5.7.测试结果
我在消费者服务新建一个Controller类,讲我们刚才写的interface注入进来,如下:
启动项目,然后使用工具调用这个接口.
说明我们这个端口8084的服务,已经请求到message-svr的接口并返回了查询结果.
6.总结
6.1 为什么使用Dubbo提供的@Service注解
我们看一下dubbo-spring-boot-starter包的源码:
1.首先DubboProperties类会获取到我们配置到application.yml中的配置.
2.对这些配置初始化.
3.获取到所有写了@service注解的类,使用反射生成这些类的代理类.
4.当我们使用http请求,请求这些有@service注解类的方法时, 他会将http请求转换成dubbo请求,去调用这个被代理的类,将调用结果返回回去.
6.2 关于feign
Feign是一个声明式的Web Service客户端,它使得编写Web Serivce客户端变得更加简单。我们只需要使用Feign来创建一个接口并用注解来配置它既可完成,相对于使用httpClient,这种方式更加的优雅.
Feign底层实际是对Spring框架自己RestTemplate的封装,而RestTemplate是Spring自己封装的一套’HttpClient’.
Feign集成了Ribbon支持负载均衡,默认方式是轮询.