代理

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

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

就像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 条评论
登录 后参与评论

相关文章

来自专栏极乐技术社区

使用ES6新特性开发微信小程序(2)

Template Literals(模板对象) ES6中的模板字符串(Template String)是一种能在字符串文本中内嵌表达式的字符串字面量(Strin...

34060
来自专栏Java架构沉思录

Java的装箱和拆箱,你掌握到了第几层?

自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来一些看一下装箱和拆箱中的若干问题。本文先讲述装箱和拆箱最基本的东西,再来看一下面试笔试中经常遇到...

14320
来自专栏chenjx85的技术专栏

leetcode-868-Binary Gap

Given a positive integer N, find and return the longest distance between two con...

12510
来自专栏令仔很忙

新手学JAVA(四)----装箱与拆箱

                                                                                ...

11720
来自专栏逆向技术

C++反汇编第四讲,反汇编中识别继承关系,父类,子类,成员对象

              C++反汇编第四讲,反汇编中识别继承关系,父类,子类,成员对象 讲解目录:    1.各类在内存中的表现形式   备注: 主要复...

23790
来自专栏liukaili_666888999

类方法和实例方法

17020
来自专栏黑泽君的专栏

方法的返回值类型为引用数据类型时

方法的返回值类型为引用数据类型: 基本数据类型:(基本类型太简单,我不准备讲解) 引用数据类型: 1.方法的返回值类型为类名时:返回的是该类的对象。 ...

10210
来自专栏后端沉思录

动态代理(一)

代理模式是Java的一种设计模式,开发中可能会有一种场景,某个类的方法需要补充,但是由于不想在原有的类基础上改动,该如何做呢,如下:

11930
来自专栏专注 Java 基础分享

详解Java API之正则表达式

     正则表达式描述的是一种规则,符合这种限定规则的字符串我们认为它某种满足条件的,是我们所需的。在正则表达式中,主要有两种字符,一种描述的是普通的字符,另...

25090
来自专栏黑泽君的专栏

Java中如何通过一个类名来调用另一个类的静态方法?

所以,比如另一个类叫OtherClass,它的静态公有方法是 public static int MethodA() {...}

1.3K40

扫码关注云+社区

领取腾讯云代金券