JDK1.8 Proxy

Proxy 1.8

以下源码分析取核心代码

变量定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/** parameter types of a proxy class constructor */
private static final Class<?>[] constructorParams =
{ InvocationHandler.class };

/**
* a cache of proxy classes
*/
// #1
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

/**
* the invocation handler for this proxy instance.
* @serial
*/
protected InvocationHandler h;
  1. 根据注释很容易理解,1.8在1.7基础上优化代码,依然是弱引用做为缓存。key和value都采用工厂模式。

    KeyFactory

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /**
    * A function that maps an array of interfaces to an optimal key where
    * Class objects representing interfaces are weakly referenced.
    */
    private static final class KeyFactory
    implements BiFunction<ClassLoader, Class<?>[], Object>
    {
    @Override
    public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
    switch (interfaces.length) {
    case 1: return new Key1(interfaces[0]); // the most frequent
    case 2: return new Key2(interfaces[0], interfaces[1]);
    case 0: return key0;
    default: return new KeyX(interfaces);
    }
    }
    }
  2. 根据上下文代码及注释,可以知道这是工厂模式。

  3. 实现BiFunction函数,BiFunction是函数式接口。
  4. Key1Key2KeyX,代表接口数量。分别是1个接口、2个接口、多个接口。

Key1、Key2、KeyX

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/*
* a key used for proxy class with 0 implemented interfaces
*/
// #1
private static final Object key0 = new Object();

/*
* Key1 and Key2 are optimized for the common use of dynamic proxies
* that implement 1 or 2 interfaces.
*/

/*
* a key used for proxy class with 1 implemented interface
*/
// #2
private static final class Key1 extends WeakReference<Class<?>> {
private final int hash;

Key1(Class<?> intf) {
super(intf);
this.hash = intf.hashCode();
}

@Override
public int hashCode() {
return hash;
}

@Override
public boolean equals(Object obj) {
Class<?> intf;
return this == obj ||
obj != null &&
obj.getClass() == Key1.class &&
(intf = get()) != null &&
intf == ((Key1) obj).get();
}
}

/*
* a key used for proxy class with 2 implemented interfaces
*/
// #3
private static final class Key2 extends WeakReference<Class<?>> {
private final int hash;

private final WeakReference<Class<?>> ref2;

Key2(Class<?> intf1, Class<?> intf2) {
super(intf1);
hash = 31 * intf1.hashCode() + intf2.hashCode();
// #4
ref2 = new WeakReference<Class<?>>(intf2);
}

@Override
public int hashCode() {
return hash;
}

@Override
public boolean equals(Object obj) {
Class<?> intf1, intf2;
return this == obj ||
obj != null &&
obj.getClass() == Key2.class &&
(intf1 = get()) != null &&
intf1 == ((Key2) obj).get() &&
(intf2 = ref2.get()) != null &&
intf2 == ((Key2) obj).ref2.get();
}
}

