介绍
文档来自:https://dubbo.apache.org/docs/v2.7/
dubbo+springboot环境搭建:注解配置方式
zookeeper注册中心
下载
官网下载地址:https://archive.apache.org/dist/zookeeper/
这里用3.4.10。
配置
打开conf/zoo.cfg,配置data目录和log目录。
启动
运行bin/zkServer.cmd,如下界面就算成功:
放着窗口别关就行。
父工程搭建
父工程主要做版本锁定,只留pom.xml,src可以删掉。
module:
<groupId>com.atguigu</groupId>
<artifactId>dubbo</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
pom:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>user-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- Spring Boot相关依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${springboot.version}</version>
</dependency>
<!-- springboot web模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${springboot.version}</version>
</dependency>
<!-- 引入spring-boot-starter以及dubbo和curator的依赖 -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo-springboot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${springboot.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
服务接口定义模块
module:
<artifactId>user-interface</artifactId>
IUserService:
package com.atguigu.dubbo.service;
public interface IUserService {
public String getUserId(String id);
}
服务提供者模块
module:
<artifactId>user-provider</artifactId>
pom:
<dependencies>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>user-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- Spring Boot相关依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 引入spring-boot-starter以及dubbo和curator的依赖 -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
可以看到,dubbo的starter里面带dubbo+curator:
操作zookeeper的jar包依赖:
yaml:
application.yaml:
dubbo:
application:
name: user-provider
registry:
protocol: zookeeper
address: 127.0.0.1:2181
protocol:
name: dubbo
port: 20880
主启动:
package com.atguigu.dubbo;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableDubbo
@SpringBootApplication
public class ProviderMain {
public static void main(String[] args) {
SpringApplication.run(ProviderMain.class,args);
}
}
业务类:
UserServiceImpl:
package com.atguigu.dubbo.service.impl;
import com.alibaba.dubbo.config.annotation.Service;
import com.atguigu.dubbo.service.IUserService;
//暴露服务
@Service
@org.springframework.stereotype.Service
public class UserServiceImpl implements IUserService {
@Override
public String getUserId(String id) {
return "id:"+id;
}
}
服务消费者模块
module:
<artifactId>user-consumer</artifactId>
pom:
<dependencies>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>user-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- Spring Boot相关依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- springboot web模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入spring-boot-starter以及dubbo和curator的依赖 -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
yaml:
server:
port: 8081
dubbo:
application:
name: user-consumer
registry:
protocol: zookeeper
address: 127.0.0.1:2181
主启动:
package com.atguigu.dubbo;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo
public class ConsumerMain {
public static void main(String[] args) {
SpringApplication.run(ConsumerMain.class,args);
}
}
业务类:
package com.atguigu.dubbo.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.atguigu.dubbo.service.IUserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
//引入暴露的服务
@Reference
private IUserService userService;
@GetMapping("/user/{id}")
public String getUserId(@PathVariable("id") String id) {
return userService.getUserId(id);
}
}
测试:
打开网址:http://localhost:8081/user/1
可以得到结果,即为通过。
dubbo+spring环境搭建:xml配置方式
建个dubbo-spring的父工程。
interface
package com.coderhao.service;
public interface IUserService {
public String getUserId(String id);
}
provider
module:
<artifactId>user-provider</artifactId>
pom:
<dependencies>
<dependency>
<groupId>com.coderhao</groupId>
<artifactId>user-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
</dependencies>
provider.xml:
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--容器中注入java bean-->
<bean id="userServiceImpl" class="com.coderhao.service.impl.UserServiceImpl"></bean>
<!--服务提供方的应用名,相同微服务相同名,不同微服务不同名。-->
<dubbo:application name="user-provider"></dubbo:application>
<!--注册中心信息-->
<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"></dubbo:registry>
<!--服务的暴露协议与暴露端口-->
<dubbo:protocol name="dubbo" port="20880"></dubbo:protocol>
<!--暴露服务的接口与实现类-->
<dubbo:service interface="com.coderhao.service.IUserService" ref="userServiceImpl"></dubbo:service>
</beans>
log4j.properties:
### 设置###
log4j.rootLogger = debug,stdout,D,E
### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 输出DEBUG 级别以上的日志到=://logs/log.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = D://software/log/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### 输出ERROR 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =D://software/log/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
UserServiceImpl:
package com.coderhao.service.impl;
import com.coderhao.service.IUserService;
public class UserServiceImpl implements IUserService {
@Override
public String getUserId(String id) {
return "id:"+id;
}
}
ProviderMain:
package com.coderhao;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ProviderMain {
public static void main(String[] args) throws Exception{
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("provider.xml");
applicationContext.start();
//弄个按任意键退出的代码,防止程序执行结束。
System.in.read();
}
}
consumer
module:
<artifactId>user-consumer</artifactId>
pom:
<dependencies>
<dependency>
<groupId>com.coderhao</groupId>
<artifactId>user-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
</dependencies>
consumer.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://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="user-consumer"></dubbo:application>
<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"></dubbo:registry>
<!--生成远程服务代理,使其可以注入使用-->
<dubbo:reference id="iUserService" interface="com.coderhao.service.IUserService"></dubbo:reference>
</beans>
log4j.properties:
同上,也可以改改,不然日志输出太多了,影响查找测试结果:
ConsumerMain:
package com.coderhao;
import com.coderhao.service.IUserService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ConsumerMain {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml");
context.start();
IUserService userService = (IUserService) context.getBean("iUserService"); // 获取远程服务代理,或者注入使用
String result = userService.getUserId("2"); // 执行远程方法
System.out.println("******************result:"+result); // 显示调用结果
}
}
注:
测试
1.启动zookeeper
2.启动provider
3.启动consumer
xml配置
各详细匹配,请参考文档:https://dubbo.apache.org/zh/docsv2.7/user/references/xml/
比如负载均衡的:
配置优先级
微服务配置的优先级
以 timeout 为例,下图显示了配置的查找顺序,其它 retries, loadbalance, actives 等类似:
- 方法级优先,接口级次之,全局配置再次之。
- 如果级别一样,则消费方优先,提供方次之。
其中,服务提供方配置,通过 URL 经由注册中心传递给消费方。
(建议由服务提供方设置超时,因为一个方法需要执行多长时间,服务提供方更清楚,如果一个消费方同时引用多个服务,就不需要关心每个服务的超时设置)。
配置文件优先级
优先级从高到低:
- JVM -D 参数:当你部署或者启动应用时,它可以轻易地重写配置,比如,改变 dubbo 协议端口;
- XML:XML 中的当前配置会重写 dubbo.properties 中的;
- Properties:默认配置,仅仅作用于以上两者没有配置时。
配置来源优先级
- JVM System Properties,-D 参数
- Externalized Configuration,外部化配置
- ServiceConfig、ReferenceConfig 等编程接口采集的配置
- 本地配置文件 dubbo.properties
rest风格接入
和RPC方式类似。有改动的地方:
在原RPC风格基础上添加依赖:
<dependencies>
<!-- REST风格远程调用 -->
<!--jax-rs 标准的依赖 -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.0.7.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>3.0.7.Final</version>
</dependency>
<!-- jetty的依赖-->
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>6.1.26</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>8.0.11</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-logging-juli</artifactId>
<version>8.0.11</version>
</dependency>
<!-- 如果要使用json序列化 -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
<version>3.0.7.Final</version>
</dependency>
<!-- 如果要使用xml序列化 -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxb-provider</artifactId>
<version>3.0.7.Final</version>
</dependency>
</dependencies>
改动xml,协议改为rest:
业务类:
package com.coderhao.service.impl;
import com.coderhao.service.IUserService;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
@Path("restful")
public class UserServiceImpl implements IUserService {
@Path("user")
@POST
//接受json格式的数据
@Consumes({MediaType.APPLICATION_JSON})
@Override
public String getUserId(String id) {
String result="**********result-restful:id:"+id;
System.out.println(result);
return result;
}
}
最佳实践
在 Provider 端尽量多配置 Consumer 端属性
原因如下:
- 作为服务的提供方,比服务消费方更清楚服务的性能参数,如调用的超时时间、合理的重试次数等
- 在 Provider 端配置后,Consumer 端不配置则会使用 Provider 端的配置,即 Provider 端的配置可以作为 Consumer 的缺省值 1。否则,Consumer 会使用 Consumer 端的全局设置,这对于 Provider 是不可控的,并且往往是不合理的
Provider 端尽量多配置 Consumer 端的属性,让 Provider 的实现者一开始就思考 Provider 端的服务特点和服务质量等问题。
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService"
timeout="300" retries="2" loadbalance="random" actives="0" />
<dubbo:service interface="com.alibaba.hello.api.WorldService" version="1.0.0" ref="helloService"
timeout="300" retries="2" loadbalance="random" actives="0" >
<dubbo:method name="findAllPerson" timeout="10000" retries="9" loadbalance="leastactive" actives="5" />
<dubbo:service/>
在 Provider 端配置合理的 Provider 端属性
<dubbo:protocol threads="200" />
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService"
executes="200" >
<dubbo:method name="findAllPerson" executes="50" />
</dubbo:service>