dubbo源码解析-spi(4)
前言
本篇是spi的第四篇,本篇讲解的是spi中增加的AOP,还是和上一篇一样,我们先从大家熟悉的spring引出AOP.
AOP是老生常谈的话题了,思想都不会是一蹴而就的.比如架构设计从All in One到SOA也是一个逐步演进的过程,所以本篇也讲讲这个AOP的思想演进过程.
插播面试题
你提到了dubbo中spi也增加了AOP,那你讲讲这用到了什么设计模式,dubbo又是如何做的.
直入主题
假如我们就以AOP最常用的场景事务来说,我们最初的做法是怎么样的?
简单做法
public class EmployeeServiceImpl implements IEmployeeService { private TransactionManager txManager; @Override
public void save() {
try {
txManager.begin();
System.out.println("保存操作");
txManager.commit();
}catch (Exception e){
txManager.rollback();
e.printStackTrace();
}
} @Override
public void update() {
try {
txManager.begin();
System.out.println("更新操作");
txManager.commit();
}catch (Exception e){
txManager.rollback();
e.printStackTrace();
}
}
}
这些代码存在的问题就很明显了,比如
- 处理事务的代码大量重复
- 根据责任分离思想,在业务方法中,只需要处理业务功能,不该处理事务.
优化代码我们第一个想到的是设计模式,那么我们进入如下的优化
装饰设计模式
public class APP { @Test
public void testSave() throws Exception {
IEmployeeService service = new EmployeeServiceImplWapper(new TransactionManager(),
new EmployeeServiceImpl());
service.save();
} @Test
public void testUpdate() throws Exception {
IEmployeeService service = new EmployeeServiceImplWapper(new TransactionManager(),
new EmployeeServiceImpl());
service.update();
}
}
通过装饰设计模式,我们解决了上面遇到的两个问题,但是同时也引出了新的问题,在客户端我们暴露了真实的对象EmployeeServiceImpl,这样就很不安全,那么我们可不可以把真实对象隐藏起来,让使用者看不到呢?那么我们进一步优化
静态代理
通过这种方式,真实对象对使用者进行了一定的隐藏,但是又引出了新的问题
- 如果需要代理的方法很多,则每一种都要处理.比如图中只处理了save方法,万一有很多方法,则需要处理很多次
- 接口新增了方法后,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法(EmployeeServiceImpl和EmployeeServiceImplProxy都要改动),增加了代码的维护难度
- 代理对象的某个接口只服务于某一种类型的对象,比如EmployeeServiceImplProxy是只给IEmployeeService接口服务的,假如我新增了一个IRoleService,又要搞一个RoleServiceImplProxy,增加了维护难度
鉴于以上问题,我们能否再优化一下呢?答案是可以的
动态代理
动态代理类是在程序运行期间由JVM通过反射等机制动态的生成的,所以不存在代理类的字节码文件.代理对象和真实对象的关系是在程序运行事情才确定的.
动态代理的方式和区别我们前面有讲过,这里就简单演示一下jdk动态代理
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class JDKProxyTest { @Autowired
private TransactionManagerInvocationHandle handle; @Test
public void testSave() throws Exception {
IEmployeeService service = handle.getProxyObject();
service.save();
} @Test
public void testUpdate() throws Exception {
IEmployeeService service = handle.getProxyObject();
service.update();
}
}
public class TransactionManagerInvocationHandle implements InvocationHandler { @Setter
private TransactionManager txManager;
@Setter
private Object target;//真实对象 //生成代理对象
//泛型只是为了调用时不用强转,如果用Object的话调用时需要强转
public <T> T getProxyObject() {
return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(),//类加载器
target.getClass().getInterfaces(),//为哪些接口做代理(拦截什么方法)
this);//为哪个类监听增强操作的方法(把这些方法拦截到哪里处理)
} //如何做增强操作(被拦截的方法在这里增强处理)
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object obj = null; try {
txManager.begin();
//原封不动调用之前的方法
obj = method.invoke(target, args);
txManager.commit();
return obj;
} catch (Exception e) {
e.printStackTrace();
txManager.rollback();
} return obj;
}
}
这样,对于使用者来说,就无需再关心事务的逻辑.当然这个还需要getProxyObject获取动态代理对象是不是还是太麻烦,那如何不调用getProxyObject就无声无息的注入动态代理对象呢?可以观看之前的dubbo源码解析-简单原理、与spring融合
dubbo-spi-aop
看了这么多演进的过程,是不是还是没有看到dubbo源码的影子?因为dubbo在做spi的设计的时候,也是有一个演进和优化的过程的.我们来看看dubbo是怎么做的
//dubbo spi中的aop
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
下面引用文档介绍
ExtensionLoader 在加载扩展点时,如果加载到的扩展点有拷贝构造函数,则判定为扩展点 Wrapper 类。
Wrapper类内容:
package com.alibaba.xxx; import com.alibaba.dubbo.rpc.Protocol; public class XxxProtocolWrapper implemenets Protocol {
Protocol impl; public XxxProtocol(Protocol protocol) { impl = protocol; } // 接口方法做一个操作后,再调用extension的方法
public void refer() {
//... 一些操作
impl.refer();
// ... 一些操作
} // ...
}
通过 Wrapper 类可以把所有扩展点公共逻辑移至 Wrapper 中。新加的 Wrapper 在所有的扩展点上添加了逻辑,有些类似 AOP,即 Wrapper 代理了扩展点。
看到这里可能发现,dubbo里面的spi增加的aop,其实就是装饰者设计模式.但是从上面的演进中我们发现,装饰者设计模式还是有很多弊端的,后面是逐步演进,最后到达动态代理.那dubbo又是如何处理这个弊端逐步演进的?
dubbo里面有个概念叫扩展点自适应,也就是给接口注入拓展点是一个Adaptive实例,直到方法执行时,才决定调用的是哪一个拓展点的实现.这个在下一篇的Adaptive会详细介绍,本篇其实也是下一篇的启蒙篇.
敲黑板划重点-小技巧
既然本篇提到了spring的aop,那么这里插播一个小技巧,Spring的AOP
增强方式一共有5种,分别为
增强类型 | 应用场景 |
---|---|
前置增强 | 权限控制、记录调用日志 |
后置增强 | 统计分析结果数据 |
异常增强 | 通过日志记录方法异常信息 |
最终增强 | 释放资源 |
环绕增强 | 缓存、性能、权限、事务管理 |
面试的时候也会问到5种增强方式,但是很多同学都是说,我每天都在加班,哪有时间记这些.但是其实如果你理解他的设计思想,那么就可以"理解性记忆",以后想忘都忘不掉.
//环绕
try {
//前置
System.out.println("=====");
//后置
}catch (Exception e){
//异常
}finally {
//最终
}
其实他这5种方式就是根据try-catch-finally的模型来设计的,只要你记住了这个设计的思想,自然不会忘记这5种方式,这也是我之前反复强调的,理解透原理和设计思想,很多东西都是一通百通的.
Ref:
https://www.jianshu.com/p/dba4447e5dc5
dubbo源码解析-spi(4)的更多相关文章
- dubbo源码解析-spi(3)
前言 在上一篇的末尾,我们提到了dubbo的spi中增加了IoC和AOP的功能.那么本篇就讲一下这个增加的IoC,spi部分预计会有四篇,因为这东西实在是太重要了.温故而知新,我们先来回顾一下,我们之 ...
- dubbo源码解析-spi(一)
前言 虽然标题是dubbo源码解析,但是本篇并不会出现dubbo的源码,本篇和之前的dubbo源码解析-简单原理.与spring融合一样,为dubbo源码解析专题的知识预热篇. 插播面试题 你是否了解 ...
- dubbo源码解析-spi(二)
前言 上一篇简单的介绍了spi的基本一些概念,在末尾也提到了,dubbo对jdk的spi进行了一些改进,具体改进了什么,来看看文档的描述 JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩 ...
- Dubbo源码(二) - SPI源码
前情提要 假设你已经知道Dubbo SPI的使用方式,不知道的请出门左转: Dubbo源码(一) - SPI使用 Dubbo源码地址: apache/dubbo 本文使用版本:2.6.x 测试Demo ...
- dubbo源码解析五 --- 集群容错架构设计与原理分析
欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 博客园 Dubbo 入门之二 --- 项目结构解析 博客园 Dubbo 源码分析系列之 ...
- Dubbo 源码解析四 —— 负载均衡LoadBalance
欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 Dubbo 入门之二 --- 项目结构解析 Dubbo 源码分析系列之三 -- 架构原 ...
- dubbo源码解析-zookeeper创建节点
前言 在之前dubbo源码解析-本地暴露中的前言部分提到了两道高频的面试题,其中一道dubbo中zookeeper做注册中心,如果注册中心集群都挂掉,那发布者和订阅者还能通信吗?在上周的dubbo源码 ...
- Dubbo源码解析之SPI(一):扩展类的加载过程
Dubbo是一款开源的.高性能且轻量级的Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用.智能容错和负载均衡,以及服务自动注册和发现. Dubbo最早是阿里公司内部的RPC框架,于 ...
- 【Dubbo 源码解析】02_Dubbo SPI
Dubbo SPI:(version:2.6.*) Dubbo 微内核 + 插件 模式,得益于 Dubbo SPI .其中 ExtentionLoader是 Dubbo SPI 最核心的类,它负责扩展 ...
随机推荐
- ref:linux用户和组管理,/etc/passwd,/etc/shadow和/etc/group 文件内容解释
ref:https://www.cnblogs.com/xuha0/p/5519232.html 与用户相关的系统配置文件主要有/etc/passwd 和/etc/shadow,其中/etc/shad ...
- shiro实现账号同一时间只能在一处登录(非单点登录)
<bean id="myRealm" class="com.sys.shiro.MyRealm" /> <bean id="sess ...
- poj-2421-最小生成树刷题
title: poj-2421-最小生成树刷题 date: 2018-11-20 20:30:29 tags: acm 刷题 categories: ACM-最小生成树 概述 做了几道最小生成树的题, ...
- i春秋CTF web题(1)
之前边看writeup,边做实验吧的web题,多多少少有些收获.但是知识点都已记不清.所以这次借助i春秋这个平台边做题,就当记笔记一样写写writeup(其实都大部分还是借鉴其他人的writeup). ...
- VMware vsphere Hypervisor、VMware vsphere和VMware Workstation小记
VMware Workstation软件需要依赖于宿主操作系统之上. VMware vSphere是VMware公司推出一套服务器虚拟化解决方案,它是可以直接独立安装和运行在祼机上的系统. VMwar ...
- Javascript:10天设计一门语言
演进和使用的JavaScript是早在1995年开发的一种语言,真的是刚刚起步. 网景公司在1995年四月聘请Brendan Eich ,他被告知,他有10天时间创造并制作了一种将在Netscape的 ...
- app分组
将项目中中的urls.py复制到app当中 清空项目名称文件夹下的urls.py文件中的内容,并写入一下内容 from django.conf.urls import url,include urlp ...
- Xtreme9.0 - Car Spark 动态规划
Car Spark 题目连接: https://www.hackerrank.com/contests/ieeextreme-challenges/challenges/car-spark Descr ...
- 2010-2011 ACM-ICPC, NEERC, Moscow Subregional Contest Problem D. Distance 迪杰斯特拉
Problem D. Distance 题目连接: http://codeforces.com/gym/100714 Description In a large city a cellular ne ...
- Ubuntu Java7 SDK环境变量配置(转)
1.去甲骨文官网下载java7 sdk http://www.oracle.com/technetwork/java/javase/downloads/index.html 这里笔者下载了最新的jav ...