注:本文代码基于JDK 17

一、概述

动态代理,一个听起来很高深的名词,其实并非如此,在日常的开发中,你或多或少都有遇到过,比如你调用第三方SDK的方法时,该方法的具体实现或许就是使用了动态代理,这个本文后面会讲到。

不管是在Java开发还是Android开发中,动态代理的应用场景都非常广泛,因此我们需要学习它,并且了解它的运行原理,这也是本文接下来要做的事情。

二、什么是代理?

代理在我们的日常生活中很常见,比如说:

  • 恶略天气出去吃饭麻烦,可以点外卖

  • 爷爷不会使用手机充话费,找孙女帮忙充

在这两个例子中,外卖骑手、孙女这两个角色都是帮我们干活的,他们做着我们不能做或不想做的事情。

因此,代理其实就是当前对象不能做或不想做的事情,委托给别的对象做。

三、静态代理的使用

还是以上面的“孙女帮爷爷充话费”为例进行说明,现有一个行为接口Action,包含了一个充话费的方法recharge

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/**
 * 行为接口
 */
public interface Action {

    /**
     * 充话费
     */
    void recharge();
}

因为爷爷需要充话费,所以Grandfather类实现了Action接口。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/**
 * 爷爷
 */
public final class Grandfather implements Action {

    @Override
    public void recharge() {
        System.out.println("recharge");
    }
}

但是,爷爷并不会使用手机充话费,于是他找了孙女请求帮忙充话费,那么Granddaughter类也要实现Action接口,然后把两者的充话费行为关联起来。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
/**
 * 孙女
 */
public final class Granddaughter implements Action {

    private final Action action;

    public Granddaughter(Action action) {
        this.action = action;
    }

    @Override
    public void recharge() {
        System.out.println("before recharge");
        if (action != null) action.recharge();
        System.out.println("after recharge");
    }
}

最终的main方法如下:

1
2
3
4
5
6
7
8
public class Client {

    public static void main(String[] args) {
        Grandfather grandfather = new Grandfather();
        Granddaughter granddaughter = new Granddaughter(grandfather);
        granddaughter.recharge();
    }
}

由上面代码可知,GrandfatherGranddaughter两个类都实现了相同的接口Action,实际对象是Grandfather,代理对象是Granddaughter

Granddaughter内部有一个action的成员变量,指向实际对象,在构造方法中被初始化,对于方法recharge方法的调用,它转发给了实际对象,接着在调用前后输出了一些跟踪调试信息,这也是代理对原方法进行增强的一种体现,上面代码输出如下:

1
2
3
before recharge
recharge
after recharge

因此,代理背后一般至少有一个实际对象,代理的外部功能和实际对象一般是一样的,用户与代理打交道,不直接接触实际对象。

在代码中创建了一个代理类Granddaughter,它的代码是在写程序时固定的,所以称为静态代理

虽然静态代理实现简单,且不侵入原代码,但是当场景复杂一些的时候,静态代理的缺点也会暴露出来。

1、当需要代理多个类的时候,由于代理对象要实现与目标对象一致的接口,有2种方式:

  • 只维护一个代理类,由这个代理类实现多个接口,但是这样就导致代理类过于庞大
  • 新建多个代理类,每个目标对象对应一个代理类,但是这样会产生过多的代理类

2、当接口增加、删除、修改方法的时候,目标对象与代理类都要同时修改,十分不易维护。

那么,这要如何改进呢?

当然是让代理类动态的生成,这也是接下来要说的动态代理

四、动态代理的使用

在静态代理中,代理类是直接定义在代码中的,而在动态代理中,代理类是动态生成的,那么就有一个疑问了,要如何去实现动态代理呢?

JDK中,提供了java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler这两个类来实现动态代理。动态代理的使用有2个步骤:

  • 创建一个类去实现InvocationHandler接口,并且实现该接口的invoke方法。

  • 使用Proxy类的newProxyInstance方法去创建代理类的实例对象。

