Java动态代理是代理模式的一种,代理模式就是:为另一个对象提供一个替身或占位符一控制对这个对象的访问。举个例子,明星都有一个经济人,一般各种商业活动,都会先找到经济人进行洽谈,洽谈成功,才会给明星安排上活动,经纪人就是明星的代理。
在java.lang.reflect包中实现了对代理的支持,利用这个包,可以在运行时动态的创建一个代理类。通过实现一个或多个接口,并将方法的调用转发到你所指定的类。
看下java动态代理的类图:
Proxy类是java根据Subject动态创建的,我们干预不了这个类,所以我们不能在这个类中,去做什么。我们需要一个方式来告诉Proxy我们要做什么。所以我们需要一个InvocationHandler来响应Proxy类的方法调用。可以理解为Proxy收到方法调用后,会将通过InvocationHandler来做实际的工作(其实InvocationHandler也是委托RealSubject来做的)。
/** * 接口 */ public interface Subject { void doSomething(); } /** * 接口实现类 */ public class RealSubject implements Subject{ public void doSomething(){ System.out.println( "I‘m doSomething()" ); } } /** * 实现Invocation,重写invoke方法 * 在此方法中,实现对要请求的真正的方法进行一些控制:比如方法前后执行一些操作 */ public class ProxyHandler implements InvocationHandler { private Object proxied; public ProxyHandler(Object proxied) { this.proxied = proxied; } // 该方法负责集中处理动态代理类上的所有方法调用。第一个参数是代理类实例,第二个参数是被调用的方法对象 // 第三个方法是调用参数。InvocationHandler根据这三个参数进行预处理或分派到委托类实例上执行 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //在调用具体目标对象之前,可以执行一些功能处理 System.out.println("before doSomething"); //转调具体目标对象的方法 Object obj = method.invoke(proxied, args); //在调用具体目标对象之后,可以执行一些功能处理 System.out.println("after doSomething"); return obj; } } /** * 创建动态代理,并调用其方法 */ public class DynamicProxy { public static void main(String[] args) { RealSubject real = new RealSubject(); /** * Proxy.newProxyInstance就是创建动态代理类的方法,此方法接收三个参数: * 1、和要代理的类RealSubject实现的接口相同的类加载器 * 2、一组接口 * 3、InvocationHandler实例 * 方法返回的是一个Object对象,因为生成的代理类实现了Subject接口,所以可以强转为Subject */ Subject proxySubject = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(), new Class[]{Subject.class}, new ProxyHandler(real)); //代理类对象调用doSomething()方法,会调用InvocationHandler实例中的invoke方法来做真正的工作 proxySubject.doSomething(); } }
从Proxy类的静态方法newProxyInstance开始,动态代理实例就是通过此方法生成的。此方法接收三个参数:1、类加载器;2、代理需要实现的一组接口;3、InvocationHandler类型的实例。在进一步分析newProxyInstance方法之前,我们先概览一下Proxy这个类:
1、Proxy类静态属性和静态方法清单:
/**-------------静态方法----------------*/ //代理类的构造器参数类型 */ private static final Class<?>[] constructorParams = { InvocationHandler.class }; // 用于维护类装载器对象到其对应的代理类缓存 private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache =
new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); //调用处理器的实例. protected InvocationHandler h; /**-------------静态方法----------------*/ // 方法 1:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例 public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) // 方法2:内部私有静态方法。该方法用于为指定类装载器、一组接口生成动态代理类对象 private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces)
进入到newProxyInstance方法内,去看方法的执行过程(如下图),我们看到getProxyClass0方法,这个方法返回代理类对象,这个方法接收两个参数:类加载器和代理的一组接口。
接下来,我们看getProxyClass0方法内部
到这里,我们看到关键代码就是,从proxyClassCache这个静态属性中获取类对象。这个静态属性,上面我们橄榄过了,就是一个维护类加载器到其代理类实例的缓存。接下来我们看proxyClassCache.get方法,看这个方法之前,我们先分析下这个静态属性:
看完了这些相关的我们就接着看proxyClassCache.get方法,这个方法接收两个参数,一个是类加载器,一个接口。
public V get(K key, P parameter) { Objects.requireNonNull(parameter); expungeStaleEntries(); //确保key不为空 Object cacheKey = CacheKey.valueOf(key, refQueue); /**延迟装载第二个valuesMap * 如果根据cache获取不到valuesMap,则创建一个 * ConcurrentHashMap加到map中 * */ 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; } } /** 获取第二map即valuesMap的key, *这个subKeyFactory就是我们前面看过的KeyFactory,这个factroy用来产生一个key *然后根据这个key去获取我们需要的值, * 这个值就是我们需要的动态代理类对象 *其实第一次获取的时候,缓存中是空的,这个时候,会通过Factory这个WeakCache类中的私有类来生成这个动态代理类对象 */ Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); Supplier<V> supplier = valuesMap.get(subKey); Factory factory = null;//通过这个类来调用相关方法生成动态代理类对象 while (true) { if (supplier != null) { // supplier might be a Factory or a CacheValue<V> instance 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 Factory if (factory == null) { factory = new Factory(key, parameter, subKey, valuesMap); } if (supplier == null) { supplier = valuesMap.putIfAbsent(subKey, factory); if (supplier == null) { // successfully installed Factory supplier = factory; } // else retry with winning supplier } else { if (valuesMap.replace(subKey, supplier, factory)) { // successfully replaced // cleared CacheEntry / unsuccessful Factory // with our Factory supplier = factory; } else { // retry with current supplier supplier = valuesMap.get(subKey); } } } }
看下WeakCache类中的私有Factory类
// 生成动态代理类对象的私有内部类 private final class Factory implements Supplier<V> { private final K key; private final P parameter; private final Object subKey; private final ConcurrentMap<Object, Supplier<V>> valuesMap; Factory(K key, P parameter, Object subKey, ConcurrentMap<Object, Supplier<V>> valuesMap) { this.key = key; this.parameter = parameter; this.subKey = subKey; this.valuesMap = valuesMap; } @Override public synchronized V get() { // 再次检查valuesMap时候包含需要查找的动态代理类对象 Supplier<V> supplier = valuesMap.get(subKey); if (supplier != this) { return null; } // 如果supplier == this 说明还没生成动态代理类对象,就新生成一个 V value = null; try { /* 如果supplier == this 说明还没生成动态代理类对象,就新生成一个 * 找到生成字节码的地方了,就是valueFactory.apply这个方法。前面我们看到过proxyClassCache这个Proxy类中的静态属性,这个属性在初始化的时候传了 * ProxyClassFactory这个类实例到WeakCache的构造方法中,就是赋值给valueFactory,现在调用其apply方法来动态生成代理类的字节码了 * 生成的字节码就会保存到valuesMap中了 */ value = Objects.requireNonNull(valueFactory.apply(key, parameter)); } finally { if (value == null) { valuesMap.remove(subKey, this); } } // the only path to reach here is with non-null value assert value != null; // wrap value with CacheValue (WeakReference) CacheValue<V> cacheValue = new CacheValue<>(value); // put into reverseMap reverseMap.put(cacheValue, Boolean.TRUE); // try replacing us with CacheValue (this should always succeed) if (!valuesMap.replace(subKey, this, cacheValue)) { throw new AssertionError("Should not reach here"); } // successfully replaced us with new CacheValue -> return the value // wrapped by it return value; }
字节码生成的过程已经搞清楚了,回到Proxy类的newProxyInstance方法,前面我们进行到此方法中的getProxyClass0中去分析了,如下图所示:
现在我们接着往下看
我的源码版本是jdk1.8
原文:https://www.cnblogs.com/guolinjiang/p/12008823.html