代理

代理就像个中介,最外层操作代理对象,代理对象再调用委托对象

当需要在调用前后做一些处理,但是这些处理与业务逻辑无关的时候,如果把无关代码写在业务逻辑里面,代码就会变得很乱,这时候用代理就再好不过了。

就像spring的aop编程,也是用了代理,在调用前后做一些校验、日志记录等无关业务流程的事

因为要通过代理对象去调用委托对象,所以代理对象需要持有委托对象的引用,而且代理类中需要实现委托对象的各种方法

代理有两种一种是静态代理、一种是动态代理

静态代理是由自己编写代理类,但是代理类都相差无几,而且要每一个类都编写一个代理类的话,就会有太多的类了

动态代理是由反射技术,自动生成代理类,运行期才生成class文件

动态代理有两种实现方法,一种是java.lang.reflect、一种是cglib

jdk自带的实现方法,委托类只能实现接口,不能继承类,所有具有一定的局限性

cglib,委托类既可以实现接口也可以继承类

下面通过一个例子来说明代码

一个Book接口,接口有read方法,有一个EBook类实现Book接口

//Book接口 public interface Book { public void read(); }   //委托类 class EBook implements Book { @Override public void read() { System.out.println("读电子书"); } }

静态代理

比原本的代码多了一个BookProxy

//代理类 public class BookProxy implements Book{ //持有Book委托实例 private Book book; //绑定Book委托实例并返回代理对象 public Book bind(Book book){ this.book=book; return this; } //委托book调用read public void read(){ try{ //前置代码 book.read(); //后置代码 }catch(Exception e){ //异常代码 }finally{ //finall代码 } } }

可以看到,代理的本质就是,代理类持有委托对象,通过代理对象去调用委托对象,在调用的时候就可以添加一些额外代码

jdk实现动态代理

这里的BookProxy,是使用反射,在运行期自动生成的

重要的是InvocationHandler,调用反射对象的时候,实际上是调用了InvocationHandler.invoke()

所以需要实现InvocationHandler接口,让实现类持有委托类引用,并且重写invoke方法

//代理类 public class BookInvocationHandler implements InvocationHandler { //委托类 private Object target;   //绑定委托类 并 返回一个代理对象 public Object bind(Object target){ this.target=target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } //调用委托对象 //proxy是代理对象,method是要调用的方法,arg是方法的参数 @Override public Object invoke(Object proxy, Method method, Object[] arg) throws Throwable { Object result = null; try{ //前置代码 result=method.invoke(proxy,arg); //后置代码 }catch(Exception e){ //异常代码 }finally{ //finally代码 } return result; } }

这里需要注意两个地方

  • Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)通过newProxyInstance拿到代理对象,主要参数,loader:委托类的类加载器,interfaces实现的接口,h调用处理程序
  • InvocationHandler.invoke(Object proxy, Method method, Object[] arg) 这里的参数proxy是代理对象!所以调用委托对象的时候不能是method.invoke(proxy,arg),不然会循环调用invoke的,要invoke绑定的委托类对象

jdk不能代理继承的类,要代理继承的类,要用cglib去实现

cglib实现动态代理

这里和jdk实现方法差不多,就是InvocationHandler换成了MethodInterceptor

proxy还是用反射在运行期生成,只是他用Enhancer.create()

public class BookInterceptor implements MethodInterceptor {   private Object target; public Object bind(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); //设置父类 enhancer.setSuperclass(this.target.getClass()); // 回调方法 enhancer.setCallback(this); // 创建代理对象 return enhancer.create(); }   //obj委托对象 mehtod要拦截的方法 args参数 proxy也是要拦截的方法(更快) @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { method.invoke(target, args); return null; }   }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 从源代码到Runtime发生的重排序编译器重排序指令重排序内存系统重排序阻止重排序

     源代码和Runtime时执行的代码很可能不一样,这是因为编译器、处理器常常会为了追求性能对改变执行顺序。然而改变顺序执行很危险,很有可能使得运行结果和预想的不...

    用户1174983
  • apache反向代理一、泛解析域名二、APACHE配置

    正向代理是客户端发送请求给代理服务器,代理服务器将请求发给实际处理的服务器 反向代理是客户端发送请求给服务器(实际上是个代理服务器),服务器将请求发给实际处理的...

    用户1174983
  • java.io.StreamCorruptedException: invalid type code: AC错误的解决方法

    问题描述: 在向一个文件写入可序列化对象时,每次只想向文件的末尾添加一个可序列化的对象,于是使用了FileOutputStream(文件名,true)间接的构建...

    用户1174983
  • 代理模式之jdk动态代理

    有一个方法是invoke (object proxy , Method method object [ ] args );

    用户2141593
  • 倒置依赖原则(DIP)

    原则 A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。 B.抽象不应该依赖于具体实现,具体实现应该依赖于抽象 概念 依赖倒置原则(Dep...

    张俊怡
  • [C#6] 6-表达式形式的成员函数

    0. 目录 C#6 新增特性目录 1. 老版本的代码 1 internal class Person 2 { 3 public string Fi...

    blackheart
  • 那些有趣的代码(二)--偏不听父母话的 Tomcat 类加载器

    看 Tomcat 的源码越看越有趣。Tomcat 的代码总有一种处处都有那么一点调皮的感觉。今天就聊一聊 Tomcat 的类加载机制。

    用户2060079
  • MyBatis拦截器原理探究

    MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,但其实这是拦截器功能。那么拦截器拦截MyBatis中的哪些内容呢?

    Rookie
  • 2016年SDN迅猛发展

    预计在2016年,SDN的部署将呈现飙升的趋势,服务提供商和企业将会利用硬件和软件来提高网络的灵活性。 ? 根据IHS最新的调查报告显示,云服务提供商和通信服务...

    SDNLAB
  • SDN技术概述

    1.SDN架构定义        软件定义网络(Software Defined Networking,SDN)是一种数据平面与控制分离、软件可编程的新...

    JNJYan

扫码关注云+社区

领取腾讯云代金券