/*
1. a key used for proxy class with any number of implemented interfaces
2. (used here for 3 or more only)
*/
// #5
private static final class KeyX {
private final int hash;

private final WeakReference<Class<?>>[] refs;

@SuppressWarnings("unchecked")
KeyX(Class<?>[] interfaces) {
hash = Arrays.hashCode(interfaces);
refs = (WeakReference<Class<?>>[])new WeakReference<?>[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
refs[i] = new WeakReference<>(interfaces[i]);
}
}

@Override
public int hashCode() {
return hash;
}

@Override
public boolean equals(Object obj) {
return this == obj ||
obj != null &&
obj.getClass() == KeyX.class &&
equals(refs, ((KeyX) obj).refs);
}

private static boolean equals(WeakReference<Class<?>>[] refs1,
WeakReference<Class<?>>[] refs2) {
if (refs1.length != refs2.length) {
return false;
}
for (int i = 0; i < refs1.length; i++) {
Class<?> intf = refs1[i].get();
if (intf == null || intf != refs2[i].get()) {
return false;
}
}
return true;
}
}
  1. 0个接口,proxy class的key。
  2. 同3。
  3. Key1Key2是proxy class实现1个接口、2个接口的实现。
  4. 第2个接口的弱引用对象。
  5. Key3是proxy class实现3个以上接口。

    ProxyClassFactory

    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
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    /**
    1. A factory function that generates, defines and returns the proxy class given
    2. the ClassLoader and array of interfaces.
    */
    private static final class ProxyClassFactory
    implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
    // prefix for all proxy class names
    private static final String proxyClassNamePrefix = "$Proxy";

    // next number to use for generation of unique proxy class names
    private static final AtomicLong nextUniqueNumber = new AtomicLong();

    @Override
    public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
    // #1
    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 in
    int 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.
    */
    // #2
    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 package
    proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
    }

    /*
    * Choose a name for the proxy class to generate.
    */
    // #3
    long num = nextUniqueNumber.getAndIncrement();
    String proxyName = proxyPkg + proxyClassNamePrefix + num;

    /*
    * Generate the specified proxy class.
    */
    // #4
    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());
    }
    }
    }
  6. IdentityHashMap存储接口class,并且做interfaceclass验效。

  7. 验证非public接口的package是不是都是在同一个package下。
  8. 根据原子特性,生成proxy nameproxy name规则是序号递增的。
  9. ProxyGeneratorsun.misc包下的,生成proxy class的字节码。
  10. 由以上得知Java动态代理只能代理接口。

    newProxyInstance

    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
    public static Object newProxyInstance(ClassLoader loader,
    Class<?>[] interfaces,
    InvocationHandler h)
    throws IllegalArgumentException
    {
    Objects.requireNonNull(h);

    final Class<?>[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
    checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }

    /*
    * Look up or generate the designated proxy class.
    */
    // #1
    Class<?> cl = getProxyClass0(loader, intfs);

    /*
    * Invoke its constructor with the designated invocation handler.
    */
    try {
    if (sm != null) {
    checkNewProxyPermission(Reflection.getCallerClass(), cl);
    }
    // #2
    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;
    }
    });
    }
    // #3
    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);
    }
    }
  11. 生成proxy class,cl = class com.sun.proxy.$Proxy0。这里$Proxy0对象是临时生成,没有java、class(第6会说明)文件。

  12. cl.getConstructor(constructorParams)实际上就是com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)
  13. 生成proxy class实例化对象。

    ProxyGenerator#generateProxyClass

    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
    private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));

    public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
    ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
    final byte[] var4 = var3.generateClassFile();
    // #1
    if (saveGeneratedFiles) {
    AccessController.doPrivileged(new PrivilegedAction<Void>() {
    public Void run() {
    try {
    int var1 = var0.lastIndexOf(46);
    Path var2;
    if (var1 > 0) {
    Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
    Files.createDirectories(var3);
    var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
    } else {
    var2 = Paths.get(var0 + ".class");
    }
    // #2
    Files.write(var2, var4, new OpenOption[0]);
    return null;
    } catch (IOException var4x) {
    throw new InternalError("I/O exception saving generated file: " + var4x);
    }
    }
    });
    }

    return var4;
    }
  14. 判断是否存储proxy class字节码$Proxy0到磁盘。

  15. 输出流,保存到磁盘。

    proxy class字节码写入磁盘

    demo1

    根据ProxyGenerator#generateProxyClass#saveGeneratedFiles,可以把saveGeneratedFiles设置为true。在磁盘上(项目路径下)会生成$Proxy0.class文件。
    1
    2
    // #1
    private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));
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;
}
1
2
// #2
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
  1. GetBooleanAction#run,从Boolean#getBoolean获取值,从Boolean#getBoolean可以知道,最终调用的System.getProperty(name)
  2. 由1知道,所以我们这里设置saveGeneratedFiles = true。注意jdk1.8.0_161设置String = true才生效。

    完整代码例子

    Mammal

    1
    2
    3
    4
    5
    //接口1:Mammal(哺乳动物)
    public interface Mammal {
    void eat(String food);
    String type();
    }

Primate

1
2
3
4
//接口2:Primate(灵长类动物)  
public interface Primate {
void think();
}

Monkey

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//实现类:Monkey  
public class Monkey implements Mammal, Primate {
@Override
public String type() {
String type = "哺乳动物";
System.out.println(type);
return type;
}

@Override
public void eat(String food) {
System.out.println("The food is " + food + " !");
}

@Override
public void think() {
System.out.println("思考!");
}
}

MyInvocationHandler

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
public class MyInvocationHandler implements InvocationHandler {
private Object obj;

public MyInvocationHandler(Object obj) {
super();
this.obj = obj;
}

/**
* 获取目标对象的代理对象
*
* @return 代理对象
*/
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), obj.getClass().getInterfaces(), this);
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//代理方法
// #1
System.out.println("Invoke method Before!");
Object returnObject = method.invoke(obj, args);
System.out.println("Invoke method After!");

