架构分类:单体架构、垂直架构、SOA架构、微服务架构
分布式
RPC
框架
Apache Dubbo :
RPC
全称为
remote procedure call
,即远程过程调用。Java
中的
RPC
框架比较多,广泛使用的有
RMI
、
Hessian
、
Dubbo
等。
Dubbo
架构
![](https://i-blog.csdnimg.cn/blog_migrate/b90f38cf664e0ad198144eb51eabd78a.png)
节点
角色名称
Provider
暴露服务的服务提供方
Consumer
调用远程服务的服务消费方
Registry
服务注册与发现的注册中心
Monitor
统计服务的调用次数和调用时间的监控中心
Container
服务运行容器
调用关系说明
:
0.
服务容器负责启动,加载,运行服务提供者。
1.
服务提供者在启动时,向注册中心注册自己提供的服务。
2.
服务消费者在启动时,向注册中心订阅自己所需的服务。
3. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
4.
服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失
败,再选另一台调用。
5. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
服务注册中心
Zookeeper
Zookeeper
是
Apache Hadoop
的子项目,是一个树型的目录服务,支持变更推送,适合作为 Dubbo 服务的注册中心,工业强度较高,可用于生产环境,并推荐使用
思考一:
上面的
Dubbo
入门案例中我们是将
HelloService
接口从服务提供者工程
(dubbodemo_provider)
复制到服务消费者工程
(dubbodemo_consumer)
中,这种做法是否合适?还有
没有更好的方式?
答:这种做法显然是不好的,同一个接口被复制了两份,不利于后期维护。更好的方式是单独创建一个maven
工程,将此接口创建在这个
maven
工程中。需要依赖此接口的工程只需要在自己工程的
pom.xml
文件中引入
maven
坐标即可。
思考二:
在服务消费者工程
(dubbodemo_consumer)
中只是引用了
HelloService接口,并没有提供实现类,
Dubbo
是如何做到远程调用的?
答:
Dubbo
底层是基于代理技术为
HelloService接口创建代理对象,远程调用是通过此代理对象完成的。可以通过开发工具的
debug
功能查看此代理对象的内部结构。另外,
Dubbo实现网络传输底层是基于
Netty
框架完成的。
思考三:
上面的
Dubbo
入门案例中我们使用
Zookeeper作为服务注册中心,服务提供者需要将自己的服务信息注册到
Zookeeper
,服务消费者需要从
Zookeeper
订阅自己所需要的服务,此时
Zookeeper服务就变得非常重要了,那如何防止
Zookeeper
单点故障呢?
答:
Zookeeper
其实是支持集群模式的,可以配置
Zookeeper
集群来达到
Zookeeper服务的高可用,防止出现单点故障。
Dubbo
管理控制台
我们在开发时,需要知道
Zookeeper注册中心都注册了哪些服务,有哪些消费者来消费这些服务。我们 可以通过部署一个管理中心来实现。其实管理中心就是一个
web
应用,部署到
tomcat
即可。
解决
Dubbo
无法发布被事务代理的
Service
问题
前面我们已经完成了
Dubbo
的入门案例,通过入门案例我们可以看到通过
Dubbo提供的标签配置就可 以进行包扫描,扫描到
@Service
注解的类就可以被发布为服务。
但是我们如果在服务提供者类上加入
@Transactional事务控制注解后,服务就发布不成功了。原因是事 务控制的底层原理是为服务提供者类创建代理对象,而默认情况下
Spring
是基于
JDK动态代理方式创建 代理对象,而此代理对象的完整类名为
com.sun.proxy.$Proxy42(最后两位数字不是固定的),导致Dubbo在发布服务前进行包匹配时无法完成匹配,进而没有进行服务的发布。
解决方案
通过上面的断点调试可以看到,在
HelloServiceImpl
类上加入事务注解后,
Spring
会为此类基于
JDK动 态代理技术创建代理对象,创建的代理对象完整类名为
com.sun.proxy.$Proxy35
,导致
Dubbo在进行 包匹配时没有成功(因为我们在发布服务时扫描的包为
com.lxs.service),所以后面真正发布服务的代 码没有执行。
解决方式操作步骤:
(1
)修改
applicationContext-service.xml
配置文件,开启事务控制注解支持时指定proxy-target-class属性,值为
true
。其作用是使用
cglib
代理方式为
Service
类创建代理对象
<!--
开启事务控制的注解支持
-->
<tx:annotation-driven
transaction-manager
=
"transactionManager"
proxy-target-
class
=
"true"
/>
![](https://i-blog.csdnimg.cn/blog_migrate/6dbb3d4011399d1975984b591b3fd4d5.png)
(2
)修改
HelloServiceImpl
类,在
Service
注解中加入
interfaceClass
属性,值为
HelloService.class, 作用是指定服务的接口类型
@Service
(
interfaceClass
=
HelloService
.
class
)
@Transactional
public class
HelloServiceImpl
implements
HelloService
{
public
String
sayHello
(
String
name
) {
return
"hello "
+
name
;
}
}
此处也是必须要修改的,否则会导致发布的服务接口为
SpringProxy
,而不是
HelloService
接口,如
下:
![](https://i-blog.csdnimg.cn/blog_migrate/0c30566f9663f38f10f711285691b780.png)