接下来,我们按照上面的步骤一一实现动态代理,首先创建一个类ActionInvocationHandler,让它去实现InvocationHandler接口,并且实现该接口的invoke方法,代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
/**
 * Action接口调用处理器
 */
public class ActionInvocationHandler implements InvocationHandler {

    private final Object realObj;   // 实际对象

    public ActionInvocationHandler(Object realObj) {
        this.realObj = realObj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before recharge");
        Object result = method.invoke(realObj, args);
        System.out.println("after recharge");
        return result;
    }
}

ActionInvocationHandler类实现了InvocationHandler接口,它的构造方法接受一个Object类型的参数realObjrealObj表示被代理的实际对象,接着在invoke方法中处理所有的接口调用,它有3个参数:

  • proxy:表示代理对象本身,注意了,它不是被代理的实际对象,这个参数一般用处不大

  • method:表示代理方法的method对象;

  • args:表示代理方法的参数;

上面调用了methodinvoke方法,传递了实际对象realObj作为参数,达到了调用实际对象对应方法的目的,在调用任何方法前后,我们输出了跟踪调试语句。需要注意的是,不能将proxy作为参数传递给methodinvoke方法,比如:

1
Object result = method.invoke(proxy, args);

上面的语句会造成死循环,因为proxy表示当前代理对象,这又会调用到ActionInvocationHandlerinvoke方法。

然后使用Proxy类的newProxyInstance方法去创建代理类的实例对象,调用代理类的实例对象的方法,代码如下:

1
2
3
4
5
6
7
8
9
public class Client {

    public static void main(String[] args) {
        Grandfather grandfather = new Grandfather();
        Action action = (Action) Proxy.newProxyInstance(Action.class.getClassLoader(), new Class<?>[]{Action.class},
                new ActionInvocationHandler(grandfather));
        action.recharge();
    }
}

和静态代理相比,代码看起来复杂不少,但是Action接口和Grandfather的定义不变,程序的输出也没变,只是代理对象Granddaughter的创建方式变了,它使用Proxy类的静态方法newProxyInstance来创建代理对象,该方法的声明如下:

1
2
3
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

newProxyInstance方法有3个参数:

  • loader:代理类的类加载器;

  • interfaces:代理类要实现的接口列表,它是一个数组,元素的类型只能是接口,不能是普通的类;

  • hh的类型为InvocationHandler,它是一个接口,只定义了一个方法invoke,对代理接口所有方法的调用都会转给该方法。

newProxyInstance方法的返回值类型为Object,可以强制转换为interfaces数组中的某个接口类型。这里我们强制转换为了Action类型,需要注意的是,它不能强制转换为某个类类型

如果上面动态代理的代码令你感到疑惑,那么接下来让我们一起去深入源码,慢慢解开你心中的疑惑。

五、动态代理的原理

我们先看下Proxy类的newProxyInstance方法,因为它返回的是代理类的实例对象,那么代理类的实例对象是怎么被构造出来的呢?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public static Object newProxyInstance(ClassLoader loader,                        
                                      Class<?>[] interfaces,                     
                                      InvocationHandler h) {                     
    Objects.requireNonNull(h);                                                   

    // 如果没有调用setSecurityManager方法设置SecurityManager,那么getSecurityManager方法返回为null,因此,默认情况下caller即为null,否则返回调用此方法的方法的调用者的类
    @SuppressWarnings("removal")                                                 
    final Class<?> caller = System.getSecurityManager() == null                  
                                ? null                                           
                                : Reflection.getCallerClass();                   

    /*                                                                           
     * Look up or generate the designated proxy class and its constructor.       
     */   
    // 分析1                                                                      
    Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);       
    // 分析2
    return newProxyInstance(caller, cons, h);                                    
}                                                                                

分析1:调用getProxyConstructor方法创建代理类的构造方法所对应的构造器对象cons

其中方法的参数传入了类加载器loader和数组interfaces

分析2:调用newProxyInstance方法创建代理类的实例对象并返回,其中方法的参数传入了构造器对象consInvocationHandler类型的变量h

