| | |
| | | ## algo-java |
| | | ## 介绍 |
| | | |
| | | Dubbo是一款高性能、轻量级的开源Java RPC(Remote Procedure |
| | | Call,远程过程调用)框架,它提供了分布式系统中服务之间的高效、透明化的服务调用方案。Dubbo最初由阿里巴巴公司开发并开源,现已成为Apache顶级项目。 |
| | | |
| | | ## 架构演变 |
| | | |
| | | 在了解dubbo之后,我们要知道dubbo在当今互联网架构中在什么样的位置,我们先来看一个架构演进图 |
| | | |
| | |  |
| | | |
| | | 而了解过feign的同学这里就可以拿它和dubbo对比,在上面的图中,feign就是在微服务架构承担rpc框架,而dubbo就在在上面的SOA((Service-Oriented |
| | | Architecture,面向服务的架构)是一个组件模型,它将应用程序的不同功能单元(称为服务)进行拆分,并通过这些服务之间定义良好的接口和契约联系起来。)架构中承担rpc框架的角色。 |
| | | |
| | | SOA架构,就像是大部门制,一个部门管的事儿比较多,几个相关的工作一块儿干,这样大家协作起来方便,但是部门和部门之间还是得互相配合,有时候沟通多了就复杂了。而且,这种模式下,大家用的工具和流程尽量统一,为了好配合。 |
| | | 微服务架构呢,就像是小团队制,每个小团队就专攻一件事,特别专注,自己管自己那一块,出了问题也不容易影响别人。这种模式灵活多了,每个小团队还能根据自己的喜好选最好的工具干活,更新换代快。不过,这么多小团队,怎么让它们高效合作,也得好好设计一套规则。 |
| | | |
| | | ## DUBBO |
| | | |
| | | 说了这么多,其实dubbo的精髓就是**把自己的api暴露出去给大家,具体的实现继承自己的api去写实现方法。** |
| | | |
| | | 但是feign就可以完全脱离api提供,可以提供一个restful的http接口,然后其他服务可以直接通过feign进行调用,这也导致了feign的耦合度更低,但是feign在实际开发过程中也可以模仿dubbo暴露api的方式进行架构的搭建。 |
| | | |
| | | 之前我们快速演示一下了dubbo,[每天一个新知识之 SpringBoot+Dubbo 的快速入门](https://blog.csdn.net/csdnerM/article/details/125410232) |
| | | 要使用dubbo首先要搭建一个注册中心,注册中心的目的就是为了让其他的服务调用dubbo服务,在dubbo官方,推荐使用Zookeeper作为注册中心。 |
| | | |
| | | [公司居然还在用zookeeper,吓得我马上学习了相关命令!](https://juejin.cn/post/7376930488738938920) |
| | | |
| | | [Linux安装Zookeeper(图文解说详细版)](https://masiyi.blog.csdn.net/article/details/121848173) |
| | | |
| | | |
| | | |
| | | >  |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | 虽然之前也写过一篇dubbo的快速入门,但是写的简单,时隔两年,这次介绍一些Dubbo的高级特性。 |
| | | |
| | | ## 框架 |
| | | |
| | | 我们先从框架的搭建说起 |
| | | |
| | |  |
| | | |
| | | 这次我们一共建了四个单独的模块,他们没有共同的父模块,但是他们之间有依赖关系,他们之间的关系是这样的: |
| | | |
| | |  |
| | | |
| | | 在service模块中引入了Dubbo的jar包,这样,一套整体的dubbo模块框架就出来了 |
| | | |
| | | ``` |
| | | <dependency> |
| | | <groupId>com.alibaba.boot</groupId> |
| | | <artifactId>dubbo-spring-boot-starter</artifactId> |
| | | <version>0.2.0</version> |
| | | </dependency> |
| | | ``` |
| | | |
| | | 他们的作用分别是: |
| | | |
| | | api模块提供最基础的实体类,枚举类等,最重要是需要暴露出去的抽象接口。 |
| | | |
| | | service写具体的接口的实现类,提供具体的实现类。 |
| | | |
| | | rpc-server里面是一个启动类,因为依赖service模块,可以理解为生产提供者。 |
| | | |
| | | web-server则是主要提供http接口给第三方,如前端调用,也可以引入其他项目的api模块,之后只要有生产者注入到注册中心就可以提供服务了,直接调用api里面的抽象接口方法。 |
| | | |
| | | 说这么多,我们来看里面的具体实现代码,由于篇幅问题,请移至代码仓库查看代码: |
| | | |
| | | [https://gitee.com/wangfugui-ma/springboot-dubbo/tree/dubbo/](https://gitee.com/wangfugui-ma/springboot-dubbo/tree/dubbo/) |
| | | |
| | | 那么,dubbo是需要搭配zookeeper去使用,由于上一篇文章已经讲过了,这里就不再赘述。我们怎么去使用dubbo的一些高级特性呢 |
| | | |
| | | ## 高级特性 |
| | | |
| | | ### 序列化 |
| | | |
| | | 由于我们的实体类是写在api里面的,而api又是供各个项目去引用的,所以如果我们要在其他的项目中获取这个类,例如在这个项目中的queryUser方法中。 |
| | | |
| | | ```java |
| | | package com.zy.controller; |
| | | |
| | | |
| | | import com.alibaba.dubbo.config.annotation.Reference; |
| | | import com.zy.entity.User; |
| | | import com.zy.service.UserService; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | @RestController |
| | | public class UserController { |
| | | |
| | | @Reference//远程注入 |
| | | private UserService userService; |
| | | |
| | | |
| | | @GetMapping("/user") |
| | | public String user() { |
| | | User user = userService.queryUser(); |
| | | return user.toString(); |
| | | } |
| | | } |
| | | |
| | | ``` |
| | | |
| | | 我们的User对象必须实现Serializable接口,例如这样 |
| | | |
| | | ```java |
| | | package com.zy.entity; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | public class User implements Serializable { |
| | | private String name; |
| | | private Integer age; |
| | | |
| | | public String getName() { |
| | | return name; |
| | | } |
| | | |
| | | public void setName(String name) { |
| | | this.name = name; |
| | | } |
| | | |
| | | public Integer getAge() { |
| | | return age; |
| | | } |
| | | |
| | | public void setAge(Integer age) { |
| | | this.age = age; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return "User{" + |
| | | "name='" + name + '\'' + |
| | | ", age=" + age + |
| | | '}'; |
| | | } |
| | | } |
| | | |
| | | ``` |
| | | |
| | | ### 超时 |
| | | |
| | | #### 生产者超时 |
| | | |
| | | 如果我们的生产者需要设置一个超时时间,我们可以在提供方的Service注解中加入timeout属性,就像这样: |
| | | |
| | | ```java |
| | | package com.zy.support; |
| | | |
| | | import com.alibaba.dubbo.config.annotation.Service; |
| | | import com.zy.entity.User; |
| | | import com.zy.service.UserService; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | |
| | | @Service(timeout = 3000) |
| | | @Component |
| | | public class UserServiceSupport implements UserService { |
| | | |
| | | /** |
| | | * 查询user |
| | | */ |
| | | @Override |
| | | public User queryUser() { |
| | | try { |
| | | Thread.sleep(5000); |
| | | } catch (InterruptedException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | User user = new User(); |
| | | user.setAge(18); |
| | | user.setName("王富贵"); |
| | | return user; |
| | | } |
| | | } |
| | | |
| | | ``` |
| | | |
| | | 这样当我们的controller接口调用超过3秒的时候就会报错: |
| | | |
| | | ``` |
| | | com.alibaba.dubbo.remoting.TimeoutException: Waiting server-side response timeout. start time: 2024-06-15 21:24:14.504, end time: 2024-06-15 21:24:17.511, client elapsed: 1 ms, server elapsed: 3006 ms, timeout: 3000 ms, request: Request [id=2, version=2.0.0, twoway=true, event=false, broken=false, data=RpcInvocation [methodName=queryUser, parameterTypes=[], arguments=[], attachments={path=com.zy.service.UserService, interface=com.zy.service.UserService, version=0.0.0, timeout=3000}]], channel: /10.8.0.136:8061 -> /10.8.0.136:20885 |
| | | ``` |
| | | |
| | | 这样我们就从生产方加入了超时控制 |
| | | |
| | | #### 消费者超时 |
| | | |
| | | 其实我们也可以从消费者这边控制超时时间,就像这样: |
| | | |
| | | ``` |
| | | package com.zy.controller; |
| | | |
| | | |
| | | import com.alibaba.dubbo.config.annotation.Reference; |
| | | import com.zy.entity.User; |
| | | import com.zy.service.UserService; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | @RestController |
| | | public class UserController { |
| | | |
| | | @Reference(timeout = 1000)//远程注入 |
| | | private UserService userService; |
| | | |
| | | |
| | | @GetMapping("/user") |
| | | public String user() { |
| | | User user = userService.queryUser(); |
| | | return user.toString(); |
| | | } |
| | | } |
| | | |
| | | ``` |
| | | |
| | | 在Reference注解中加入timeout属性也是可以达到一样的效果: |
| | | |
| | | ``` |
| | | com.alibaba.dubbo.remoting.TimeoutException: Waiting server-side response timeout. start time: 2024-06-15 21:25:25.398, end time: 2024-06-15 21:25:26.399, client elapsed: 0 ms, server elapsed: 1001 ms, timeout: 1000 ms, request: Request [id=2, version=2.0.0, twoway=true, event=false, broken=false, data=RpcInvocation [methodName=queryUser, parameterTypes=[], arguments=[], attachments={path=com.zy.service.UserService, interface=com.zy.service.UserService, version=0.0.0, timeout=1000}]], channel: /10.8.0.136:8570 -> /10.8.0.136:20885 |
| | | ``` |
| | | |
| | | ### @Autowired |
| | | |
| | | 除了使用@Reference注解注入dubbo服务外,还可以使用@Autowired去注入dubbo服务 |
| | | |
| | |  |
| | | |
| | | ### 配置文件 |
| | | |
| | | ``` |
| | | dubbo.application.name=web-server |
| | | dubbo.registry.address=zookeeper://127.0.0.1:2181 |
| | | ``` |
| | | |
| | | 在配置文件中写上最基础的两个配置,dubbo.registry.address可以不带zookeeper前缀,但是要加个配置key |
| | | |
| | | ``` |
| | | # 如果不加这个,就需要在address里面加zookeeper:// |
| | | dubbo.registry.protocol=zookeeper |
| | | ``` |
| | | |
| | | 注意这个配置: |
| | | |
| | | ``` |
| | | dubbo.protocol.port=20885 |
| | | ``` |
| | | |
| | | dubbo默认用20880端口,如果你需要在一个服务器上面启动多个dubbo服务,那就不能让他们的端口冲突 |
| | | |
| | | ``` |
| | | dubbo.registry.password=zk_password |
| | | dubbo.registry.username=zk_user |
| | | ``` |
| | | |
| | | 如果你的节点有acl权限,则可能需要加上这两个配置,替换value |
| | | |
| | | 如果你还不知道acl权限是什么,推荐你看一下这篇文章 |
| | | |
| | | [公司居然还在用zookeeper,吓得我马上学习了相关命令!](https://juejin.cn/post/7376930488738938920) |
| | | |
| | | ### @EnableDubbo |
| | | |
| | | 记得在启动类开启这个注解,否则不能使用dubbo的相关服务,你懂的。。。。 |
| | | |
| | | >  |
| | | |