代理模式

通过代理来访问真实的对象,而不是直接去访问真正干活的对象,比如二房东租房,二房是代理者,而一房东才是真正的房东;或者说生活中的中介。Spring中的AOP就是动态代理

适用场景

  • 需要动态修改方法参数
  • 方法执行日志功能,比如AOP实现方法拦截记录日志
  • 安全检查,比如方法执行时的权限校验

角色说明

  • 抽象角色:声明代理对象和真实的对象的共同接口(接口或抽象类)
  • 代理角色:代理角色内部包含对真实对象的引用,从而可以操作真实的对象,同时代理对象与真实对象拥有同样的接口以便在任何时候都能够替代真实对象。并且代理对象可以对真实对象附加操作,相当于对真实对象的封装
  • 真实角色:代理角色所代表的真实对象,我们最终要引用的对象(真正干活的对象)

代理方式

目前实现代理的方式共有三种,分别是JDK静态代理JDK动态代理Cglib动态代理,每一种都有各自的使用场景与其优缺点

如何选择合适的代理方法?

我们来看一张表格,会让你一目了然

静态代理 JDK动态代理 Cglib动态代理
是否支持动态代理
是否提供子类代理
提供接口代理(目标类必须实现接口)
性能 三者最高 JDK1.8中要高于Cglib JDK1.8之前要高于JDK动态代理

可以依据目前i项目情况进行对号入座,很容易确定出该用哪一种代理方式

JDK静态代理

其实就是一个对象中调用另一个对象实现简单的代理功能,没有反射也没有字节码修改,我们平时无形中其实就用了这种代理方式

优点

  • 代理类使客户端不需要知道具体的实现是什么,客户端只需要知道代理类(客户端和实现解耦),符合开闭原则
  • 静态代理比动态代理性能高

缺点

  • 一个静态代理类只能为一个接口服务(如果我们需要一个代理类动态为多个接口服务,则就是动态代理了)
  • 每个代理类都需要和目标类实现同样的接口,一旦接口增加,代理类也需要修改
  • 代理类每个接口都包含着一个真实对象的引用,如果真实对象很多,则静态代理类就会很臃肿,难以胜任

代码示例

类的一个抽象,代理类和实现类都需要实现同样的接口

public abstract class Subject {public abstract void visit();
}

代理类,可以看到就只有代理了visit接口,并写死了代理的方法 visit()

public class ProxySubject extends Subject {private RealSubject realSubject = null;/*** 除了代理真实⻆⾊做该做的事情,代理⻆⾊也可以提供附加操作,如:before()和postRequest()*/@Overridepublic void visit() {before(); //真实⻆⾊操作前的附加操作if (realSubject == null) {realSubject = new RealSubject();}// 真正干活的对象realSubject.visit();after(); //真实⻆⾊操作后的附加操作}private void before() {System.out.println("do something before...");}private void after() {System.out.println("do something after...");}
}

真正的实现类,代理类中持有这个类的引用

public class RealSubject extends Subject {@Overridepublic void visit() {System.out.println("visit");}
}

测试中实例化代理类并调用代理类中的方法,然后代理类再调用实现类中的方法

