java动态代理

浪子不回头ぞ 提交于 2019-12-09 01:13:28

  引言

  Java动态代理是代理模式的一种,代理模式就是:为另一个对象提供一个替身或占位符一控制对这个对象的访问。举个例子,明星都有一个经济人,一般各种商业活动,都会先找到经济人进行洽谈,洽谈成功,才会给明星安排上活动,经纪人就是明星的代理。

  在java.lang.reflect包中实现了对代理的支持,利用这个包,可以在运行时动态的创建一个代理类。通过实现一个或多个接口,并将方法的调用转发到你所指定的类。

  看下java动态代理的类图:

 

 

 

 

  Proxy类是java根据Subject动态创建的,我们干预不了这个类,所以我们不能在这个类中,去做什么。我们需要一个方式来告诉Proxy我们要做什么。所以我们需要一个InvocationHandler来响应Proxy类的方法调用。可以理解为Proxy收到方法调用后,会将通过InvocationHandler来做实际的工作(其实InvocationHandler也是委托RealSubject来做的)。

  简单demo代码 

/**
 * 接口
 */
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);
                }
            }
        }
    }             

 

 


// 生成动态代理类对象的私有内部类
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() { // serialize access // 再次检查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) { // remove us on failure 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中去分析了,如下图所示:

 

 现在我们接着往下看

 

 

 

    

/** * 接口 */public interface Subject {    void doSomething();}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!