OK,首先看getProxyConstructor方法的实现,它是怎么创建的构造器对象cons

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private static Constructor<?> getProxyConstructor(Class<?> caller,             
                                                  ClassLoader loader,          
                                                  Class<?>... interfaces)      
{                                                                              
    // optimization for single interface     
    // 代理接口数组中只有单个接口                                  
    if (interfaces.length == 1) {                                              
        Class<?> intf = interfaces[0]; 
        // 默认情况下,caller为null,不满足此处if                                        
        if (caller != null) {   
            // 检查创建代理类所需的权限                                               
            checkProxyAccess(caller, loader, intf);                            
        }                                                                      
        return proxyCache.sub(intf).computeIfAbsent(                           
            loader,                                                            
            (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()               
        );                                                                     
    } else {    
        // 代理接口数组中存在多个接口                                                                  
        // interfaces cloned                                           
        final Class<?>[] intfsArray = interfaces.clone();  
        // 默认情况下,caller为null,不满足此处if                         
        if (caller != null) { 
            // 检查创建代理类所需的权限                                                 
            checkProxyAccess(caller, loader, intfsArray);                      
        }                                                                      
        final List<Class<?>> intfs = Arrays.asList(intfsArray);                
        return proxyCache.sub(intfs).computeIfAbsent(                          
            loader,                                                            
            (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()               
        );                                                                     
    }                                                                          
}                                                                              

通过上面代码可知,根据数组interfaces的长度来分情况处理,但是不管怎样,最终都是调用了proxyCache变量的复杂调用链进行相关操作,那么proxyCache是什么玩意?

1
2
3
4
5
6
7
8
public class Proxy implements java.io.Serializable {
    /**
     * a cache of proxy constructors with
     * {@link Constructor#setAccessible(boolean) accessible} flag already set
     */
    private static final ClassLoaderValue<Constructor<?>> proxyCache =
        new ClassLoaderValue<>();  
}

由代码注释可知,proxyCache是已设置accessible标志的代理构造函数的缓存,并且它是ClassLoaderValue类型。跟踪ClassLoaderValue类发现它继承自抽象类AbstractClassLoaderValue,当调用ClassLoaderValuesub方法时,因为ClassLoaderValue没有sub方法,所以实际上是调用了抽象类AbstractClassLoaderValuesub方法,这个sub方法创建了Sub对象,而Sub类又是AbstractClassLoaderValue的内部类。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public abstract class AbstractClassLoaderValue<CLV extends AbstractClassLoaderValue<CLV, V>, V> {

    public <K> Sub<K> sub(K key) {
        return new Sub<>(key);
    }

    public final class Sub<K> extends AbstractClassLoaderValue<Sub<K>, V> {
        private final K key;

        Sub(K key) {
            this.key = key;
        }  
    }

}

根据proxyCache变量的复杂调用链,下一步就是调用Sub类的computeIfAbsent方法了,但是Sub类没有computeIfAbsent方法,那么调用的就是父类AbstractClassLoaderValuecomputeIfAbsent方法了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public abstract class AbstractClassLoaderValue<CLV extends AbstractClassLoaderValue<CLV, V>, V> {

    public V computeIfAbsent(ClassLoader cl,
                             BiFunction<
                                 ? super ClassLoader,
                                 ? super CLV,
                                 ? extends V
                                 > mappingFunction) throws IllegalStateException {
        ConcurrentHashMap<CLV, Object> map = map(cl);
        @SuppressWarnings("unchecked")
        CLV clv = (CLV) this;
        Memoizer<CLV, V> mv = null;
        while (true) {
            Object val = (mv == null) ? map.get(clv) : map.putIfAbsent(clv, mv);
            if (val == null) {
                if (mv == null) {
                    // create Memoizer lazily when 1st needed and restart loop
                    mv = new Memoizer<>(cl, clv, mappingFunction);
                    continue;
                }
                // mv != null, therefore sv == null was a result of successful
                // putIfAbsent
                try {
                    // trigger Memoizer to compute the value
                    V v = mv.get();
                    // attempt to replace our Memoizer with the value
                    map.replace(clv, mv, v);
                    // return computed value
                    return v;
                } catch (Throwable t) {
                    // our Memoizer has thrown, attempt to remove it
                    map.remove(clv, mv);
                    // propagate exception because it's from our Memoizer
                    throw t;
                }
            } else {
                try {
                    return extractValue(val);
                } catch (Memoizer.RecursiveInvocationException e) {
                    // propagate recursive attempts to calculate the same
                    // value as being calculated at the moment
                    throw e;
                } catch (Throwable t) {
                    // don't propagate exceptions thrown from foreign Memoizer -
                    // pretend that there was no entry and retry
                    // (foreign computeIfAbsent invocation will try to remove it anyway)
                }
            }
            // TODO:
            // Thread.onSpinLoop(); // when available
        }
    }

}

computeIfAbsent方法当中用到了ConcurrentHashMap,这里可以知道应该是支持多线程并发的,computeIfAbsent方法的功能可以解读为:返回与此ClassLoaderValue和给定ClassLoader关联的值,如果不存在,则通过调用给定的mappingFunction来计算该值,将其关联并返回它。

很明显,map中没有缓存时,创建构造器的核心逻辑落在了在ProxyBuilder类上,继续跟踪ProxyBuilder类,发现它是Proxy的内部类,先看它的成员变量。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public class Proxy implements java.io.Serializable {

    private static final class ProxyBuilder {
        // 分析1
        private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();

        // 分析2:所有代理类名称的前缀
        // prefix for all proxy class names
        private static final String proxyClassNamePrefix = "$Proxy";

        // 分析3:用于生成唯一代理类名称的下一个数字
        // next number to use for generation of unique proxy class names
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        // 分析4:已定义代理类的反向缓存,也就是已经生成代理类的纪录为true
        // a reverse cache of defined proxy classes
        private static final ClassLoaderValue<Boolean> reverseProxyCache =
            new ClassLoaderValue<>();

    }
}

分析1:创建了JavaLangAccess实例,它是通过SharedSecretsgetJavaLangAccess方法来获取,我寻思既然有getXXX方法,那么也应该有setXXX方法,经过一番搜索,发现JavaLangAccesssetJavaLangAccess方法是在System类的setJavaLangAccess方法中被调用,而System类的setJavaLangAccess方法将通过虚拟机VM来调用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
private static void setJavaLangAccess() {                                                                                            
    // Allow privileged classes outside of java.lang                                                                                 
    SharedSecrets.setJavaLangAccess(new JavaLangAccess() {                                                                           

        // 埋下伏笔                                                                                                                                                                 
        public Class<?> defineClass(ClassLoader loader, String name, byte[] b, ProtectionDomain pd, String source) {                 
            return ClassLoader.defineClass1(loader, name, b, 0, b.length, pd, source);                                               
        }                                                                                                                            

        // ...                                                                           
    });                                                                                                                              
}                                                                                                                                    

继续跟踪ProxyBuilder类的构造函数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
ProxyBuilder(ClassLoader loader, List<Class<?>> interfaces) {
    // 分析2:如果模块系统未初始化,那么代理是不支持的                      
    if (!VM.isModuleSystemInited()) {                                              
        throw new InternalError("Proxy is not supported until "                    
                + "module system is fully initialized");                           
    }     
    // 分析3:代理接口数量最多只能65535个                                                                         
    if (interfaces.size() > 65535) {                                               
        throw new IllegalArgumentException("interface limit exceeded: "            
                + interfaces.size());                                              
    }                                                                              

    // 分析4:返回代理接口的所有公共非静态方法签名引用的所有类型(返回值类型、共享参数类型,共享异常类型)                                                                              
    Set<Class<?>> refTypes = referencedTypes(loader, interfaces);                  

    // 分析5:验证给定的代理接口和给定的引用类型对定义加载器可见             
    // IAE if violates any restrictions specified in newProxyInstance              
    validateProxyInterfaces(loader, interfaces, refTypes);                         

    this.interfaces = interfaces;    
    // 分析6:返回生成的代理类所属的模块,有如下规则:
    // 1、如果任何代理接口是包私有的,则代理类位于包私有接口的同一模块中
    // 2、如果所有代理接口都是公共的并且位于导出包中,则代理类位于无条件导出包中的动态模块中
    // 3、如果所有代理接口都是公共的,并且至少有一个位于非导出包中,则该代理类位于非导出包中的动态模块中                                              
    this.module = mapToModule(loader, interfaces, refTypes);                       
    assert getLoader(module) == loader;                                            
}     

// 分析1:如果是单个代理接口的情况,其实也是把接口转换为List,然后调用另一个构造方法                                                                 
ProxyBuilder(ClassLoader loader, Class<?> intf) {  
    this(loader, Collections.singletonList(intf)); 
}                                                  

由上面代码可知,代理类的生成有着许多限制规则,主要是Java 9引入了模块管理的概念,继续跟踪ProxyBuilder类的build方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// 生成一个代理类并返回其代理构造函数,并已设置可访问标志
Constructor<?> build() {                
    // 分析1:定义代理类的Class对象                                       
    Class<?> proxyClass = defineProxyClass(module, interfaces);                
    assert !module.isNamed() || module.isOpen(proxyClass.getPackageName(), Prox

    final Constructor<?> cons;                                                 
    try {      
        // 分析2:返回代理类的构造器                                                                
        cons = proxyClass.getConstructor(constructorParams);                   
    } catch (NoSuchMethodException e) {                                        
        throw new InternalError(e.toString(), e);                              
    }                                                                          
    AccessController.doPrivileged(new PrivilegedAction<Void>() {               
        public Void run() {                                                    
            cons.setAccessible(true);                                          
            return null;                                                       
        }                                                                      
    });                                                                        
    return cons;                                                               
}                                                                              

很明显,代理类的生成过程都在defineProxyClass方法当中,继续跟踪。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
private static Class<?> defineProxyClass(Module m, List<Class<?>> interfaces) { 
    // 分析1:定义代理类所在的包路径                                         
    String proxyPkg = null;     // package to define proxy class in                                                      
    int accessFlags = Modifier.PUBLIC | Modifier.FINAL;                                                                  
    boolean nonExported = false;                                                                                         

    /*                                                                                                                   
     * 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.                                                          
     */        
    // 分析2:记录非公共代理接口的包,以便代理类将定义在同一个包中。验证所有非公共代理接口是否位于同一个包中。                                                                                                          
    for (Class<?> intf : interfaces) {                                                                                   
        int flags = intf.getModifiers();                                                                                 
        if (!Modifier.isPublic(flags)) {                                                                                 
            accessFlags = Modifier.FINAL;  // non-public, final                                                          
            String pkg = intf.getPackageName();                                                                          
            if (proxyPkg == null) {                                                                                      
                proxyPkg = pkg;                                                                                          
            } else if (!pkg.equals(proxyPkg)) {                                                                          
                throw new IllegalArgumentException(                                                                      
                        "non-public interfaces from different packages");                                                
            }                                                                                                            
        } else {                                                                                                         
            if (!intf.getModule().isExported(intf.getPackageName())) {                                                   
                // module-private types                                                                                  
                nonExported = true;                                                                                      
            }                                                                                                            
        }                                                                                                                
    }                                                                                                                    

    // 分析3:所有代理接口都是公共和导出的                                                                                                                 
    if (proxyPkg == null) {                                                                                              
        // all proxy interfaces are public and exported                                                                  
        if (!m.isNamed())                                                                                                
            throw new InternalError("ununamed module: " + m);     
        // 如果代理接口所在包名在模块中是不可导出的,那么代理接口包名定义为com.sun.proxy.模块名,否则定义为模块名                                                       
        proxyPkg = nonExported ? PROXY_PACKAGE_PREFIX + "." + m.getName()                                                
                               : m.getName();                                                                            
    } else if (proxyPkg.isEmpty() && m.isNamed()) {                                                                      
        throw new IllegalArgumentException(                                                                              
                "Unnamed package cannot be added to " + m);                                                              
    }                                                                                                                    

    if (m.isNamed()) {                                                                                                   
        if (!m.getDescriptor().packages().contains(proxyPkg)) {                                                          
            throw new InternalError(proxyPkg + " not exist in " + m.getName());                                          
        }                                                                                                                
    }                                                                                                                    

    /*                                                                                                                   
     * Choose a name for the proxy class to generate.                                                                    
     */                
    // 分析4:选择要生成的代理类的名称           
    // 计数器+1                                                                                      
    long num = nextUniqueNumber.getAndIncrement();  
    // 如果包名为"",代理类名字 $Proxy + 计数器数字,否则 包名.$Proxy + 计数器数字                                                                     
    String proxyName = proxyPkg.isEmpty()                                                                                
                            ? proxyClassNamePrefix + num                                                                 
                            : proxyPkg + "." + proxyClassNamePrefix + num;                                               

    ClassLoader loader = getLoader(m);                                                                                   
    trace(proxyName, m, loader, interfaces);                                                                             

    /*                                                                                                                   
     * Generate the specified proxy class.                                                                               
     */             
    // 分析5:生成指定的代理类
    // 动态生成代理类字节数组                                                                                                     
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(loader, proxyName, interfaces, accessFlags);               
    try {          
        // 通过代理类字节数组定义代理类Class对象,对于了前面说的System的setJavaLangAccess方法的实现                                                                                                     
        Class<?> pc = JLA.defineClass(loader, proxyName, proxyClassFile,                                                 
                                      null, "__dynamic_proxy__");  
        // 缓存代理类已经生成过的标记true                                                      
        reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);                                                     
        return pc;                                                                                                       
    } 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());                                                                
    }                                                                                                                    
}                                                                                                                        

