介绍
Spring动态代理可以选择使用jdk动态代理, 或者cglib动态代理, jdk动态代理位于 java.lang.reflect 包下.
使用时涉及
接口: java.lang.reflect.InvocationHandler
动态代理类: java.lang.reflect.Proxy
注意: JDK 动态代理是基于接口的代理, 只能对实现接口的类生成代理, 不能对类进行代理
使用步骤
1.创建InvocationHandler接口的实现类, 并编写invoke方法的实现
2.创建被代理类的接口及实现类
3.使用动态代理类Proxy的静态方法生成代理类实例
4.使用实例调用方法
代码演示
创建InvocationHandler接口的实现类
/*** JDK 动态代理* 基于接口的代理, 只能对实现接口的类生成代理, 不能对类进行代理** @author liuzhihang* @date 2018/5/17 10:36*/public class MyInvocationHandler implements InvocationHandler {/*** 目标对象*/private Object target;public MyInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("jdk 动态代理 before . . . ");System.out.println("当前代理方法为:" + method);Object invoke = method.invoke(target, args);System.out.println("jdk 动态代理 after . . . ");return invoke;}}
创建被代理类的接口及实现类
/*** 被代理类的接口* @author liuzhihang* @date 2018/5/17 10:47*/public interface Subject {/*** 获取名字* @return*/String getName();/*** 获取年龄* @param name* @return*/String getAge(String name);}
/*** 被代理类** @author liuzhihang* @date 2018/5/17 10:48*/public class SubjectImpl implements Subject {@Overridepublic String getName() {System.out.println("SubjectImpl的获取名字方法 . . .");return "liuzhihang";}@Overridepublic String getAge(String name) {System.out.println(name + "开始获取年龄 . . .");return "25";}}
使用动态代理类Proxy的静态方法生成代理类实例
获取代理类实例有以下两种方式, 一种是通过Proxy.newProxyInstance(..)获取, 一种是通过 Proxy.getProxyClass(..) 方式获取
1.Proxy.newProxyInstance(..)
/*** 当代理类实例调用方法时, 会自动跳转到代理类关联的 handler 对象, 通过 method.invoke(target, args) 进行调用*** @author liuzhihang* @date 2018/5/17 10:49*/public class ProxyMainTest {public static void main(String[] args) {Subject subject = new SubjectImpl();ClassLoader classLoader = subject.getClass().getClassLoader();Class<?>[] interfaces = subject.getClass().getInterfaces();MyInvocationHandler handler = new MyInvocationHandler(subject);// 生成代理类实例Subject proxyInstance = (Subject) Proxy.newProxyInstance(classLoader, interfaces, handler);String name = proxyInstance.getName();String instanceAge = proxyInstance.getAge("liuzhihang");System.err.println(name + " " + instanceAge);}}
2.Proxy.getProxyClass(..)
/*** 当代理类实例调用方法时, 会自动跳转到代理类关联的 handler 对象, 通过 method.invoke(target, args) 进行调用* 此方式有异常抛出** @author liuzhihang* @date 2018/5/17 10:49*/public class ProxyMainTest {public static void main(String[] args) {try {Subject subject = new SubjectImpl();ClassLoader classLoader = subject.getClass().getClassLoader();Class<?>[] interfaces = subject.getClass().getInterfaces();MyInvocationHandler handler = new MyInvocationHandler(subject);Class<?> proxyClass = Proxy.getProxyClass(classLoader, interfaces);Constructor<?> constructor = proxyClass.getConstructor(InvocationHandler.class);Subject subject1 = (Subject) constructor.newInstance(handler);String name1 = subject1.getName();String instanceAge1 = subject1.getAge("liuzhihang");System.err.println(name1 + " " + instanceAge1);} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {e.printStackTrace();}}}
执行结果
D:\jdk1.8\bin\java.exe . . .liuzhihang 25jdk 动态代理 before . . .当前代理方法为:public abstract java.lang.String com.liuzhihang.tool.proxy.jdk.Subject.getName()SubjectImpl的获取名字方法 . . .jdk 动态代理 after . . .jdk 动态代理 before . . .当前代理方法为:public abstract java.lang.String com.liuzhihang.tool.proxy.jdk.Subject.getAge(java.lang.String)liuzhihang开始获取年龄 . . .jdk 动态代理 after . . .Process finished with exit code 0
相关源码解析
完整注释可自己查看相关源码, 源码过程应当DeBug多走走.
1.调用 Proxy.newProxyInstance 方法
/*** 返回指定接口的代理类实例,该接口将方法调用分派给指定的调用处理程序*/@CallerSensitivepublic 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);}/** 从缓存中获取代理类 或者 生成新的代理类*/Class<?> cl = getProxyClass0(loader, intfs);/** 通过反射获取构造函数对象并生成代理类实例*/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() {// 将此对象的可访问标志设置为指定的布尔值, true表示反射对象在使用时应禁止Java语言访问检查, false表示反射对象应强制执行Java语言访问检查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);}}
可以看出获取代理类是在 Class<?> cl = getProxyClass0(loader, intfs); 处, 继续相关逻辑
2.获取代理类相关逻辑
/*** 生成代理类, 之前必须进行权限检查*/private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {if (interfaces.length > 65535) {throw new IllegalArgumentException("interface limit exceeded");}//如果由实现给定接口的给定加载器定义的代理类存在,则它将简单地返回缓存副本; 否则,它将通过Proxy Class Factory创建代理类return proxyClassCache.get(loader, interfaces);}
3.proxyClassCache.get(loader, interfaces);
java.lang.reflect.WeakCache#get(..) 介绍
/*** 通过缓存查找值, 如果缓存中没有给定的(key,sub Key)对的条目或条目已被清除,则它总是评估{Key sub Key Factory}函数并可选择评估{Factory value}函数*/public V get(K key, P parameter) {// 非空校验Objects.requireNonNull(parameter);// 判断移除队列expungeStaleEntries();// 缓存keyObject cacheKey = CacheKey.valueOf(key, refQueue);// 延迟加载使用二级mapConcurrentMap<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;}}// 创建子key 并根据key 检索supplierObject subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));// 根据key获取supplierSupplier<V> supplier = valuesMap.get(subKey);Factory factory = null;while (true) {if (supplier != null) {// supplier 可能为 Factory 或者 CacheValue<V> 的实例, 从缓存中获取到则直接返回V value = supplier.get();if (value != null) {return value;}}// factory不存在则创建if (factory == null) {factory = new Factory(key, parameter, subKey, valuesMap);}// supplier 为nullif (supplier == null) {// 从valuesMap获取suppliersupplier = valuesMap.putIfAbsent(subKey, factory);if (supplier == null) {// successfully installed Factorysupplier = factory;}// else retry with winning supplier} else {if (valuesMap.replace(subKey, supplier, factory)) {// successfully replaced// cleared CacheEntry / unsuccessful Factory// with our Factorysupplier = factory;} else {// retry with current suppliersupplier = valuesMap.get(subKey);}}}}
可以发现重点在 Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); 获取 subKey 的过程中.
4.subKeyFactory.apply(key, parameter)
Debug发现在此处调用的是 java.lang.reflect.Proxy.ProxyClassFactory 静态内部类,
此处根据接口的数量生成二级缓存
/*** 一个工厂函数, 用于生成, 定义并返回给定ClassLoader和接口数组的代理类*/private static final class ProxyClassFactoryimplements BiFunction<ClassLoader, Class<?>[], Class<?>>{// 所有代理类的前缀private static final String proxyClassNamePrefix = "$Proxy";// next number to use for generation of unique proxy class namesprivate static final AtomicLong nextUniqueNumber = new AtomicLong();@Overridepublic Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {// 在IdentityHashMap中, 当且仅当两个key严格相等(key1==key2)时,IdentityHashMap才认为两个key相等Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);// 循环接口数组for (Class<?> intf : interfaces) {/** 验证类加载器是否将此接口的名称解析为同一个Class对象*/Class<?> interfaceClass = null;try {// 获取接口的 classinterfaceClass = Class.forName(intf.getName(), false, loader);} catch (ClassNotFoundException e) {}if (interfaceClass != intf) {throw new IllegalArgumentException(intf + " is not visible from class loader");}/** 验证interfaceClass是否为接口*/if (!interfaceClass.isInterface()) {throw new IllegalArgumentException(interfaceClass.getName() + " is not an interface");}/** 验证接口是否重复*/if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());}}String proxyPkg = null; // package to define proxy class inint accessFlags = Modifier.PUBLIC | Modifier.FINAL;/** 验证所有非公开代理接口是否在同一个包中*/for (Class<?> intf : interfaces) {int flags = intf.getModifiers();if (!Modifier.isPublic(flags)) {accessFlags = Modifier.FINAL;String name = intf.getName();int n = name.lastIndexOf('.');String pkg = ((n == -1) ? "" : name.substring(0, n + 1));if (proxyPkg == null) {proxyPkg = pkg;} else if (!pkg.equals(proxyPkg)) {throw new IllegalArgumentException("non-public interfaces from different packages");}}}if (proxyPkg == null) {// 如果没有非公开的代理接口,使用 com.sun.proxy packageproxyPkg = ReflectUtil.PROXY_PACKAGE + ".";}/** 为要生成的代理类选择一个名称*/long num = nextUniqueNumber.getAndIncrement();String proxyName = proxyPkg + proxyClassNamePrefix + num;/** 生成代理类*/byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);try {return defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);} catch (ClassFormatError e) {/** A ClassFormatError here means that (barring bugs in the* proxy class generation code) there was some other* invalid aspect of the arguments supplied to the proxy* class creation (such as virtual machine limitations* exceeded).*/throw new IllegalArgumentException(e.toString());}}}
5.生辰给代理类
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
可以在测试类中添加以下内容打印出代理类:
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
代理类内容如下:
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package com.sun.proxy;import com.liuzhihang.tool.proxy.jdk.Subject;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;public final class $Proxy0 extends Proxy implements Subject {private static Method m1;private static Method m3;private static Method m2;private static Method m4;private static Method m0;public $Proxy0(InvocationHandler var1) throws {super(var1);}public final boolean equals(Object var1) throws {try {return (Boolean)super.h.invoke(this, m1, new Object[]{var1});} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}public final String getName() throws {try {return (String)super.h.invoke(this, m3, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final String toString() throws {try {return (String)super.h.invoke(this, m2, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final String getAge(String var1) throws {try {return (String)super.h.invoke(this, m4, new Object[]{var1});} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}public final int hashCode() throws {try {return (Integer)super.h.invoke(this, m0, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}static {try {m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));m3 = Class.forName("com.liuzhihang.tool.proxy.jdk.Subject").getMethod("getName");m2 = Class.forName("java.lang.Object").getMethod("toString");m4 = Class.forName("com.liuzhihang.tool.proxy.jdk.Subject").getMethod("getAge", 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());}}}
可以看出生成的$Proxy0类继承Proxy动态代理类并实现了Subject被代理接口, 实现所有方法
通过 super.h.invoke(this, m1, new Object[]{var1}) 内部调用了 InvocationHandler.invoke(…)方法, 通过反射调用代理实例的方法
