常用动态代理主要有两种:Java自带的Proxy动态代理和cglib的动态代理。

Proxy动态代理是基于接口的,只能对实现了接口的类生成代理,而对于普通类的代理cglib能胜任。
例如在Spring中有接口默认JDK代理,无接口使用CGLIB,但可以配置强制全部使用CGLIB代理。
XML

<aop:aspectj-autoproxy proxy-target-class="true"/>

配置文件或注解

#配置文件
spring.aop.proxy-target-class=true
#注解
@EnableAspectJAutoProxy(proxyTargetClass = true

JDK Proxy

使用实例:三个参数:ClassLoader,Interface,InvocationHandler。
method.invoke(实例,参数);

   public class ProxyTest {public static void main(String[] args) throws RuntimeException{Hello hello=new DogHello();Hello o = (Hello)Proxy.newProxyInstance(hello.getClass().getClassLoader(), DogHello.class.getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("start--");method.invoke(hello,args);System.out.println("end--");return null;}});o.say("aa");}
}

其实,对于以上的简写的代码类,编译后会出现两个Class文件,一个普通的ProxyTest.class,另一个名字为ProxyTest$1.class. 如果手动创建类实现InvocationHandler接口则没有。为什么是1呢,因为0被生成的代理类占用了

final class ProxyTest$1 implements InvocationHandler {ProxyTest$1(Hello var1) {this.val$hello = var1;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("start--");method.invoke(this.val$hello, args);System.out.println("end--");return null;}
}

原理讲解