    public static void main(String[] args) {Subject subject = new ProxySubject();// 调用代理者(实际上是RealSubject在工作)subject.visit();}

运行结果

do something before...
visit
do something after...

JDK动态代理

利用拦截器(必须实现InvocationHandler)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理

创建JDK动态代理步骤

  1. 编写⼀个委托类的接⼝,即静态代理的(Subject接⼝)
  2. 实现⼀个真正的委托类,即静态代理的(RealSubject类)
  3. 创建⼀个动态代理类,实现InvocationHandler接⼝,并重写该invoke⽅法
  4. 在客户端中,⽣成动态代理的对象。

优点

  • 在jdk1.8中性能要比cglib高

缺点

  • 目标类必须实现接口,只能代理实现了接口的类,而不能实现接口的类就不能实现JDK动态代理

代码示例

实现的抽象类,这也是JDK动态代理的缺点,所有实现都需要实现接口

public interface Subject {public void visit();
}

代理处理类,可以看到实现了InvocationHandler(这是必须实现),invoke方法中,有一个Method参数,可以根据不通的method的不同代理不同的接口

public class ProxyHandler implements InvocationHandler {/*** 代理的对象*/private Object proxyObject;public ProxyHandler(Object target) {this.proxyObject = target;}/*** 实现invoke方法,实现代理** @param proxy  要代理的对象* @param method 要代理的方法* @param args   真实对象方法里的入参* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("do something before...");method.invoke(proxyObject, args);System.out.println("do something after...");return null;}public Object getProxyObject() {return proxyObject;}public void setProxyObject(Object proxyObject) {this.proxyObject = proxyObject;}
}

最终的实现类

public class RealSubject implements Subject {@Overridepublic void visit() {System.out.println("visit()");}
}

客户端,代码关键在于Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler)⽅法,该方法会根据指定的参数动态创建代理对象。三个参数的意义如下:

  1. loader:指定代理对象的类加载器
  2. interfaces:代理对象需要实现的接口,可以同时指定多个接口
  3. handler:【重要】方法调用的实际处理者,代理对象的方法都会转发到这里
    public static void main(String[] args) {// 代理的对象,可以动态切换代理RealSubject userService = new RealSubject();// 代理的具体实现ProxyHandler proxyHandler = new ProxyHandler(userService);ClassLoader classLoader = proxyHandler.getClass().getClassLoader();// note 根据指定参数动态创建代理对象Subject proxyObject = (Subject) Proxy.newProxyInstance(classLoader,userService.getClass().getInterfaces(), proxyHandler);proxyObject.visit();}

执行结果

do something before...
visit()
do something after...

源码分析

JDK动态代理实现原理详解(源码分析)

Cglib动态代理

Cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

创建代理对象的步骤

  1. 生成代理类的二进制字节码文件
  2. 加载二进制字节码,生成Class对象(例如使用Class.forName()方法)
  3. 通过反射机制获得代理类实例构造,并创建代理对象

优点

  • 可以针对类进行代理,而不需要实现接口
  • 可以在运行时动态创建字节码文件并加载

缺点

  • 在JDK1.8中,性能比不上JDK动态代理

代码示例

执行代码之前,需要引入一个cglib的包,这里使用maven的方式

        <dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version></dependency>

然后直接写一个需要被代理的类

public class RealSubject {public void visit() {System.out.println("visit...");}
}

然后通过实现接口net.sf.cglib.proxy.MethodInterceptor进行代理处理

public class CglibProxyHandler implements MethodInterceptor {/*** 代理的对象*/private Object target;public Object getInstance(Object target) {this.target = target;Enhancer enHancer = new Enhancer();enHancer.setSuperclass(this.target.getClass());// 回调方法enHancer.setCallback(this);// 创建代理对象return enHancer.create();}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("############ 我是CGLIB动态代理 ##############");// 反射方法调用前System.out.println("我准备调用visit");Object returnObje = proxy.invokeSuper(obj, args);// 反射方法调用之后System.out.println("我调用过visit了");return returnObje;}
}

客户端测试类,直接传入RealSubject对象,然后就实现了代理,是不是很方便

    public static void main(String[] args) {CglibProxyHandler cglib = new CglibProxyHandler();RealSubject subject = (RealSubject) cglib.getInstance(new RealSubject());subject.visit();}

运行结果

############ 我是CGLIB动态代理 ##############
我准备调用visit
visit...
我调用过visit了

总结

Spring的AOP动态代理也是使用JDK动态代理+Cglib动态代理实现,只不过会依据不同情况动态选择代理方式,我们在选择的时候也可以参照AOP的逻辑进行选择,有如下几种情况:

  1. 如果目标对象实现了接口,默认情况下使用JDK的动态代理
  2. 如果目标对象实现了接口,可以强制使用Cglib实现AOP
  3. 如果目标对象没有实现接口,则强制使用Cglib库

一文理解JDK静态代理、JDK动态代理、Cglib动态代理相关推荐

  1. 代理详解 静态代理+JDK/CGLIB 动态代理实战

    1. 代理模式 代理模式是一种比较好理解的设计模式.简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对 ...

  2. cglib动态代理jar包_代理模式详解:静态代理+JDK/CGLIB 动态代理实战

    1. 代理模式 代理模式是一种比较好的理解的设计模式.简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标 ...

  3. Java 结合实例学会使用 静态代理、JDK动态代理、CGLIB动态代理

    前言 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 代理 很多人至今都是看到 代理就懵, 静态代理.动态代理.JDK动态代理.CGL ...

  4. Java设计模式(五)代理设计模式—静态代理—JDK动态代理—Cglib动态代理

    文章目录 什么是代理模式 代理模式应用场景 代理的分类 静态代理 什么是静态代理 深入解析静态代理 小结 动态代理 什么是动态代理 JDK动态代理 原理和实现方式 代码实现 优缺点 Cglib动态代理 ...

  5. Java之代理(jdk静态代理,jdk动态代理,cglib动态代理,aop,aspectj)

    Java之代理... 1 一.         概念... 1 二.         jdk的静态代理... 1 三.         jdk动态代理... 4 四.         cglib 动态 ...

  6. 代理模式(静态代理、jdk动态代理、CGLib动态代理)

    目录 1.什么是代理模式? 2.静态代理 1.案例 2.优化案例 3.静态代理瓶颈 3.动态代理 1.什么是动态代理? 2.jdk动态代理 1.动态代理的工具类 匿名内部类简介 2.jdk动态代理实现 ...

  7. Java两种动态代理JDK动态代理和CGLIB动态代理

    目录 代理模式 JDK动态代理 cglib动态代理 测试 代理模式 代理模式是23种设计模式的一种,他是指一个对象A通过持有另一个对象B,可以具有B同样的行为的模式.为了对外开放协议,B往往实现了一个 ...

  8. JDK和cglib动态代理原理详解

    AOP的基础是Java动态代理,了解和使用两种动态代理能让我们更好地理解 AOP,在讲解AOP之前,让我们先来看看Java动态代理的使用方式以及底层实现原理. 转自https://www.jiansh ...

  9. 你必须会的 JDK 动态代理和 CGLIB 动态代理

    来自:ytao 我们在阅读一些 Java 框架的源码时,基本上常会看到使用动态代理机制,它可以无感的对既有代码进行方法的增强,使得代码拥有更好的拓展性.通过从静态代理.JDK 动态代理.CGLIB 动 ...

  10. 浅谈Spring中JDK动态代理与CGLIB动态代理

    前言 Spring是Java程序员基本不可能绕开的一个框架,它的核心思想是IOC(控制反转)和AOP(面向切面编程).在Spring中这两个核心思想都是基于设计模式实现的,IOC思想的实现基于工厂模式 ...

最新文章

  1. Alluxio 1.5集群搭建
  2. python多态的例子_Python编程之多态用法实例详解
  3. 计算机开始按钮作用,Win8.1的12个变化:开始按钮回归功能不再
  4. weblogic常见漏洞
  5. How Tomcat works — 一、怎样阅读源码
  6. 将游戏成绩传到排名页面html,用野狗开发实时游戏排行榜
  7. 操作多台_一支热电偶能否连接多台显示仪表
  8. 热门开源后端软件Parse Server中存在严重的 RCE ,CVSS评分10分
  9. 20145122 《Java程序设计》第5周学习总结
  10. (16)数据结构-并查集
  11. Linux c 多线程写日志,linux c/c++多线程程序的编写(转)
  12. 计算机网络属于什么结构,计算机网络体系结构是一种什么结构
  13. Renascence使用方法
  14. gopro lrv文件和thm文件
  15. 深入浅出Spring Cloud整合dubbo
  16. Python IDLE的下载,安装和使用
  17. 经历 成长——致逝去的时光
  18. nyoj 239 月老的难题 【二分匹配之匈牙利】
  19. java定时器每月月末自动执行
  20. 关于mysql的行转列问题

热门文章

  1. python 变成float32_python – Numpy将float32转换为float64
  2. 超详细CookieSession的原理与用法
  3. python时间序列滞后命令,时间序列-相关性和滞后时间
  4. 最大独立匹配_新车|升级柴油国六动力,配后排独立座椅,瑞风M5新车型上市...
  5. t4 tornado 模板
  6. IDEA或Webstorm设置Terminal终端字体大小
  7. Hadoop +x86平台:大数据分析的好拍档
  8. [javaSE] 网络编程(浏览器客户端-自定义服务端)
  9. Microsoft Visual Studio 2008从试用版转为正式版
  10. 从零开始学MVC3——创建项目