通俗易懂详解Java代理及代码实战
一、概述
代理模式是Java常用的设计模式之一,实现代理模式要求代理类和委托类(被代理的类)具有相同的方法(提供相同的服务),代理类对象自身并不实现真正的核心逻辑,而是通过调用委托类对象的相关方法来处理核心逻辑,而代理类对象主要负责为委托类对象过滤消息、预处理消息、转发消息给委托类、事后处理消息等等。通常代理类会与委托类存在关联关系。
二、静态代理
public interface SaleCar {void sale(); }
2.hafiz真正卖车子实现类
public class HafizSaleCar implements SaleCar {@Overridepublic void sale() {System.out.println("hafiz sale his car...");} }
3.二手车交易中介类
public class CarTradeProxy implements SaleCar {private HafizSaleCar owner;public CarTradeProxy(HafizSaleCar owner) {this.owner = owner;}@Overridepublic void sale() {System.out.println("proxy add price...");owner.sale();} }
4.测试类
public class Client {public static void main(String[] args) {HafizSaleCar owner = new HafizSaleCar();CarTradeProxy proxy = new CarTradeProxy(owner);proxy.sale();} }
5.测试结果
从上面的代码中,我们可以看出,其实代理类(CarTradeProxy)和委托类(HafizSaleCar)好像区别并不大,我们直接创建一个HafizSaleCar对象,然后调用它的sale()方法不就好了?细心的同学你会发现,其实代理在真正调用委托类的方法之前做了中介加价的操作,这也就意味着我们使用代理模式实现在委托类的基础上增加额外的逻辑操作。
以上就是一个很简单的静态代理的实现过程。但是这个时候我又有了一个新需求,我想用我手里的存款以及买车子赚的钱来给自己买一套新房子,那我又不想东奔西跑找房源,于是我又把买房这件事委托给了房产中介,下面我们就来实现这个逻辑。
1.再定义一个买房的接口
public interface BuyHouse {void buy(); }
2.重写委托类,实现卖车和买房两个接口
public class HafizTrade implements SaleCar, BuyHouse {@Overridepublic void buy() {System.out.println("hafiz buy house...");}@Overridepublic void sale() {System.out.println("hafiz sale car...");} }
可以看到,我现在既要卖掉我的车子,又要购买新的房子。
3.再创建一个买房子的中介代理类
public class HouseTradeProxy implements BuyHouse {private HafizTrade customer;public HouseTradeProxy(HafizTrade customer) {this.customer = customer;}@Overridepublic void buy() {System.out.println("proxy add price...");customer.buy();} }
4.卖车子的代理类修改如下
public class CarTradeProxy implements SaleCar {private HafizTrade owner;public CarTradeProxy(HafizTrade owner) {this.owner = owner;}@Overridepublic void sale() {System.out.println("proxy add price...");owner.sale();} }
5.新的测试类
public class Client {public static void main(String[] args) {HafizTrade trader = new HafizTrade();CarTradeProxy carTradeProxy = new CarTradeProxy(trader);carTradeProxy.sale();System.out.println("-----------------------------------------------");HouseTradeProxy houseTradeProxy = new HouseTradeProxy(trader);houseTradeProxy.buy();System.out.println("-----------------------------------------------");} }
6.测试结果
这样通过静态代理的方式,我们的确也可以很完美的解决我们的问题,但当我们有越来越多的委托类需要代理,而且代理做的工作又一样,那是不是会多出来很多的代理类,我们开发者会疯掉的,这时候我们就想:如果我们可以只做一次,就能代理一类委托类该多好啊?那么这个时候,动态代理就应运而生了,它可以使得我们只定义一次就能为一类委托类做代理。
三、动态代理
静态代理要求我们在程序发布上线运行之前,就要开发好对应委托类的代理类,而动态代理是我们在程序发布之前,并没有创建好对应的代理类,而是在运行的时候动态的创建代理类。
动态代理实现方式有两种:jdk自带动态代理实现以及cglib实现。jdk代理只适合代理实现接口的目标对象,cglib可以代理没有实现接口的目标对象。
四、基于JDK实现动态代理
1.实现步骤
1).通过实现 InvocationHandler 接口创建自己的调用处理器
2).通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类
3).通过反射机制获得动态代理类的构造函数(jdk自带,不需手动处理)
4).通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入(jdk自带,不需手动处理)
2.创建代理处理器
public class ProxyHandler implements InvocationHandler {private Object target;public ProxyHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("proxy add price...");Object result = method.invoke(target, args);return result;} }
3.测试类
public class Client {public static void main(String[] args) {HafizTrade trader = new HafizTrade();ProxyHandler handler = new ProxyHandler(trader);Class<? extends HafizTrade> clazz = trader.getClass();ClassLoader classLoader = clazz.getClassLoader();Class<?>[] interfaces = clazz.getInterfaces();SaleCar carProxy = (SaleCar)Proxy.newProxyInstance(classLoader, interfaces, handler);carProxy.sale();System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++");BuyHouse houseProxy = (BuyHouse)Proxy.newProxyInstance(classLoader, interfaces, handler);houseProxy.buy();System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++");} }
4.测试结果
5.原理
生成一个代理类,这个代理类继承Proxy类并且实现了我们定义的接口,代理对象调用方法的时候,调用这个代理对象的一个成员InvocationHandler(上面我们传入了一个InvocationHandler实现对象)的方法,也就是我们包装了委托类后的方法。
五、基于cglib实现动态代理
1.实现步骤
1).通过实现CGLib包提供的MethodInterceptor接口,重写intercept方法,创建自己的方法拦截器
2).通过CGLib中的Enhancer的creat方法创建动态代理对象
2.添加cglib的maven依赖
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>2.2.2</version> </dependency>
3.自定义ProxyInterceptor
public class ProxyInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("Trade proxy add price...");Object result = methodProxy.invokeSuper(o, objects);return result;} }
4.测试client
public class Client {public static void main(String[] args) {ProxyInterceptor proxy = new ProxyInterceptor();HafizTrade tradeProxy = (HafizTrade)Enhancer.create(HafizTrade.class, proxy);tradeProxy.sale();System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++");tradeProxy.buy();} }
5.测试结果
6.原理
首先通过asm字节码生成框架生成代理类Class的二进制字节码,然后通过Class.forName加载二进制字节码,生成Class对象,最后通过反射机制获取实例构造,并初始化代理类对象。
六、总结
动态代理可以使得我们一次可以解决一批需要创建代理的问题,使得代码更加灵活,提高了程序的扩展性。动态代理在主流java框架中也非常常用,比如最著名的spring,它在AOP的功能就是使用动态代理实现,还有Dubbo等这样的RPC服务框架,在客户端都是通过代理完成服务的真正调用。了解和学会代理以及实现方式能帮助我们更好地理解主流框架。
关于动态代理的实现细节,可以参考:http://www.360doc.com/content/14/0801/14/1073512_398598312.shtml#
通俗易懂详解Java代理及代码实战相关推荐
- 详解 Java 中的三种代理模式
代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能. 这里使用 ...
- java斐波那契查找_详解Java Fibonacci Search斐波那契搜索算法代码实现
一, 斐波那契搜索算法简述 斐波那契搜索(Fibonacci search) ,又称斐波那契查找,是区间中单峰函数的搜索技术. 斐波那契搜索采用分而治之的方法,其中我们按照斐波那契数列对元素进行不均等 ...
- java学习 类变量 类方法_这篇文章主要介绍了JAVA类变量及类方法代码实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下类变量(...
这篇文章主要介绍了JAVA类变量及类方法代码实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 类变量(static) 类变量是该类的所有对象共 ...
- java 代码块_详解java中的四种代码块
在java中用{}括起来的称为代码块,代码块可分为以下四种: 一.简介 1.普通代码块: 类中方法的方法体 2.构造代码块: 构造块会在创建对象时被调用,每次创建时都会被调用,优先于类构造函数执行. ...
- java 引用传递_详解java的值传递、地址传递、引用传递
详解java的值传递.地址传递.引用传递 一直来觉得对值传递和地址传递了解的很清楚,刚才在开源中国上看到一篇帖子介绍了java中的值传递和地址传递,看完后感受颇深.下边总结下以便更容易理解. 按照以前 ...
- 异常处理器详解 Java多线程异常处理机制 多线程中篇(四)
在Thread中有异常处理器相关的方法 在ThreadGroup中也有相关的异常处理方法 示例 未检查异常 对于未检查异常,将会直接宕掉,主线程则继续运行,程序会继续运行 在主线程中能不能捕获呢? 我 ...
- 详解Java解析XML的四种方法
http://developer.51cto.com 2009-03-31 13:12 cnlw1985 javaeye 我要评论(8) XML现在已经成为一种通用的数据交换格式,平台的无关性 ...
- java使用集合存储过程_详解java调用存储过程并封装成map
详解java调用存储过程并封装成map 发布于 2020-5-1| 复制链接 摘记: 详解java调用存储过程并封装成map 本文代码中注释写的比较清楚不在单独说明,希望能帮助到大 ...
- java 死锁 内存消耗_详解Java中synchronized关键字的死锁和内存占用问题
先看一段synchronized 的详解: synchronized 是 java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并 ...
最新文章
- 号外:Mapinfo被Pitney Bowes公司收购
- UA OPTI544 量子光学7 2-level system approximation的Density Matrix模型
- ibm liberty_使用Eclipse和Open Liberty的Java EE 8上的Java 9
- 第四十期:九个对Web开发者最有用的Python包,掌握这些,工资至少能涨涨
- 爱情才是程序员的第一生产力
- webpack3.0 压缩css 但是不在html中引用,webpack怎样压缩css?
- java esc的_如何用Java中的Receipt打印机和ESC / POS命令提高速度
- Spring的4种事务管理(1种编程式事务+三种声明事务)
- 把想法变成现实-兄弟连IT教育
- 生成对抗网络(十)----------infoGAN
- CMMI有几个过程域?
- 王笑京:国家新一代智能交通框架与实施进展
- 11个最佳Ionic应用程序模板
- JVM的垃圾回收Serial、Serial Old、Parallel Scavenge、Parallel Old的介绍和STW(Stop The World)
- 生信技能树linux虚拟机,科学网—Windows10安装Linux子系统Ubuntu 20.04LTS,轻松使用生信软件,效率秒杀虚拟机 - 刘永鑫的博文...
- IOS开发之 ---- 苹果系统代码汉字转拼音
- CSS 行高 line-height属性
- 最强 Python 数据可视化库,没有之一!
- hdu 1983 Kaitou Kid - The Phantom Thief (2)【Bfs+暴力枚举】
- windows 消息处理