动态代理原理解析 (一):Proxy
常用动态代理主要有两种: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相关推荐
- JDK的动态代理深入解析(Proxy,InvocationHandler)(转)
一.什么是动态代理 动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实.代理一般会实现它所表示的实际对象的接口.代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际对象实现系统的实际 ...
- java动态代理原理解析
总结:一.应用:1.要代理的类必须有对应实现接口.2.被增强的代码要实现invocationHandle接口,实现接口的invoke方法,在方法里添加增强代码和通过调用method.invoke( p ...
- 使用 cglib_CGLib 动态代理 原理解析
CGLib的基本使用 使用一下CGLib,在JDK动态代理中提供一个Proxy类来创建代理类,而在CGLib动态代理中也提供了一个类似的类Enhancer: 使用的CGLib版本是2.2.2,我是随便 ...
- jdk动态代理实例和cglib动态代理实例_CGLib 动态代理 原理解析
JDK 动态代理实现与原理 首先来看一段CGLib代理的测试代码(MethodInterceptor的测试, 其他类型这里不做展开了). Util类的代码在后面给出的码云片段中 public 下面的输 ...
- Java 动态代理 原理解析
概要 AOP的拦截功能是由java中的动态代理来实现的.说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常 ...
- java动态代理_Java 动态代理 原理解析
示例 需要代理的接口 public interface IHello {public void sayHello(); } 需要代理的类 public class HelloImpl implemen ...
- JDK和CGLIB动态代理原理
JDK动态代理原理解析 一.例子: 1.定义基础接口 public interface HttpApi {String get(String url); } 2.实现类 public class Re ...
- java动态代理原理及解析
转载自 http://blog.csdn.net/scplove/article/details/52451899 代理:设计模式 代理模式是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制 ...
- 深入理解Java Proxy和CGLIB动态代理原理
点击上方关注,每天进步一点点 动态代理在Java中有着广泛的应用,比如Spring AOP,Hibernate数据查询.测试框架的后端mock.RPC,Java注解对象获取等.静态代理的代理关系在编译 ...
最新文章
- opengl学习笔记 (一)
- python用户登录a_用Python实现用户登录接口
- oracle中冗余,各位有没有检查冗余索引的脚本
- 踢向《英雄王座》的面目全非脚
- 借助C++类结构计算矩形面积(矩形类)
- css解决打印不加粗BUG
- android自定义剪切板,Android10适配之剪切板
- Windows10系统 定时开/关机设置
- 微生物组-扩增子16S分析第10期(报名直播课免费参加线下2020.12)
- 微信计算机发展的表征是什么意思,【表征】的意思是什么?【表征】是什么意思?...
- 第八届山东省赛题 I Parity check 【找规律】
- 上海升级为欧莱雅集团北亚区总部;西门子与太古可口可乐将共同打造18座数字化工厂 | 美通企业日报...
- 怎样制作Lrc歌词文件
- 苹果7p服务器维护中,苹果7p无服务怎么解决
- 微信聊天机器人搭建方式分享
- 混合高斯模型去除背景
- 关于 C4D R18 载入闪退
- 如何利用校园邮箱免费使用IDEA
- “全国名中医学术经验传承暨经方临证与五运六气经典”高级研修班
- 几款JVM图形化监控工具