//测试代理类覆写的方法
// #2
Class<?> c = ((Mammal) proxy).getClass();
Method[] methods = c.getDeclaredMethods();
for (Method m : methods) {
System.out.println(m.getName());
}
return proxy;

}
}

Main

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
public class Main {

public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
System.out.println(System.getProperties().get("sun.misc.ProxyGenerator.saveGeneratedFiles"));

// 第1种创建动态代理的方法
// #3
Object proxy1 = Proxy.newProxyInstance(Monkey.class.getClassLoader(), Monkey.class.getInterfaces(), new MyInvocationHandler(new Monkey()));
// 第2种创建动态代理的方法
// #4
Class<?> proxyClass = Proxy.getProxyClass(Monkey.class.getClassLoader(), Monkey.class.getInterfaces());
Object proxy2 = proxyClass.getConstructor(new Class[]{InvocationHandler.class}).newInstance(new MyInvocationHandler(new Monkey()));
//ProxyGeneratorUtils.writeProxyClassToHardDisk("D:\\$Proxy0.class");

// 第3种创建动态代理的方法
// 实例化目标对象
// #5
Monkey monkey = new Monkey();
// 实例化InvocationHandler
MyInvocationHandler invocationHandler = new MyInvocationHandler(monkey);
// 根据目标对象生成代理对象
Primate primate = (Primate) invocationHandler.getProxy();
primate.think();

Mammal mammal = (Mammal) proxy2;
mammal.eat("香蕉");
mammal.type();
Primate primate2 = (Primate) proxy2;
primate2.think();
}
}
  1. method = public abstract void demo1.Primate.think(),method接口方法;obj=Monkey@663,obj是实现类的对象。这里通过反射调用方法。
  2. c = com.sun.proxy.$Proxy0,在项目目录下生成的代理类对象。
  3. 动态代理生成方式一,proxy1 = ($Proxy@667)Monkey@2b80d80f,动态Proxy Class对象。
  4. 同上,proxyClass = class com.sun.proxy.$Proxy0,proxy2 = ($Proxy@685)Monkey@3ab39c39,动态Proxy Class对象。
  5. 同上
  6. saveGeneratedFiles设置为true,默认会写入磁盘。

    proxy0.class另一种方式写入磁盘

    code

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 获取代理类的字节码  
    byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy11", Monkey.class.getInterfaces());
    FileOutputStream out = null;
    try {
    out = new FileOutputStream(path);
    out.write(classFile);
    out.flush();
    } catch (Exception e) {
    e.printStackTrace();
    } finally {
    try {
    out.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }

分析$Proxy.class

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package com.sun.proxy;

import demo1.Mammal;
import demo1.Primate;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

// #1
public final class $Proxy0 extends Proxy
implements Mammal, Primate
{
private static Method m1;
private static Method m3;
private static Method m5;
private static Method m2;
private static Method m4;
private static Method m0;

// #2
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}

public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

// #3
public final String type()
throws
{
try
{
return (String)this.h.invoke(this, m3, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

// #4
public final void think()
throws
{
try
{
this.h.invoke(this, m5, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

.....

// #5
public final void eat(String paramString)
throws
{
try
{
this.h.invoke(this, m4, new Object[] { paramString });
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

// #6
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("demo1.Mammal").getMethod("type", new Class[0]);
m5 = Class.forName("demo1.Primate").getMethod("think", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m4 = Class.forName("demo1.Mammal").getMethod("eat", new Class[] { Class.forName("java.lang.String") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
  1. $Proxy0继承Proxy,实现Mammal, Primate接口。
  2. 这里是$Proxy0的构造函数,是前文提到的cl.getConstructor(constructorParams)
  3. 就是调用MyInvocationHandlerpublic Object invoke(Object proxy, Method method, Object[] args)。根据上文例子:
    1
    2
    Mammal mammal = (Mammal) proxy2;
    mammal.type()实际上就是调用();

type()实际上就是调用MyInvocationHandler#invoke

  1. 同上。
  2. 同上。
  3. 静态代码块初始化方法,其中3个是接口必需实现的方法,通过覆写接口方法调用InvocationHandler#invoke

    总结

  4. JDK1.8相对JDK1.7,代码结构更加简洁,Proxy Cache Map的key、value都是用简单工厂模式,阅读起来很舒畅。
  5. 源码阅读起来很容易,写笔记真的好累、好累。

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×