随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。简单了解一下,网站架构的发展历程:
- 单一应用架构
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。
- 垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。
- 分布式服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。这种架构也就是所说的面向服务的架构,一般方法为把工程拆分成服务层、表现层。服务层中包含业务逻辑,真正对外提供服务。表现层只需要定义服务协议(接口),业务逻辑都是调用服务层的服务来实现,这样不光开发效率快,而且在扩展和升级相关服务的时候更加灵活。
- 流动计算架构
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。
在大规模服务化之前,应用可能只是通过RMI或Hessia 等工具,简单的暴露和引用远程服务,通过配置服务的URL地址进行调用,通过 F5 等硬件进行负载均衡。当服务越来越多时,服务URL配置管理变得非常困难,F5硬件负载均衡器的单点压力也越来越大。 此时需要一个服务注册中心,动态的注册和发现服务,使服务的位置透明。并通过在消费方获取服务提供方地址列表,实现软负载均衡和Failover,降低对F5硬件负载均衡器的依赖,也能减少部分成本。其实Dubbo就是SOA服务治理的一个优秀的实现方案。
Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的RPC实现服务的输出和输入功能,可以和Spring框架无缝集成。
介绍完Dubbo的基本概念,本篇文章讲述一下,Spring Boot与Dubbo集成的实现方案。Dubbo现在已经成为Apache社区优秀开源项目,在Maven中心仓库现在最新的版本是2.6.3。在开源后,Dubbo很长一段时间处官方未支持状态,直至2017年才重启了官方的维护。期间很多公司在Dubbo的基础上,根据自身的需求,为Dubbo实现了一些新的功能,比如当当的Dubbox,现在最新版本是2.8.4。因为之前用Maven中心仓库的2.6.3版本存在一些bug,比如使用telnet invoke测试时,如果dubbo服务的request是对象,会报no such method异常,所以本文使用的是2.8.4版本。2.8.4在Maven中心仓库拉不到,需要手动下载dubbox源码进行编译获取jar包,如果不想手动打包,可以到我的网盘下载,链接: https://pan.baidu.com/s/1yL_lcyS2nfFABG5hiv_lZw 密码: 752f。可以通过maven中心仓库拉取2.6.3的Dubbo依赖,然后手动将com.alibaba:dubbo手动替换成2.8.4版本,注意同时要添加com.alibaba:fastjson依赖,否则telnet invoke测试依然报错。
在测试dubbo之前,要安装dubbo注册中心——Zookeeper(其实也可以不适用Zookeeper作为注册中心,Redis也可以),安装方法windows、Linux直接通过apt安装即可。
1. 项目结构
| .gitignore
| pom.xml
| springboot-11-dubbo.iml
+---dubbo-consumer
| | dubbo-consumer.iml
| | pom.xml
| |
| +---src
| | +---main
| | | +---java
| | | | \---com
| | | | \---zhuoli
| | | | \---service
| | | | \---springboot
| | | | \---dubbo
| | | | \---consumer
| | | | | DubboConsumerApplicationContext.java
| | | | |
| | | | +---common
| | | | | +---request
| | | | | | SayHelloConsumerRequest.java
| | | | | |
| | | | | \---vo
| | | | | SayHelloConsumerVo.java
| | | | |
| | | | +---controller
| | | | | HelloController.java
| | | | |
| | | | \---core
| | | | | HelloControllerService.java
| | | | |
| | | | \---impl
| | | | HelloControllerServiceImpl.java
| | | |
| | | \---resources
| | | dubbo-consumer.xml
| | |
| | \---test
| | \---java
+---dubbo-contract
| | dubbo-contract.iml
| | pom.xml
| |
| +---src
| | +---main
| | | +---java
| | | | \---com
| | | | \---zhuoli
| | | | \---service
| | | | \---springboot
| | | | \---dubbo
| | | | \---contract
| | | | +---request
| | | | | SayHelloRequest.java
| | | | |
| | | | +---service
| | | | | DubboTestService.java
| | | | |
| | | | \---vo
| | | | SayHelloVo.java
| | | |
| | | \---resources
| | \---test
| | \---java
\---dubbo-provider
| dubbo-provider.iml
| pom.xml
|
+---src
| +---main
| | +---java
| | | \---com
| | | \---zhuoli
| | | \---service
| | | \---springboot
| | | \---dubbo
| | | \---provider
| | | | DubboProviderApplicationContext.java
| | | |
| | | \---core
| | | \---rpc
| | | DubboTestServiceImpl.java
| | |
| | \---resources
| | dubbo-provider.xml
| | logback.xml
| |
| \---test
| \---java
该项目跟以往的示例代码有所不同,该项目是个多module项目,可以理解为每个module都是一个独立的项目。
- dubbo-provider:dubbo服务提供方
- dubbo-consumer:dubbo服务消费放
- dubbo-contract:之前讲的面向服务架构的协议,提供方通过协议暴露服务,消费方通过协议消费服务
2. 父pom.xml定义
<?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.zhuoli.service</groupId>
<artifactId>springboot-11-dubbo</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>dubbo-provider</module>
<module>dubbo-consumer</module>
<module>dubbo-contract</module>
</modules>
<!-- 继承说明:这里继承SpringBoot提供的父工程 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.7.RELEASE</version>
<relativePath/>
</parent>
<!-- 版本说明:这里统一管理依赖的版本号 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.zhuoli.service</groupId>
<artifactId>dubbo-provider</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.zhuoli.service</groupId>
<artifactId>dubbo-consumer</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/dubbo -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.5.9</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.44</version>
</dependency>
</dependencies>
</project>
注意如果要使用2.8.4版本的Dubbo,通过Maven获取依赖后,要手动替换com.alibaba:dubbo jar包。其实不替换也可以,我测试了一下,2.6.3版本只是在使用telnet invoke消费时会报”no such method”异常,除此之外,都是正常的。
3. Dubbo Contract
@Getter
@Setter
public class SayHelloRequest implements Serializable {
private String content;
}
@Getter
@Setter
public class SayHelloVo implements Serializable {
private String result;
}
public interface DubboTestService {
SayHelloVo sayHello(SayHelloRequest request);
}
contract的意义在于dubbo服务提供方暴露服务,而服务消费方通过协议消费提供方的服务。实际开发中通常将contract作为提供方的一个子module,通过maven/gradle集成自动打包工具,将contract发布到公司私服上,消费方通过maven/gradle引用这个包就可以了。但是在本项目中,不具备这些条件,所以我将contract单独作为一个module,然后通过provider和consumer的pom.xml添加对dubbo-contract的依赖,达到同样的效果。
4. Dubbo Provider
4.1 pom.xml
<?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>springboot-11-dubbo</artifactId>
<groupId>com.zhuoli.service</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbo-provider</artifactId>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!--添加dubbo-contract依赖-->
<dependency>
<groupId>com.zhuoli.service</groupId>
<artifactId>dubbo-contract</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
4.2 服务暴露
在src/main/resources目录下定义dubbo-provider.xml文件,暴露dubbo服务,如下:
<?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服务名称-->
<dubbo:application name="springboot-dubbo-provider" />
<!--dubbo注册地址-->
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<!--dubbo服务端口-->
<dubbo:protocol name="dubbo" port="10001" />
<!--服务实现-->
<bean id="dubboTestService" class="com.zhuoli.service.springboot.dubbo.provider.core.rpc.DubboTestServiceImpl"/>
<!--dubbo服务暴露-->
<dubbo:service interface="com.zhuoli.service.springboot.dubbo.contract.service.DubboTestService"
protocol="dubbo"
ref="dubboTestService"
timeout="5000"/>
</beans>
4.3 服务实现
@Service
public class DubboTestServiceImpl implements DubboTestService {
@Override
public SayHelloVo sayHello(SayHelloRequest request) {
SayHelloVo sayHelloVo = new SayHelloVo();
sayHelloVo.setResult("Hello: " + request.getContent());
return sayHelloVo;
}
}
4.4 dubbo-provider web服务启动入口
@SpringBootApplication
@ImportResource(value = "dubbo-provider.xml")
public class DubboProviderApplicationContext {
public static void main(String[] args) {
SpringApplication.run(DubboProviderApplicationContext.class, args);
}
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
/*http端口*/
return container -> container.setPort(9898);
}
}
4.5 配置web服务启动Configuration
配置方法见Spring Boot入门Intellij Idea配置Edit Configurations启动程序章节。
5. Dubbo Consumer
5.1 pom.xml
<?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>springboot-11-dubbo</artifactId>
<groupId>com.zhuoli.service</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbo-consumer</artifactId>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!--dubbo contract依赖-->
<dependency>
<groupId>com.zhuoli.service</groupId>
<artifactId>dubbo-contract</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
5.2 dubbo consumer注册服务
在src/main/resources目录下定义dubbo-consumer.xml文件,引用dubbo服务,如下:
<?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="springboot-dubbo-consumer"/>
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<dubbo:reference id="dubboTestService"
interface="com.zhuoli.service.springboot.dubbo.contract.service.DubboTestService"
check="false"
validation="true"
timeout="5000"/>
</beans>
5.3 dubbo-consumer web服务启动入口
@SpringBootApplication
@ImportResource(value = "dubbo-consumer.xml")
public class DubboConsumerApplicationContext {
public static void main(String[] args) {
SpringApplication.run(DubboConsumerApplicationContext.class, args);
}
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return container -> container.setPort(9899);
}
}
定义之后,也要配置web服务启动Configuration,配置方法跟4.5节一致。
5.4 controller web接口
@RestController
@RequestMapping(value = "/consumer/hello")
@AllArgsConstructor
public class HelloController {
private HelloControllerService helloControllerService;
@RequestMapping(value = "/say_hello", method = RequestMethod.POST)
public ResponseEntity<SayHelloConsumerVo> sayHello(@Valid @RequestBody SayHelloConsumerRequest request){
return ResponseEntity.status(HttpStatus.OK).body(helloControllerService.sayHello(request));
}
}
5.5 service层服务
public interface HelloControllerService {
SayHelloConsumerVo sayHello(SayHelloConsumerRequest request);
}
@Service
@AllArgsConstructor
public class HelloControllerServiceImpl implements HelloControllerService {
private DubboTestService dubboTestService;
@Override
public SayHelloConsumerVo sayHello(SayHelloConsumerRequest request) {
SayHelloRequest sayHelloRequest = new SayHelloRequest();
sayHelloRequest.setContent(request.getContent());
SayHelloVo sayHelloVo = dubboTestService.sayHello(sayHelloRequest);
SayHelloConsumerVo sayHelloConsumerVo = new SayHelloConsumerVo();
sayHelloConsumerVo.setResult(sayHelloVo.getResult());
return sayHelloConsumerVo;
}
}
可以看到,对dubbo服务的引用就是通过contract接口实现的。
5.6 测试
将provider、consumer web服务启动,通过postman发送请求,查看结果,如下: 以上,就是一次dubbo的简单调用过程,只是讲述一下简单的使用方法,对于dubbo来讲仅仅是皮毛,dubbo作为优秀的SOA服务治理框架,比如负载均衡,服务分组等高级应用,我的了解也是比较少少,以后有机会希望可以研究一下dubbo源码,深入一下对Dubbo的了解
示例代码:码云 – 卓立 – Spring Boot + Dubbo示例
参考链接: