代理实现可以分为静态代理和动态代理。

静态代理

静态代理模式其实很常见,比如买火车票这件小事:黄牛相当于是火车站的代理,我们可以通过黄牛买票,但只能去火车站进行改签和退票。在代码实现中相当于为一个委托对象realSubject提供一个代理对象proxy,通过proxy可以调用realSubject的部分功能,并添加一些额外的业务处理,同时可以屏蔽realSubject中未开放的接口。

1、RealSubject 是委托类,Proxy 是代理类;
2、Subject 是委托类和代理类的接口;
3、request() 是委托类和代理类的共同方法;

具体代码实现如下:

interface Subject {void request();
}
class RealSubject implements Subject {public void request(){System.out.println("RealSubject");}
}
class Proxy implements Subject {private Subject subject;public Proxy(Subject subject){this.subject = subject;}public void request(){System.out.println("begin");subject.request();System.out.println("end");}
}
public class ProxyTest {public static void main(String args[]) {RealSubject subject = new RealSubject();Proxy p = new Proxy(subject);p.request();}
}

静态代理实现中,一个委托类对应一个代理类,代理类在编译期间就已经确定。

动态代理

动态代理中,代理类并不是在Java代码中实现,而是在运行时期生成,相比静态代理,动态代理可以很方便的对委托类的方法进行统一处理,如添加方法调用次数、添加日志功能等等,动态代理分为jdk动态代理和cglib动态代理,下面通过一个例子看看如何实现jdk动态代理。

1、定义业务逻辑

public interface Service {  //目标方法 public abstract void add();
} 
public class UserServiceImpl implements Service {  public void add() {  System.out.println("This is add service");  }
}

2、利用 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口定义代理类的实现。

class MyInvocatioHandler implements InvocationHandler {private Object target;public MyInvocatioHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("-----before-----");Object result = method.invoke(target, args);System.out.println("-----end-----");return result;}// 生成代理对象public Object getProxy() {ClassLoader loader = Thread.currentThread().getContextClassLoader();Class<?>[] interfaces = target.getClass().getInterfaces();return Proxy.newProxyInstance(loader, interfaces, this);}
}
3、使用动态代理
public class ProxyTest {public static void main(String[] args) {Service service = new UserServiceImpl();MyInvocatioHandler handler = new MyInvocatioHandler(service);Service serviceProxy = (Service)handler.getProxy();serviceProxy.add();}
}
执行结果:
-----before-----
This is add service
-----end-----
代理对象的生成过程由Proxy类的newProxyInstance方法实现,分为3个步骤:1、ProxyGenerator.generateProxyClass方法负责生成代理类的字节码,生成逻辑比较复杂,有兴趣的同学可以继续分析源码sun.misc.ProxyGenerator;
// proxyName:格式如 "com.sun.proxy.$Proxy.1";
// interfaces:代理类需要实现的接口数组;
// accessFlags:代理类的访问标识;
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
2、native方法Proxy.defineClass0负责字节码加载的实现,并返回对应的Class对象。
Class clazz = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
3、利用clazz.newInstance反射机制生成代理类的对象;反编译代理类为了更清楚的理解动态代理,通过以下方式把代理类字节码生成class文件。
byte[] classFile = ProxyGenerator.generateProxyClass("com.sun.proxy.$Proxy.1", service.getClass().getInterfaces());
FileOutputStream out = new FileOutputStream("com.sun.proxy.$Proxy.1.class");
out.write(classFile);
out.flush();
使用 反编译工具 jad jad com.sun.proxy.$Proxy.1 看看代理类如何实现,反编译出来的java代码如下:
public final class $proxy1 extends Proxy implements Service {public $proxy1(InvocationHandler invocationhandler) {super(invocationhandler);}public final boolean equals(Object obj) {try {return ((Boolean)super.h.invoke(this, m1, new Object[] {obj})).booleanValue();}catch(Error _ex) { }catch(Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}public final String toString() {try {return (String)super.h.invoke(this, m2, null);}catch(Error _ex) { }catch(Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}public final void add() {try {super.h.invoke(this, m3, null);return;}catch(Error _ex) { }catch(Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}public final int hashCode() {try {return ((Integer)super.h.invoke(this, m0, null)).intValue();}catch(Error _ex) { }catch(Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}private static Method m1;private static Method m2;private static Method m3;private static Method m0;static {try {m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {Class.forName("java.lang.Object")});m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);m3 = Class.forName("zzzzzz.Service").getMethod("add", new Class[0]);m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);}catch(NoSuchMethodException nosuchmethodexception) {throw new NoSuchMethodError(nosuchmethodexception.getMessage());}catch(ClassNotFoundException classnotfoundexception) {throw new NoClassDefFoundError(classnotfoundexception.getMessage());}}
}
从上述代码可以发现:1、生成的$proxy1继承自Proxy类,并实现了Service接口。2、执行代理对象的方法,其实就是执行InvocationHandle对象的invoke方法,传入的参数分别是当前代理对象,当前执行的方法和参数。
super.h.invoke(this, m3, null);
jdk动态代理使用的局限性通过反射类ProxyInvocationHandler回调接口实现的jdk动态代理,要求委托类必须实现一个接口,但事实上并不是所有类都有接口,对于没有实现接口的类,便无法使用该方方式实现动态代理。文/占小狼(简书作者)原文链接:http://www.jianshu.com/p/a1d094fc6c00

说说Java代理模式相关推荐