继续跟踪ProxyGeneratorgenerateProxyClass方法,看看是如何生成代理类字节数组的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 给定名称和代理接口列表生成代理类
static byte[] generateProxyClass(ClassLoader loader,                                                                       
                                 final String name,                                                                        
                                 List<Class<?>> interfaces,                                                                
                                 int accessFlags) {    
    // 分析1                                                                    
    ProxyGenerator gen = new ProxyGenerator(loader, name, interfaces, accessFlags);                                        
    final byte[] classFile = gen.generateClassFile();                                                                      

    // 分析2                                                                                                             
    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 = Path.of(dotToSlash(name.substring(0, i)));                                      
                                Files.createDirectories(dir);                                                              
                                path = dir.resolve(name.substring(i + 1) + ".class");                                      
                            } else {                                                                                       
                                path = Path.of(name + ".class");                                                           
                            }                                                                                              
                            Files.write(path, classFile);                                                                  
                            return null;                                                                                   
                        } catch (IOException e) {                                                                          
                            throw new InternalError(                                                                       
                                    "I/O exception saving generated file: " + e);                                          
                        }                                                                                                  
                    }                                                                                                      
                });                                                                                                        
    }                                                                                                                      

    return classFile;                                                                                                      
}                                                                                                                          

分析1:调用了ProxyGeneratorgenerateClassFile方法来生成代理类的字节数组,跟踪看看。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// 生成代理类的类文件。该方法驱动类文件生成过程
private byte[] generateClassFile() {  
    // 确定代理类的基础信息(类修饰符、类名、父类、实现的接口等等)                                                                    
    visit(V14, accessFlags, dotToSlash(className), null,                                                   
            JLR_PROXY, typeNames(interfaces));                                                             

    /*                                                                                                     
     * Add proxy methods for the hashCode, equals,                                                         
     * and toString methods of java.lang.Object.  This is done before                                      
     * the methods from the proxy interfaces so that the methods from                                      
     * java.lang.Object take precedence over duplicate methods in the                                      
     * proxy interfaces.                                                                                   
     */    
    // 分析1:将所有方法封装成ProxyMethod对象       
    // 为java.lang.Object的hashCode、equals和toString方法添加代理方法。这是在代理接口中的方法之前完成的,以便 java.lang.Object 中的方法优先于代理接口中的重复方法。                                                                                       
    addProxyMethod(hashCodeMethod);                                                                        
    addProxyMethod(equalsMethod);                                                                          
    addProxyMethod(toStringMethod);                                                                        

    /*                                                                                                     
     * Accumulate all of the methods from the proxy interfaces.                                            
     */        
    // 遍历所有代理接口中的所有方法,并生成ProxyMethod对象                                                                                            
    for (Class<?> intf : interfaces) {                                                                     
        for (Method m : intf.getMethods()) {                                                               
            if (!Modifier.isStatic(m.getModifiers())) {                                                    
                addProxyMethod(m, intf);                                                                   
            }                                                                                              
        }                                                                                                  
    }                                                                                                      

    /*                                                                                                     
     * For each set of proxy methods with the same signature,                                              
     * verify that the methods' return types are compatible.                                               
     */   
    // 对于具有相同签名的每组代理方法,验证方法的返回类型是否兼容                                                                                                 
    for (List<ProxyMethod> sigmethods : proxyMethods.values()) {                                           
        checkReturnTypes(sigmethods);                                                                      
    }                                                                                                      

    // 分析2:开始生成代理类的构造,方法,成员变量等等     
    // 生成代理类的构造方法                                                                              
    generateConstructor();                                                                                 

    // 遍历ProxyMethod列表                                                                         
    for (List<ProxyMethod> sigmethods : proxyMethods.values()) {                                           
        for (ProxyMethod pm : sigmethods) {                                                                
            // add static field for the Method object    
            // 为Method对象添加静态字段                                                  
            visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL, pm.methodFieldName,                           
                    LJLR_METHOD, null, null);                                                              

            // Generate code for proxy method 
            // 生成代理方法的代码                                                             
            pm.generateMethod(this, className);                                                            
        }                                                                                                  
    }                                                                                                      

    // 生成代理类的静态代码块                                                                                    
    generateStaticInitializer();                                                                           
    generateLookupAccessor();   
    // 第一步:计算 ClassFile 结构的大小(以字节为单位)。 magic 字段使用 4 个字节,10 个强制字段(minor_version、major_version、constant_pool_count、access_flags、this_class、super_class、interfaces_count、fields_count、methods_count 和 attribute_count)每个使用 2 个字节,每个接口也使用 2 个字节。 
    // 第二步:分配一个正确大小的 ByteVector并用 ClassFile 内容填充它。   
    // 也就是写入魔数、次版本号、主版本号、常量池等等。
    // 第三步:转换为二进制数组输出                                                                       
    return toByteArray();                                                                                  
}                                                                                                          

