@coldxiangyu
2017-06-15T08:23:24.000000Z
字数 10876
阅读 1283
源码系列
关于代理模式这里就不再详述了。
在编写简易的RPC以及AOP框架过程中,涉及到了使用java动态代理(Proxy)。
我们来首先来看java动态代理的简易demo:
1.定义接口Subject
package com.lxy.dynamicproxy;/*** Created by coldxiangyu on 2017/6/15.*/public interface Subject {public void request();}
2.定义真实角色类
package com.lxy.dynamicproxy;/*** Created by coldxiangyu on 2017/6/15.*/public class RealSubject implements Subject {@Overridepublic void request() {System.out.println("this is real subject");}}
3.定义代理类DynamicSubject实现InvocationHandler接口,重写invoke方法:
import java.lang.reflect.Method;/*** Created by coldxiangyu on 2017/6/15.*/public class DynamicSubject implements InvocationHandler{private Object obj;public DynamicSubject(Object obj){this.obj = obj;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("before calling:" + method);System.out.println("before calling:" + method);return method.invoke(obj, args);}}
4.客户端通过Proxy.newProxyInstance调用:
package com.lxy.dynamicproxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;/*** Created by coldxiangyu on 2017/6/15.*/public class Client {public static void main(String[] args){Subject rs = new RealSubject();InvocationHandler ds = new DynamicSubject(rs);Class cls = rs.getClass();Subject subject = (Subject) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),ds);subject.request();}}
调用结果:
before calling:public abstract void com.lxy.dynamicproxy.Subject.request()before calling:public abstract void com.lxy.dynamicproxy.Subject.request()this is real subject进程已结束,退出代码0
我们来看一下源码(我本地JDK1.8)是怎样的,一个是InvocationHandler接口,另一个就是Proxy类。
InvocationHandler接口比较简单,只定义了一个返回类型是Object的方法:public Object invoke(Object proxy, Method method, Object[] args),那么这个方法必然是在Proxy类中存在调用的,带着这个猜测我们去看Proxy类:
Proxy类就复杂多了,我们挑主要的地方看,首先看我们调用的Proxy.newProxyInstance方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {//Objects.requireNonNull 判空方法,之后所有的单纯的判断null并抛异常,都是此方法Objects.requireNonNull(h);//clone 类实现的所有接口final Class<?>[] intfs = interfaces.clone();//获取当前系统安全接口final SecurityManager sm = System.getSecurityManager();if (sm != null) {//Reflection.getCallerClass返回调用该方法的方法的调用类;loader:接口的类加载器//进行包访问权限、类加载器权限等检查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);}}
从上面的源码可以看出,newProxyInstance主要通过getProxyClass0(loader, intfs)方法生成代理类,并通过getConstructor(constructorParams)获取构造方法,最后通过cons.newInstance(new Object[]{h})返回代理类对象。
我们再来看看getProxyClass0是如何获取代理类的:
/*** a cache of proxy classes:动态代理类的弱缓存容器* KeyFactory:根据接口的数量,映射一个最佳的key生成函数,其中表示接口的类对象被弱引用;也就是key对象被弱引用继承自WeakReference(key0、key1、key2、keyX),保存接口密钥(hash值)* ProxyClassFactory:生成动态类的工厂* 注意,两个都实现了BiFunction<ClassLoader, Class<?>[], Object>接口*/private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());/*** Generate a proxy class. Must call the checkProxyAccess method* to perform permission checks before calling this.* 生成代理类,调用前必须进行 checkProxyAccess权限检查,所以newProxyInstance进行了权限检查*/private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {//实现接口的最大数量<65535;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 ProxyClassFactory// 如果缓存中有,就直接返回,否则会生成return proxyClassCache.get(loader, interfaces);}
这个方法并没有太多有效信息,我们继续跳转proxyClassCache.get(loader, interfaces)方法:
public V get(K key, P parameter) {//key:类加载器;parameter:接口数组Objects.requireNonNull(parameter);//清除已经被GC回收的弱引用expungeStaleEntries();//CacheKey弱引用类,refQueue已经被回收的弱引用队列;构建一个CacheKeyObject cacheKey = CacheKey.valueOf(key, refQueue);//map一级缓存,获取valuesMap二级缓存ConcurrentMap<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;}}// subKeyFactory类型是KeyFactory,apply返回表示接口的keyObject subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));//Factory 实现了supplier,我们实际是获取缓存中的Factory,调用其get方法Supplier<V> supplier = valuesMap.get(subKey);Factory factory = null;//下面用到了 CAS+重试 实现的多线程安全的 非阻塞算法while (true) {if (supplier != null) {// 只需要知道,最终会调用get方法,此supplier可能是缓存中取出来的,也可能是Factory新new出来的V value = supplier.get();if (value != null) {return value;}}// else no supplier in cache// or a supplier that returned null (could be a cleared CacheValue// or a Factory that wasn't successful in installing the CacheValue)// lazily construct a Factoryif (factory == null) {factory = new Factory(key, parameter, subKey, valuesMap);}if (supplier == null) {supplier = 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);}}}}
我们看到这个方法的返回值是通过supplier.get()获取的,这个方法调用ProxyClassFactory的apply()方法:
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);for (Class<?> intf : interfaces) {/** Verify that the class loader resolves the name of this interface to the same Class object.* 类加载器和接口名解析出的是同一个*/Class<?> interfaceClass = null;try {interfaceClass = Class.forName(intf.getName(), false, loader);} catch (ClassNotFoundException e) {}if (interfaceClass != intf) {throw new IllegalArgumentException( intf + " is not visible from class loader");}/** Verify that the Class object actually represents an interface.* 确保是一个接口*/if (!interfaceClass.isInterface()) {throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface");}/** Verify that this interface is not a duplicate.* 确保接口没重复*/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;/** Record the package of a non-public proxy interface so that the proxy class will be defined in the same package.* Verify that all non-public proxy interfaces are in the same package.* 验证所有非公共的接口在同一个包内;公共的就无需处理*/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) {// if no non-public proxy interfaces, use com.sun.proxy packageproxyPkg = ReflectUtil.PROXY_PACKAGE + ".";}/** Choose a name for the proxy class to generate.* proxyClassNamePrefix = $Proxy* nextUniqueNumber 是一个原子类,确保多线程安全,防止类名重复,类似于:$Proxy0,$Proxy1......*/long num = nextUniqueNumber.getAndIncrement();String proxyName = proxyPkg + proxyClassNamePrefix + num;/** Generate the specified proxy class.* 生成类字节码的方法:重点*/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());}}
由此ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags),生成类的字节码:
public static byte[] generateProxyClass(final String name, Class<?>[] interfaces, int accessFlags) {ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);//真正生成字节码的方法final byte[] classFile = gen.generateClassFile();//如果saveGeneratedFiles为true 则生成字节码文件,所以在开始我们要设置这个参数//当然,也可以通过返回的bytes自己输出if (saveGeneratedFiles) {java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Void>() {public Void run() {try {int i = name.lastIndexOf('.');Path path;if (i > 0) {Path dir = Paths.get(name.substring(0, i).replace('.', File.separatorChar));Files.createDirectories(dir);path = dir.resolve(name.substring(i+1, name.length()) + ".class");} else {path = Paths.get(name + ".class");}Files.write(path, classFile);return null;} catch (IOException e) {throw new InternalError( "I/O exception saving generated file: " + e);}}});}return classFile;}
我们看到 final byte[] classFile = gen.generateClassFile();是真正获取字节码的方法。限于篇幅,这里就不贴如何生成字节码类文件了,有兴趣的可以自行去看。我们真正关心的是生成的字节码文件是怎样的,我们将字节码类文件反编译查看一下:
final class $Proxy0 extends Proxy implements pro {//fieldsprivate static Method m1;private static Method m2;private static Method m3;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})).booleanValue();} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}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 void text() throws {try {//实际就是调用代理类的invoke方法super.h.invoke(this, m3, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final int hashCode() throws {try {return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}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("spring.commons.api.study.CreateModel.pro").getMethod("text", new Class[0]);m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}}
这时候,我们就看得很清楚了,每个方法的实现其实都是通过调用InvocationHandler的invoke方法实现的。
这时候总结一下Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),ds)的实现过程就是首先通过classLoader和interfaces生成字节码代理类,再进行重新构造,生成代理对象的过程。