首先我们来看一下基于JDK的动态代理源码:

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{Objects.requireNonNull(h);final Class<?>[] intfs = interfaces.clone();final SecurityManager sm = System.getSecurityManager();if (sm != null) {checkProxyAccess(Reflection.getCallerClass(), loader, intfs);}//前面的代码基本都是安全检查/*关键代码,动态构造代理类* Look up or generate the designated proxy class.*/Class<?> cl = getProxyClass0(loader, intfs);/*开始调用构造函数* Invoke its constructor with the designated invocation handler.*/try {if (sm != null) {checkNewProxyPermission(Reflection.getCallerClass(), cl);}final Constructor<?> cons = cl.getConstructor(constructorParams);final InvocationHandler ih = h;if (!Modifier.isPublic(cl.getModifiers())) {AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {cons.setAccessible(true);return null;}});}return cons.newInstance(new Object[]{h});} catch (IllegalAccessException|InstantiationException e) {throw new InternalError(e.toString(), e);} catch (InvocationTargetException e) {Throwable t = e.getCause();if (t instanceof RuntimeException) {throw (RuntimeException) t;} else {throw new InternalError(t.toString(), t);}} catch (NoSuchMethodException e) {throw new InternalError(e.toString(), e);}}
private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {if (interfaces.length > 65535) {throw new IllegalArgumentException("interface limit exceeded");}// If the proxy class defined by the given loader implementing// the given interfaces exists, this will simply return the cached copy;// otherwise, it will create the proxy class via the ProxyClassFactoryreturn proxyClassCache.get(loader, interfaces);}

首先从缓存里取代理类,如果没有则通过Proxy里的ProxyClassFactory创建

ublic V get(K key, P parameter) {Objects.requireNonNull(parameter);expungeStaleEntries();Object cacheKey = CacheKey.valueOf(key, refQueue);// lazily install the 2nd level valuesMap for the particular cacheKeyConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);if (valuesMap == null) {ConcurrentMap<Object, Supplier<V>> oldValuesMap= map.putIfAbsent(cacheKey,valuesMap = new ConcurrentHashMap<>());if (oldValuesMap != null) {valuesMap = oldValuesMap;}}// create subKey and retrieve the possible Supplier<V> stored by that// subKey from valuesMapObject subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));Supplier<V> supplier = valuesMap.get(subKey);........}
/*** A factory function that generates, defines and returns the proxy class given* the ClassLoader and array of interfaces.*/private static final class ProxyClassFactory

被代理类
因此我们可以通过ProxyClassFactory尝试手动获取一下代理类的代码:
ps:另一个简单方法:1.8 版本代码前加System.getProperties().put(""sun.misc.ProxyGenerator.saveGeneratedFiles", "true");新版:System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");

//MyHelloProxy是类名,随便取的
byte[] classFile = ProxyGenerator.generateProxyClass("MyHelloProxy", DogHello.class.getInterfaces());String path = "D:/MyHelloProxy.class";try(FileOutputStream fos = new FileOutputStream(path)) {fos.write(classFile);fos.flush();System.out.println("ok");} catch (Exception e) {System.out.println("error");}

接下来看看里面的具体内容:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//import com.baiye.proxy.Hello;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;public final class MyHelloProxy extends Proxy implements Hello {private static Method m1;private static Method m2;private static Method m3;private static Method m0;public MyHelloProxy(InvocationHandler var1) throws  {super(var1);}public final boolean equals(Object var1) throws  {......}public final String toString() throws  {......}public final void say(String var1) throws  {try {super.h.invoke(this, m3, new Object[]{var1});} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}public final int hashCode() throws  {.....}static {try {m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));m2 = Class.forName("java.lang.Object").getMethod("toString");m3 = Class.forName("com.baiye.proxy.Hello").getMethod("say", Class.forName("java.lang.String"));m0 = Class.forName("java.lang.Object").getMethod("hashCode");} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}
}

可以看到,先在静态代码块中初始化所有方法,被代理类持有这些方法,然后在方法调用时:

super.h.invoke(this, m3, new Object[]{var1});

自此Proxy的原理也就明白了:上面这句话super.h指的是父类Proxy里的 protected InvocationHandler h;对象,也就是说被代理类继承Proxy并且所以InvocationHandler h对象,调用的最终是h的方法。

动态代理原理解析 (一):Proxy相关推荐

  1. JDK的动态代理深入解析(Proxy,InvocationHandler)(转)

    一.什么是动态代理 动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实.代理一般会实现它所表示的实际对象的接口.代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际对象实现系统的实际 ...

  2. java动态代理原理解析

    总结:一.应用:1.要代理的类必须有对应实现接口.2.被增强的代码要实现invocationHandle接口,实现接口的invoke方法,在方法里添加增强代码和通过调用method.invoke( p ...

  3. 使用 cglib_CGLib 动态代理 原理解析

    CGLib的基本使用 使用一下CGLib,在JDK动态代理中提供一个Proxy类来创建代理类,而在CGLib动态代理中也提供了一个类似的类Enhancer: 使用的CGLib版本是2.2.2,我是随便 ...

  4. jdk动态代理实例和cglib动态代理实例_CGLib 动态代理 原理解析

    JDK 动态代理实现与原理 首先来看一段CGLib代理的测试代码(MethodInterceptor的测试, 其他类型这里不做展开了). Util类的代码在后面给出的码云片段中 public 下面的输 ...

  5. Java 动态代理 原理解析

    概要 AOP的拦截功能是由java中的动态代理来实现的.说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常 ...

  6. java动态代理_Java 动态代理 原理解析

    示例 需要代理的接口 public interface IHello {public void sayHello(); } 需要代理的类 public class HelloImpl implemen ...

  7. JDK和CGLIB动态代理原理

    JDK动态代理原理解析 一.例子: 1.定义基础接口 public interface HttpApi {String get(String url); } 2.实现类 public class Re ...

  8. java动态代理原理及解析

    转载自 http://blog.csdn.net/scplove/article/details/52451899 代理:设计模式 代理模式是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制 ...

  9. 深入理解Java Proxy和CGLIB动态代理原理

    点击上方关注,每天进步一点点 动态代理在Java中有着广泛的应用,比如Spring AOP,Hibernate数据查询.测试框架的后端mock.RPC,Java注解对象获取等.静态代理的代理关系在编译 ...

最新文章

  1. opengl学习笔记 (一)
  2. python用户登录a_用Python实现用户登录接口
  3. oracle中冗余,各位有没有检查冗余索引的脚本
  4. 踢向《英雄王座》的面目全非脚
  5. 借助C++类结构计算矩形面积(矩形类)
  6. css解决打印不加粗BUG
  7. android自定义剪切板,Android10适配之剪切板
  8. Windows10系统 定时开/关机设置
  9. 微生物组-扩增子16S分析第10期(报名直播课免费参加线下2020.12)
  10. 微信计算机发展的表征是什么意思,【表征】的意思是什么?【表征】是什么意思?...
  11. 第八届山东省赛题 I Parity check 【找规律】
  12. 上海升级为欧莱雅集团北亚区总部;西门子与太古可口可乐将共同打造18座数字化工厂 | 美通企业日报...
  13. 怎样制作Lrc歌词文件
  14. 苹果7p服务器维护中,苹果7p无服务怎么解决
  15. 微信聊天机器人搭建方式分享
  16. 混合高斯模型去除背景
  17. 关于 C4D R18 载入闪退
  18. 如何利用校园邮箱免费使用IDEA
  19. “全国名中医学术经验传承暨经方临证与五运六气经典”高级研修班
  20. 几款JVM图形化监控工具

热门文章

  1. 大量名片图片转excel表格文件怎么转?有什么好办法?
  2. GitHub Actions 部署爬虫并定时发送邮件
  3. 缓存原理设计(Redis)
  4. 写给开发者看的关系型数据库设计
  5. int与char类型间的相互转化
  6. kill -9无法杀死进程
  7. 最简单的matplotlib安装教程
  8. 【带你看看JS生态圈的技术趋势】state-of-js 2021 详细解读
  9. EasyExcel 的行高列宽的单位,直接设置行高列宽的大小
  10. 手机怎么用外嵌字幕_今天才知道,手机拍视频还能添加字幕,方法太简单,看完就能学会...