  1. java代理模式_Java代理

    java代理模式 本文是我们名为" 高级Java "的学院课程的一部分. 本课程旨在帮助您最有效地使用Java. 它讨论了高级主题,包括对象创建,并发,序列化,反射等. 它将指导您 ...

  2. java代理模式(java代理模式和适配器模式)

    Java设计模式的中介者模式是怎样的? 如果对象之间的关系原本一目了然,中介对象的加入便是"画蛇添足". 来看下中介者模式的组成部分吧. 1) 抽象中介者(Mediator)角色: ...

  3. java代理模式总结

    Java代理模式根据代理类生成时间的不同,可以分为静态代理和动态代理,它如同中介机构,可以为目标类提供代理服务,以控制对对象的访问,目标类的任何方法在执行前都必须经过代理类,这样代理类就可以用来负责请 ...

  4. java代理模式实现

    java代理模式实现 @(代理模式)[静态代理,动态代理,InvocationHandler] java的代理模式 分为两种,静态代理和动态代理,学习下什么是代理和静态动态代理的作用. java代理模 ...

  5. [Java] 代理模式 Proxy Mode

    [Java] 代理模式 Proxy Mode 文章目录 [Java] 代理模式 Proxy Mode 1. 代理思想 2.java.lang.reflect.Proxy类 2.1 利用反射创建prox ...

  6. 浅谈自己对Java代理模式的理解--即为什么要用怎么用

    首先,国际惯例,上Java代理模式的定义:  Java代理模式:对其他对象提供一种代理以控制对这个对象的访问.              定义很简单,就一句话,怎么去理解,不急,先听一个小故事: 故事 ...

  7. 阿里十年资深程序员吐血总结之Java代理模式

    阿里十年资深程序员吐血总结之Java代理模式 文章目录 阿里十年资深程序员吐血总结之Java代理模式 1.接口代理 2.类代理 3.动态代理都是通过反射实现的吗 4.jdk动态代理和cglib动态代理 ...

  8. Java代理模式汇编

    文章目录 Java 代理模式实现方式,主流如下五种方法 Notes 静态代理实现 实现步骤 Cat接口 委托类 Lion 代理类角色(FeederProxy) 静态代理类测试 动态代理类(基于接口实现 ...

  9. Java代理模式/静态代理/动态代理

    代理模式:即Proxy Pattern,常用的设计模式之一.代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问. 代理概念 :为某个对象提供一个代理,以控制对这个对象的访问. 代理类和委 ...

  10. 说说 JAVA 代理模式

    原文出处: 姜肇海 投稿 事例 小张是一个普普通通的码农,每天勤勤恳恳地码代码.某天中午小张刚要去吃饭,一个电话打到了他的手机上."是XX公司的小张吗?我是YY公司的王AA".&q ...

最新文章

  1. 二进制_Kubernetes集群二进制部署
  2. hdu5253最小生成树
  3. linux的线程要makefile,Linux内核线程之父pid=2的kthreadd线程
  4. 当前线程等待某些线程运行结束再执行的几种方案。CountDownLatch机制简单解读以及简单实现
  5. Ubuntu 14.04 安装Visual studio Code
  6. ann matlab,人工神经网络ann及其matlab仿真.ppt
  7. ATS push cache 测试
  8. ORACLE添加字段、删除字段
  9. php多维数组交集,求数组差/交集函数-php数组函数(二)
  10. Java比较器概述即代码讲解实现
  11. Mysql(二)——简单查询及示例
  12. 【华为云实战开发】1.传统Java项目怎么能变得高大上?
  13. WCF中的REST是什么
  14. Chrome OS 初体验
  15. 推荐多款好看的报表图表配色方案(转载)
  16. 博弈论完全信息博弈思维导图
  17. 齐齐哈尔大学计算机考研论坛,2020年一志愿报考齐齐哈尔大学硕士研究生进入复试的考生名单...
  18. javaEE自驾游旅游景点管理系统ssm
  19. android获取通讯录号码,Android跳转到通讯录获取用户名称和手机号码的实现思路...
  20. linux 系统安装aria2以及配置web端

热门文章

  1. 小红书怎么点击查看大图_小红书图片如何调整呢?
  2. 随笔杂记(十)——C++:C4996报错解决方法
  3. 2022年中国科学技术大学细胞生物III复习资料
  4. 自学实前后端践项目2 phone Store 1
  5. 地区数据erea.js
  6. 程序员应该怎么学数学?
  7. 2017初秋最时髦服装搭配,裙子+短靴搭配
  8. (byte)0xaa 0xff
  9. TDChat国内ChatGPT镜像网站最新网站入口地址
  10. linux——进程的概念与状态