分析2:saveGeneratedFiles是用于保存生成的代理类文件的调试标志,如下所示:

1
2
3
4
private static final boolean saveGeneratedFiles =                           
        java.security.AccessController.doPrivileged(                        
                new GetBooleanAction(                                       
                        "jdk.proxy.ProxyGenerator.saveGeneratedFiles"));    

AccessControllerdoPrivileged方法需要传入PrivilegedAction接口,而PrivilegedAction接口中有一个run方法,run方法的返回值即为saveGeneratedFiles,又因为GetBooleanAction实现了PrivilegedAction接口,所以只需跟踪GetBooleanActionrun方法即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public class GetBooleanAction
        implements java.security.PrivilegedAction<Boolean> {
    private String theProp;

    /**
     * Constructor that takes the name of the system property whose boolean
     * value needs to be determined.
     *
     * @param theProp the name of the system property.
     */
    public GetBooleanAction(String theProp) {
        this.theProp = theProp;
    }

    public Boolean run() {
        return Boolean.getBoolean(theProp);
    }
}

继续跟踪BooleangetBoolean方法。

1
2
3
4
5
6
7
8
public static boolean getBoolean(String name) {                   
    boolean result = false;                                       
    try {                                                         
        result = parseBoolean(System.getProperty(name));          
    } catch (IllegalArgumentException | NullPointerException e) { 
    }                                                             
    return result;                                                
}                                                                 

