1.文档参照
2.三个工程
2.1 公共接口工程
这个工程中存放的是一些公共的Java Bean、相关接口信息。
其中UserService接口是针对服务提供者的,OrderService接口是针对服务消费者的。
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.10</version> </dependency>
package com.szh.gmall.bean; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; /** * */ @Data @AllArgsConstructor @NoArgsConstructor public class UserAddress implements Serializable { private Integer id; private String userAddress; //用户地址 private String userId; //用户id private String consignee; //收货人 private String phoneNum; //电话号码 private String isDefault; //是否为默认地址 Y-是 N-否 }
package com.szh.gmall.service; import com.szh.gmall.bean.UserAddress; import java.util.List; /** * */ public interface UserService { /** * 根据用户id返回所有的收货地址 */ List<UserAddress> getUserAddressList(String userId); }
package com.szh.gmall.service; import com.szh.gmall.bean.UserAddress; import java.util.List; /** * */ public interface OrderService { /** * 初始化订单 */ void initOrder(String userId); List<UserAddress> initOrder2(String userId); }
2.2 服务提供者工程
springboot这里我使用的是 2.3.12.RELEASE。dubbo是2.7.8
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- Dubbo Spring Boot Starter --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>${dubbo.version}</version> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> <version>${dubbo.version}</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>com.szh</groupId> <artifactId>common-gmall-interface</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
那么在这个服务提供者中,我们肯定要对上面公共接口中的UserService进行具体的实现。 下面有两个实现类是为了后面测试Dubbo的多版本功能(也即version属性信息)。 @DubboService注解用来暴露服务。
package com.szh.service.impl; import com.szh.gmall.bean.UserAddress; import com.szh.gmall.service.UserService; import org.apache.dubbo.config.annotation.DubboService; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; /** * 1.将服务提供者注册到注册中心 * 1) 引入dubbo依赖、zookeeper客户端依赖 * 2) 配置服务提供者 * 2.让服务消费者从注册中心订阅服务提供者的相关服务 */ @Service @DubboService(interfaceClass = UserService.class, version = "1.0.0") public class UserServiceImpl implements UserService { //The default value of ${dubbo.application.name} is ${spring.application.name} @Value("${dubbo.application.name}") private String applicationName; @Override public List<UserAddress> getUserAddressList(String userId) { UserAddress userAddress1 = new UserAddress(1, "浙江省杭州市", "1", "张三", "123456", "Y"); UserAddress userAddress2 = new UserAddress(2, "湖北省武汉市", "1", "李四", "999999", "N"); try { TimeUnit.MILLISECONDS.sleep(2000); //测试timeout // TimeUnit.MILLISECONDS.sleep(4000); //测试重试次数 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(applicationName + " old...."); return Arrays.asList(userAddress1, userAddress2); } }
package com.szh.service.impl; import com.szh.gmall.bean.UserAddress; import com.szh.gmall.service.UserService; import org.apache.dubbo.config.annotation.DubboService; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; /** * 1.将服务提供者注册到注册中心 * 1) 引入dubbo依赖、zookeeper客户端依赖 * 2) 配置服务提供者 * 2.让服务消费者从注册中心订阅服务提供者的相关服务 */ @Service @DubboService(interfaceClass = UserService.class, version = "2.0.0") public class UserServiceImpl2 implements UserService { //The default value of ${dubbo.application.name} is ${spring.application.name} @Value("${dubbo.application.name}") private String applicationName; @Override public List<UserAddress> getUserAddressList(String userId) { UserAddress userAddress1 = new UserAddress(1, "浙江省杭州市", "1", "张三", "123456", "Y"); UserAddress userAddress2 = new UserAddress(2, "湖北省武汉市", "1", "李四", "999999", "N"); try { TimeUnit.MILLISECONDS.sleep(2000); //测试timeout // TimeUnit.MILLISECONDS.sleep(4000); //测试重试次数 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(applicationName + " new...."); return Arrays.asList(userAddress1, userAddress2); } }
properties配置文件如下,这种方式主要也就是 properties + 注解。
spring.application.name=boot-user-service-provider dubbo.application.name=boot-user-service-provider dubbo.scan.base-packages=com.szh.service.impl dubbo.registry.address=127.0.0.1:2181 dubbo.registry.protocol=zookeeper dubbo.protocol.name=dubbo dubbo.protocol.port=20880 dubbo.monitor.protocol=registry
主启动类上添加 @EnableDubbo注解开启Dubbo的注解配置功能。
package com.szh; import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableDubbo public class BootUserServiceProviderApplication { public static void main(String[] args) { SpringApplication.run(BootUserServiceProviderApplication.class, args); } }
2.3 服务消费者工程
这里是一个springboot web工程,版本仍然和上面的服务提供者相同。dubbo是2.7.8
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Dubbo Spring Boot Starter --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>${dubbo.version}</version> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> <version>${dubbo.version}</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>com.szh</groupId> <artifactId>common-gmall-interface</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
这里我们要通过浏览器访问具体的接口,所以需要一个controller。
package com.szh.controller; import com.szh.gmall.bean.UserAddress; import com.szh.gmall.service.OrderService; import org.apache.dubbo.config.annotation.DubboReference; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import java.util.List; /** * */ @RestController public class OrderController { @Autowired private OrderService orderService; @GetMapping(value = "/initOrder/{userId}") public List<UserAddress> initOrder(@PathVariable("userId") String userId) { return orderService.initOrder2(userId); } }
然后需要对公共接口工程中的OrderService进行实现,因为这是服务消费者。(要表示如何消费,即实现接口就可以了)
@DubboReference注解用来引用服务。
package com.szh.service.impl; import com.szh.gmall.bean.UserAddress; import com.szh.gmall.service.OrderService; import com.szh.gmall.service.UserService; import org.apache.dubbo.config.annotation.DubboReference; import org.apache.dubbo.config.annotation.Method; import org.springframework.stereotype.Service; import java.util.List; /** * */ @Service public class OrderServiceImpl implements OrderService { @DubboReference(interfaceClass = UserService.class, //服务接口名 version = "2.0.0", //服务版本,与服务提供者的版本一致 check = false, //启动时检查提供者是否存在,true报错,false忽略 timeout = 3000, //服务方法调用超时时间(毫秒) methods = @Method(name = "getUserAddressList"), //精确到服务接口的某个方法 retries = 3) //远程服务调用重试次数,不包括第一次调用,不需要重试请设为0 private UserService userService; @Override public List<UserAddress> initOrder2(String userId) { System.out.println("用户id:" + userId); List<UserAddress> addressList = userService.getUserAddressList(userId); return addressList; } @Override public void initOrder(String userId) { } }
server.port=8081 spring.application.name=boot-order-service-consumer dubbo.application.name=boot-order-service-consumer dubbo.registry.address=zookeeper://127.0.0.1:2181 dubbo.monitor.protocol=registry
主启动类上添加 @EnableDubbo注解开启Dubbo的注解配置功能。
package com.szh; import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableDubbo public class BootOrderServiceConsumerApplication { public static void main(String[] args) { SpringApplication.run(BootOrderServiceConsumerApplication.class, args); } }
3.启动测试
启动服务提供者和消费者之前,要先将zookeeper开启,然后再将dubbo管控台打开。
我这里为了方便,就直接在windows下启动zookeeper了,下载请移步官网:https://zookeeper.apache.org/,下载解压之后,找到conf目录下的zoo.cfg文件,做如下修改:
# example sakes. dataDir=E:\\zookeeper\\zookeeper-3.4.11\\data # the port at which the clients will connect clientPort=2181
然后转到bin目录下,cmd启动 zkServer.cmd 即可。
zookeeper相关配置等链接参考:https://dubbo.apache.org/zh/docs/references/registry/zookeeper/
这里需要先启动服务提供者,再启动服务消费者。
由于我们在服务消费者的 @DubboReference 注解中配置了 check=false,所以这里即使启动顺序不对,或者找不到服务提供者,也不会报错,而是直接忽略。
下面是dubbo的管控台,这个不安装也无所谓,我这里就不给出下载安装的步骤了。。。(可以参考尚硅谷-雷神老师的Dubbo课程)
下面通过服务消费者中的接口,可以直接调用到服务提供者的接口,同时获取到相关数据内容。
下面的截图是对应了服务提供者中的 TimeUnit.MILLISECONDS.sleep(2000); //测试timeout 代码。和服务消费者中的 @DubboReference 注解中的timeout属性。
如果服务提供者睡眠时间超过了服务消费者中定义的超时时间,那么就会出现下图的异常。
反之,则可以正常远程调用服务提供者的接口,也就是下下张图。
下面的截图演示的是重试次数,远程服务调用重试次数,不包括第一次调用,不需要重试请设为0。
对应的是服务提供者的 TimeUnit.MILLISECONDS.sleep(4000); //测试重试次数。和服务消费者中的 @DubboReference 注解中的 retries 属性。
这里需要保证服务提供者的响应时间大于服务消费者的等待超时时间,一旦满足,服务消费者此时调不到服务提供者,那么在服务提供者方就会进行重试。
最后这个测试的Dubbo的多版本问题。也就是用到了服务提供者中的两个具体实现类,这二者通过 @DubboService 注解中的 version 加以区分,一个版本为1.0.0、另一个版本为2.0.0。 而在服务消费者中通过 @DubboReference 注解中的version属性来指定具体要消费服务提供者的哪个实现类。
4.Dubbo配置原则
JVM启动 -D 参数优先,这样可以使用户在部署和启动时进行参数重写,比如在启动时需改变协议的端口。
XML次之,如果在 XML 中有配置,则 dubbo.properties 中的相应配置项无效。
Properties最后,相当于缺省值,只有 XML 没有配置时,dubbo.properties 的相应配置项才会生效,通常用于共享公共配置,比如应用名。