首页 > 编程语言 > 详细

java动态代理

时间:2019-12-09 09:32:17      阅读:74      评论:0      收藏:0      [点我收藏+]

  引言

  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);
                }
            }
        }
    }             

 

看下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

java动态代理

原文:https://www.cnblogs.com/guolinjiang/p/12008823.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!