Dubbo
Dubbo 最早是 Alibaba 开源的分布式服务框架,它最大的特点是按照分层的方式来架构, 使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合)。从服务模型的角度来看, Dubbo 采用的是一种非常简单的模型,要么是提供方提供服务,要么是消费方消费服务,所 以基于这一点可以抽象出服务提供方(Provider)和服务消费方(Consumer)两个角色。
服务架构角色
- Container:服务运行框架,dubbo完全基于spring实现
- Provider:提供远程调用服务
- Registry:服务注册和发布中心
- Consumer:执行远程调用服务
- Monitor:统计服务调用次数和调用时间的监控中心
服务开启流程
- 启动spring容器Container时会把Provider启动
- 然后将Provider相关信息注册到Registry里
- Consumer从Registry中订阅Provider的信息
- Registry将Provider的信息发送给Consumer
- Consumer根据Registry通知的信息调用Provider中的方法
- Consumer和Provider将调用次数信息异步发送给Monitor统计
Dubbo支持的协议
Dubbo协议
- 优点:采用 NIO 复用单一长连接,并使用线程池并发处理请求,减少握手和加大并发效率, 性能较好(推荐使用)
- 缺点:大文件上传时,可能出现问题(不使用 Dubbo 文件上传)
RMI(Remote Method Invocation)协议
- 优点:JDK自带的
- 缺点:偶尔连接失败
Hessian协议
优点:可与原生Hessian互操作,基于HTTP协议
缺点:需hessian.jar支持,http短连接的开销大
Dubbo支持的注册中心
ZooKeeper
- 优点:支持分布式,周边产品多
- 缺点:受限于ZooKeeper软件的稳定性
Multicast
- 优点:去中心化,不需单独安装软件
- 缺点:Provider、Consumer、Registry不能跨机房(路由)
Redis
- 优点:支持集群,性能高
- 缺点:要求服务器时间同步,否则可能出现集群失败问题
Simple
- 优点:标准RPC服务,没有兼容问题
- 缺点:不支持集群
Dubbo应用
应用结构
- parent:逻辑Maven工程,在pom文件中引入需要的依赖
- api:继承parent工程,定义功能接口,以供provider实现,consumer调用
- provider:继承parent工程,实现api中的接口功能
- consumer:继承parent工程,调用api中的功能接口
创建Parent工程
- 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.lanh</groupId>
<artifactId>parent</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>api</module>
<module>provider</module>
<module>consumer</module>
</modules>
<properties>
<spring.version>5.2.5.RELEASE</spring.version>
<dubbo.version>2.7.6</dubbo.version>
<curator.version>4.2.0</curator.version>
<registry-zookeeper.version>2.7.6</registry-zookeeper.version>
<servlet.version>3.1.0</servlet.version>
<jsp.version>2.0</jsp.version>
<jstl.version>1.2</jstl.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
<version>${registry-zookeeper.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${curator.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>${jsp.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
创建api项目
创建功能接口
public interface DemoDubboService {
String showMsg(String msg);
}
创建provider项目
- 配置pom文件
<dependencies>
<dependency>
<groupId>com.lanh</groupId>
<artifactId>api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
</dependency>
</dependencies>
注意:provider项目和consumer项目都要依赖api项目
- 实现接口
package com.lanh.dubbo.service.impl;
import com.lanh.dubbo.service.DemoDubboService;
import org.apache.dubbo.config.annotation.Service;
/**
* @Author Lanh
**/
@Service
public class DemoDubboServiceImpl implements DemoDubboService {
public String showMsg(String msg) {
return "Helle Dubbo "+msg;
}
}
需要注意的是,这里使用到的注解@Service不是spring中的注解,而是dubbo的注解
- 编写启动类
package com.lanh.dubbo;
import org.apache.dubbo.container.Main;
/**
* Dubbo的启动类
* @Author Lanh
**/
public class Start {
public static void main(String[] args) {
Main.main(args);
}
}
- 配置文件xml
<?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://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 定义服务名称 -->
<dubbo:application name="myProvider" />
<!--配置注册中心-->
<dubbo:registry address="ip:2181,ip:2182,ip:2183" protocol="zookeeper" timeout="10000"/>
<!--配置服务协议及监听端口(任意不被占用的端口)-->
<dubbo:protocol name="dubbo" port="2002" />
<!-- <!–注册接口–>-->
<!-- <dubbo:service interface="com.lanh.dubbo.service.DemoDubboService" ref="demoService"/>-->
<!-- <bean id="demoService" class="com.lanh.dubbo.service.impl.DemoDubboServiceImpl" />-->
<!--注解开发:扫描接口的位置的指定@Service-->
<dubbo:annotation package="com.lanh.dubbo.service.impl" />
</beans>
注意:
- 该配置文件必须放到resources/META-INF/spring/*.xml
- 配置文件中配置注册中心时的ip,需要替换成自己zookeeper的ip
- 在前面我有提及@Service注解,这个对应着是注解开发,另外一种xml开发的形式,我也以注释的形式写在了xml文件
创建consumer项目
web项目是在spring中不需要写启动类,是通过tomcat插件启动的
- 定义Service接口
package com.lanh.service;
public interface DemoService {
String showInfo(String msg);
}
- 实现Service接口
package com.lanh.service.impl;
import com.lanh.dubbo.service.DemoDubboService;
import com.lanh.service.DemoService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;
/**
* Consumer的业务层
* @Author Lanh
**/
@Service
public class DemoServiceImpl implements DemoService {
@Reference
private DemoDubboService demoDubboService;
public String showInfo(String msg) {
return this.demoDubboService.showMsg(msg);
}
}
注意:
- 这里使用到的@Service不同于provider,这个是spring框架的注解
- 同时,这里进行注入时,因为这个不是本地的服务,使用的也不再是@Autowire注解,而是dubbo远程调用的@Reference注解
- 页面跳转
package com.lanh.web.controller;
import com.lanh.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author Lanh
**/
@RestController
public class DemoController {
@Autowired
private DemoService demoService;
@RequestMapping("/getMsg")
public String getMsg(String str){
return this.demoService.showInfo(str);
}
}
- 配置文件
applicationContext-spring.xml
<?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://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!--配置服务名称-->
<dubbo:application name="myConsumer" />
<!--配置注册中心地址以及访问协议-->
<dubbo:registry address="192.168.126.128:2181,192.168.126.128:2182,192.168.126.128:2183" protocol="zookeeper" timeout="10000"/>
<!--dubbo扫描自己@Reference注解-->
<dubbo:annotation package="com.lanh.service.impl"/>
</beans>
applicationContext-service.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.lanh.service" />
</beans>
springmvc.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.lanh.web.controller" />
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext-*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--SpringMVC 中的编码过滤器-->
<filter>
<filter-name>encodeFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodeFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
SpringBoot整合
创建api,maven项目即可
设置功能接口
package com.lanh.dubbo.service;
public interface DemoDubboService {
String showMsg(String str);
}
创建provider项目
- 配置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 https://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.2.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lanh</groupId>
<artifactId>springbootdubbo_provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootdubbo_provider</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.lanh</groupId>
<artifactId>springbootdubbo_api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.6</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
<version>2.7.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 实现api的接口
package com.lanh.springbootdubbo_provider.service.impl;
import com.lanh.dubbo.service.DemoDubboService;
import org.apache.dubbo.config.annotation.Service;
/**
* @Author Lanh
**/
@Service
public class DemoDubboServiceImpl implements DemoDubboService {
@Override
public String showMsg(String str) {
return "Hello Dubbo "+str;
}
}
再说一次这个是@Service是dubbo的注解
- 创建启动类
springboot自带了启动类,不需要再使用dubbo的启动类
package com.lanh.springbootdubbo_provider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootdubboProviderApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootdubboProviderApplication.class, args);
}
}
- 配置application.yml
#指定服务的名称
dubbo:
application:
name: myProvider
registry:
address: 192.168.126.128:2181,192.168.126.128:2182,192.168.126.128:2183
protocol: zookeeper
timeout: 10000
#配置服务所使用的协议
protocol:
name: dubbo
port: 2002
scan:
base-packages: com.lanh.springbootdubbo_provider.service.impl
创建consumer项目
- 配置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 https://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.2.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lanh</groupId>
<artifactId>springbootdubbo_consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootdubbo_consumer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.lanh</groupId>
<artifactId>springbootdubbo_api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.6</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
<version>2.7.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 定义Service接口
package com.lanh.springbootdubbo_consumer.service;
public interface DemoService {
String getMsg(String str);
}
- 实现Service接口
package com.lanh.springbootdubbo_consumer.service.impl;
import com.lanh.dubbo.service.DemoDubboService;
import com.lanh.springbootdubbo_consumer.service.DemoService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;
/**
* @Author Lanh
**/
@Service
public class DemoServiceImpl implements DemoService {
@Reference
private DemoDubboService demoDubboService;
@Override
public String getMsg(String str) {
return this.demoDubboService.showMsg(str);
}
}
再说一次:这个@Service是spring中的注解,用@Reference而不用@Autowire
- 配置页面跳转逻辑
package com.lanh.springbootdubbo_consumer.controller;
import com.lanh.springbootdubbo_consumer.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author Lanh
**/
@RestController
public class DemoController {
@Autowired
private DemoService demoService;
@RequestMapping("/getMsg")
public String getMsg(String str){
return this.demoService.getMsg(str);
}
}
- springboot的启动类
package com.lanh.springbootdubbo_consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootdubboConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootdubboConsumerApplication.class, args);
}
}
- 配置application.yml
#指定服务的名称
dubbo:
application:
name: myConsumer
registry:
address: 192.168.126.128:2181,192.168.126.128:2182,192.168.126.128:2183
protocol: zookeeper
timeout: 10000
#配置服务所使用的协议
protocol:
name: dubbo
至此结束,欢迎各位小伙伴讨论