很显然,调用了System类的getProperty方法,然后转换为boolean值返回,name其实就是

jdk.proxy.ProxyGenerator.saveGeneratedFiles,那么我们只需要在Proxy类的newProxyInstance方法之前,通过System类的setProperty方法设置该值为true即可保存代理类文件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class Client {

    public static void main(String[] args) {
        System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
        Grandfather grandfather = new Grandfather();
        Action action = (Action) Proxy.newProxyInstance(Action.class.getClassLoader(), new Class<?>[]{Action.class},
                new ActionInvocationHandler(grandfather));
        action.recharge();
    }
}

运行过后,会在如下位置生成代理类,这也是接口都是public修饰时的情况。

本例中生成的代理类如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public final class $Proxy0 extends Proxy implements Action {
    private static final Method m0;
    private static final Method m1;
    private static final Method m2;
    private static final Method m3;

    public $Proxy0(InvocationHandler var1) {
        super(var1);
    }

    public final int hashCode() {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final boolean equals(Object var1) {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() {
        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 recharge() {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.pengmj.proxy.Action").getMethod("recharge");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }

    private static MethodHandles.Lookup proxyClassLookup(MethodHandles.Lookup var0) throws IllegalAccessException {
        if (var0.lookupClass() == Proxy.class && var0.hasFullPrivilegeAccess()) {
            return MethodHandles.lookup();
        } else {
            throw new IllegalAccessException(var0.toString());
        }
    }
}

由上面代码可知:

1、代理类$Proxy0继承自Proxy类,并实现了我们自己定义的Action接口;

有一个疑问:问什么JDK动态代理只能基于接口进行代理?

因为它已经继承了Proxy类了,而Java不支持多继承。

2、代理类使用了final修饰,说明代理类无法被继承;

3、接口中所有被代理的方法以及Object类的hashCodeequalstoString方法在static静态代码块中通过反射建立了method对象;

4、当调用接口中所有被代理的方法以及Object类的hashCodeequalstoString方法时,都会转交给InvocationHandlerinvoke方法;

我们回到之前流程,当创建了代理类的构造器之后,就会调用newProxyInstance方法,继续跟踪看看。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private static Object newProxyInstance(Class<?> caller, // null if no SecurityManager                
                                       Constructor<?> cons,                                          
                                       InvocationHandler h) {                                        
    /*                                                                                               
     * Invoke its constructor with the designated invocation handler.                                
     */                                                                                              
    try {                                                                                            
        if (caller != null) {                                                                        
            checkNewProxyPermission(caller, cons.getDeclaringClass());                               
        }                                                                                            

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

很明显了,通过构造器直接newInstance创建代理类实例对象,构造方法传入的参数为h。至此,JDK动态代理的原理就讲解完成了。

六、动态代理在Android上的运用

Android上,动态代理也隐隐约约地存在着,比如网络请求框架Retrofit,它的create方法就使用了动态代理。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public <T> T create(final Class<T> service) {                                                                         
  validateServiceInterface(service);                                                                                  
  return (T)                                                                                                          
      Proxy.newProxyInstance(                                                                                         
          service.getClassLoader(),                                                                                   
          new Class<?>[] {service},                                                                                   
          new InvocationHandler() {                                                                                   
            private final Platform platform = Platform.get();                                                         
            private final Object[] emptyArgs = new Object[0];                                                         

            @Override                                                                                                 
            public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)                      
                throws Throwable {                                                                                    
              // If the method is a method from Object then defer to normal invocation.                               
              if (method.getDeclaringClass() == Object.class) {                                                       
                return method.invoke(this, args);                                                                     
              }                                                                                                       
              args = args != null ? args : emptyArgs;                                                                 
              return platform.isDefaultMethod(method)                                                                 
                  ? platform.invokeDefaultMethod(method, service, proxy, args)                                        
                  : loadServiceMethod(method).invoke(args);                                                           
            }                                                                                                         
          });                                                                                                         
}