微服务作为当下流行的服务架构,已经渐渐地成为Web应用开发者必备的技能之一。目前我们项目正在做微服务的升级改造,使用的是SpringBoot作为底层容器,服务间通讯的RPC框架,我们选用的是
apache-dubbo ,服务的注册中心选用的是zookeeper。
本文主要是介绍我们使用springboot, apache-dubbo,zookeeper搭建的项目架构。
先介绍下基本的项目架构
整个项目分为三个模块,分别是服务消费方,服务提供者,以及对外暴露的服务。
所有的模块都是依赖父类项目的。下来我们看看父项目的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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
<groupId>org.smn.it</groupId>
<artifactId>springbootdubbodemo</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>consumer</module>
<module>provider</module>
<module>service</module>
</modules>
<packaging>pom</packaging>
<dependencies>
<!-- <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency> -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.18</version>
</dependency>
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<!-- <dependency> <groupId>com.it.sunflower</groupId> <artifactId>my-starter</artifactId>
<version>0.0.1-SNAPSHOT</version> </dependency> -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.8.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-spring-boot-starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjlib</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectj-tools</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.33</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.eclipse.jetty/jetty-server -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.4.7.RC0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.eclipse.jetty/jetty-annotations -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-annotations</artifactId>
<version>9.4.7.RC0</version>
</dependency>
</dependencies>
</project>
主要是项目以来的jar,包含springboot项目的starter,zookeeper,
dubbo的springbootstarter以及dubbo的jar包。其他的jar包主要是dubbo使用其他传输协议时使用,如hessian和http。
服务包
主要是定义了一个接口,供服务提供者和消费者使用。我们都知道dubbo服务的调用就像调用本地方法一样。因此,服务消费者和服务提供者都需要依赖此模块。
服务提供者provider
我们先看看它的yml文件中的配置
spring:
application:
name: provider
server:
port: 8080
dubbo:
#注册中心地址
registry:
address: zookeeper://127.0.0.1:2181
application:
name: ${spring.application.name}
# 协议配置
protocol:
id: dubbo
name: dubbo
port: 20881
host: 127.0.0.1
主要是配置了我们应用的端口号,dubbo的服务注册中心地址以及dubbo协议的一些配置,包含端口号和主机名称,协议的名称。
接下来我们看看Provider的启动类
package org.smn.it.provider;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class);
}
}
@EnableDubbo注解表示用dubbo的配置。
服务实现类:
package org.smn.it.provider.service;
import org.apache.dubbo.config.annotation.Service;
import org.smn.it.service.HelloServices;
import org.springframework.stereotype.Component;
@Service(interfaceClass = HelloServices.class)
@Component
public class HelloServicesImpl implements HelloServices {
@Override
public String sayHello() {
return "Hello world dubbo!";
}
}
特别需要注意的是:上面配置的注解Service是dubbo的注解,不是spring的注解,因此还需要加上Component注解,将其转换为一个spring 的bean。
返回一个字符串:Hello world dubbo!
服务消费者
我们先看看其配置文件
spring:
application:
name: consumer
server:
port: 9090
dubbo:
registry:
address: zookeeper://127.0.0.1:2181
application:
name: ${spring.application.name}
protocol:
id: dubbo
name: dubbo
port: 20880
host: 127.0.0.1
主要也是包含web应用的端口,以及注册中心和协议的配置。
服务启动类:
package org.smn.it.consumer;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class);
}
}
服务调用类:
package org.smn.it.consumer.service;
import org.apache.dubbo.config.annotation.Reference;
import org.smn.it.service.HelloServices;
import org.springframework.stereotype.Service;
@Service
public class CommonServices {
@Reference
private HelloServices helloServices;
public String sayHello() {
return helloServices.sayHello();
}
}
简单的控制器类
package org.smn.it.consumer.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.smn.it.consumer.service.CommonServices;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/common")
@RestController()
public class CommonController {
private static final Logger logger = LoggerFactory.getLogger(CommonController.class);
@Autowired
private CommonServices commonServices;
@GetMapping()
public String common() {
String hello = commonServices.sayHello();
logger.info("result from remote is {}", hello);
return hello;
}
}
启动后通过postman调用访问,查看日志和返回值的输出。
2020-03-29 15:03:21.426 WARN 20556 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : Unable to start LiveReload server
2020-03-29 15:03:21.493 INFO 20556 --- [ restartedMain] .f.a.DubboConfigBindingBeanPostProcessor : The properties of bean [name : dubbo] have been binding by prefix of configuration properties : dubbo.protocol
2020-03-29 15:03:21.656 INFO 20556 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2020-03-29 15:03:21.744 INFO 20556 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 9090 (http) with context path ''
2020-03-29 15:03:21.751 INFO 20556 --- [ restartedMain] org.smn.it.consumer.ConsumerApplication : Started ConsumerApplication in 12.583 seconds (JVM running for 14.987)
2020-03-29 15:04:10.531 INFO 20556 --- [nio-9090-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2020-03-29 15:04:10.531 INFO 20556 --- [nio-9090-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2020-03-29 15:04:10.571 INFO 20556 --- [nio-9090-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 40 ms
2020-03-29 15:04:10.787 INFO 20556 --- [nio-9090-exec-1] o.s.i.c.controller.CommonController : result from remote is Hello world dubbo!
可以看到服务的调用已经完成了。
以上内容就是SpringBoot整合apachedubbo完成服务调用的一个简单例子。
多协议配置
当然了dubbo是支持多协议调用的,下面我们再看看如何配置多协议,以及如何调用。
首先我们在,两个应用配置文件中新增hessian和http协议。
spring:
application:
name: consumer
server:
port: 9090
dubbo:
registry:
address: zookeeper://127.0.0.1:2181
application:
name: ${spring.application.name}
protocol:
id: dubbo
name: dubbo
port: 20880
host: 127.0.0.1
protocols:
hessian:
id: hessian
name: hessian
port: 20991
host: 127.0.0.1
http:
id: http
name: http
port: 30011
host: 127.0.0.1
consumer和provider的新增配置一样,注意端口号不能配置成一样的。
服务提供者的服务类变化如下
package org.smn.it.provider.service;
import org.apache.dubbo.config.annotation.Service;
import org.smn.it.service.HelloServices;
import org.springframework.stereotype.Component;
@Service(interfaceClass = HelloServices.class, protocol = {"dubbo", "hessian", "http"})
@Component
public class HelloServicesImpl implements HelloServices {
@Override
public String sayHello() {
return "Hello world dubbo!";
}
}
新增了两种hessian和http两种端口协议。
下来我们看看服务调用者中的变化:
package org.smn.it.consumer.service;
import org.apache.dubbo.config.annotation.Reference;
import org.smn.it.service.HelloServices;
import org.springframework.stereotype.Service;
@Service
public class CommonServices {
@Reference(protocol = "http")
private HelloServices helloServices;
public String sayHello() {
return helloServices.sayHello();
}
}
我们使用http协议进行调用。
看看控制台的调用结果如下:
2020-03-29 15:16:56.055 INFO 20660 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 9090 (http) with context path ''
2020-03-29 15:16:56.061 INFO 20660 --- [ restartedMain] org.smn.it.consumer.ConsumerApplication : Started ConsumerApplication in 17.096 seconds (JVM running for 19.602)
2020-03-29 15:17:24.781 INFO 20660 --- [nio-9090-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2020-03-29 15:17:24.781 INFO 20660 --- [nio-9090-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2020-03-29 15:17:24.822 INFO 20660 --- [nio-9090-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 41 ms
2020-03-29 15:17:25.253 INFO 20660 --- [nio-9090-exec-1] o.s.i.c.controller.CommonController : result from remote is Hello world dubbo!
这说明我们新配置的http协议已经生效了。并且已成功调用。