JDK Java design patterns principle of dynamic proxies

The core source to achieve dynamic proxy
public Object The getProxy () {
// use JDK dynamic proxy
return the Proxy.newProxyInstance (
this.getClass (). GetClassLoader (),
target.getClass (). The getInterfaces (),
the this // interface of InvocationHandler custom implementation class
);
}
. 1
2
. 3
. 4
. 5
. 6
. 7
. 8
using JDK dynamic proxy, since the first to implement class InvocationHandler interface, the control logic to write the proxy class.

Example:

public class JDKDynamicProxyHandler implements InvocationHandler {

private Object target;

public JDKDynamicProxyHandler(Class clazz) {
try {
this.target = clazz.getDeclaredConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

preAction();
Object result = method.invoke(target, args);
postAction();
return result;
}

public Object getProxy() {
return Proxy.newProxyInstance(
this.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this
);
}

private void preAction() {
System.out.println("JDKDynamicProxyHandler.preAction()");
}

void postAction Private () {
System.out.println ( "JDKDynamicProxyHandler.postAction ()");
}
}
. 1
2
. 3
. 4
. 5
. 6
. 7
. 8
. 9
10
. 11
12 is
13 is
14
15
16
. 17
18 is
. 19
20 is
21 is
22 is
23 is
24
25
26 is
27
28
29
30
31 is
32
33 is
34 is
35
36
37 [
particularly during use, only by acquiring the proxy class

Proxy the Proxy.newProxyInstance = Object (
this.getClass () getClassLoader (),.
Target.getClass () The getInterfaces (),.
InvocationHandler);
. 1
2
. 3
. 4
of this code in the core logic of newProxyInstance Proxy.

JDK8 dynamic proxy implementation.

Object 'newProxyInstance static public (ClassLoader Loader,
<?> Class [] the interfaces,
of InvocationHandler H)
throws an IllegalArgumentException
{
// ...
// clone interface bytecode
final Class [] intfs = interfaces.clone ( ) <?>;
// ...
// obtain or generate the specified class from the proxy cache
class Cl = getProxyClass0 (Loader, intfs) <?>;
the try {
// Get constructor
<?> final constructor cons = cl.getConstructor (constructorParams) ;
Final of InvocationHandler the IH = H;
// the parameters are proxy constructed proxy class constructor
return cons.newInstance ({H} new new Object []);
}
// ...
}

<?> class Private static getProxyClass0 (ClassLoader Loader,
Class <?> ... in the interfaces) {
// ...The number of interfaces can not be more than 65,535
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}

WeakCache // <ClassLoader, Class <> [], Class <>> = proxyClassCache new new WeakCache <> (the KeyFactory new new (), new new ProxyClassFactory ());??
// if the specified class loader has been implemented to generate the proxy class, so get a copy directly from the cache, or create a new agency implementation class.
proxyClassCache.get return (Loader, the interfaces);
}

// proxyClassCache get methods
public V get (K key, P parameter) {

//...key is classloader, parameter interface for the Class array
// delete obsolete entry
expungeStaleEntries ();
// constructor CacheKey key is null, cacheKey the Object object, otherwise phantom reference objects
Object cacheKey = CacheKey.valueOf (key, refQueue);

// The secondary cache loading cacheKey
ConcurrentMap <Object, Supplier <V >> = valuesMap as map.get (cacheKey);
IF (valuesMap == null) {
// If not, the secondary cache configured
ConcurrentMap <Object, Supplier < >> oldValuesMap V
= map.putIfAbsent (cacheKey,
valuesMap of ConcurrentHashMap new new = <> ());
IF (! oldValuesMap = null) {
// If for concurrency, returns the map cache, the cache map assigned to the original valuesMap
valuesMap oldValuesMap =;
}
}

// Construct two cache Key, SubKey
Object SubKey = Objects.requireNonNull (subKeyFactory.apply (Key, Parameter));
// Get the proxy class generated proxy class factory
Supplier <V> = valuesMap.get Supplier (SubKey);
Factory's factory = null;

the while (to true) {
// cycle generated proxy class acquisition proxy class factory
IF (Supplier! = null) {
// If the proxy class factory is not empty, obtaining the proxy class through the get method. The supplier of the inner class WeakCache Factory's
V supplier.get value = ();
IF (= null value!) {
Return value;
}
}

IF (Factory == null) {
// proxy factory class is null, creating a proxy factory class
= new new Factory's 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);
}
}
}
}

// Factory get methods
public get the synchronized V () {// the serialize Access
// Re-Check
Supplier <V> = valuesMap.get Supplier (SubKey);
IF (! = Supplier the this) {
// wait if concurrent when there is a change, it returns null, continue to implement the outer loop.
null return;
}
// Create a new proxy class
V value = null;
the try {
// proxy class generated by the apply method ProxyClassFactory
value = Objects.requireNonNull (valueFactory.apply (Key, Parameter));
} the finally {
IF (value null ==) {// Remove US ON failure
valuesMap.remove (SubKey, the this);
}
}
// packed with CacheValue value value (proxy class)
CacheValue <V> = new new CacheValue cacheValue <> (value);

//将cacheValue放入reverseMap
reverseMap.put(cacheValue, Boolean.TRUE);
return value;
}

//ProxyClassFactory类的apply方法
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

The Map <Class <>, Boolean?> InterfaceSet new new IdentityHashMap = <> (interfaces.length);
// check class is correct, check whether the class is whether interface, check class repeat
// ...
// proxy class the package name
String proxyPkg = null; // package to define proxy class in
the access modifier // proxy class
int AccessFlags = Modifier.PUBLIC | Modifier.FINAL;
// record being modified non-public proxy class interfaces, used as package name of the proxy class, and verify that all non-public proxy is modified class interface must be in the same package name
for (intf class <?>: in the interfaces) {
int flags intf.getModifiers = ();
! IF (Modifier.isPublic (the 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 there is no non-public interface class, package names Package using com.sun.proxy
proxyPkg ReflectUtil.PROXY_PACKAGE + = ".";
}

/ *
. * A name for the Choose to Generate The Proxy class
* /
Long nextUniqueNumber.getAndIncrement NUM = ();
// configured proxy class name, class package name prefix + + proxy agent class name as a value from the
String proxyName = proxyPkg + proxyClassNamePrefix + num;

// generates a proxy class bytecode file
byte [] = proxyClassFile ProxyGenerator.generateProxyClass (
the proxyName, the interfaces, AccessFlags);
the try {
// proxy class generated by the native methods
return defineClass0 (Loader, the proxyName,
proxyClassFile, 0, proxyClassFile. length);
}
// ...
}
. 1
2
. 3
. 4
. 5
. 6
. 7
. 8
. 9
10
. 11
12 is
13 is
14
15
16
. 17
18 is
. 19
20 is
21 is
22 is
23 is
24
25
26 is
27
28
29
30
31 is
32
33 is
34 is
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160.
161
162
163
164 is
165
166
167 is
168
169
170.
171 is
172
summarizes
Proxy.newProxyInstance proxy class acquisition process execution method:
Proxy.getProxyClass0 () method to get the proxy class class.

WeakCache.get () method
CacheKey.valueOf (key, refQueue) acquires a cache key, cacheKey.
ConcurrentMap.get () method to get the secondary cache ConcurrentMap.
KeyFactory generating secondary cache key, subKey.
ConcurrentMap.get () method to get the secondary cache value, Supplier implementation class Factory.
Factory does not exist, generating a new Factory by new Factory.
Examples of the secondary cache acquires CacheValue get a value obtained by the method of Factory.
Examples Factory Supplier acquired by the internal cache ConcurrentMap.get () method.
Supplier if it does not exist () method to generate the proxy class by class ProxyClassFactory.apply.
Use cacheValue proxy class packaging class.
Class.getConstructor (InvocationHandler.class) have acquired parameters (of InvocationHandler) constructor.

Constructor.newInstance (InvocationHandler) to obtain the proxy class.

Proxy class package name: determined by a defined interface modifier proxy class is implemented, if there is a non-public modifier, where the package is called a non-public packet interface path. If a plurality of non-public modifier of interfaces that must be in the same package. If you are all public interface, then package called com.sun.proxy.

Type the full path name of the proxy class: package name + proxy class name prefix ($ Proxy) + increment digit.

Internal Proxy uses multilevel cache caching proxy class generated class, to avoid repeatedly generating the same proxy class, thereby improving performance.

Cache class is used WeakCache.

// Initialization
? Private static Final WeakCache <ClassLoader, Class <> [], Class <>>?
ProxyClassCache new new WeakCache = <> (the KeyFactory new new (), new new ProxyClassFactory ());
. 1
2
. 3
a cache key is CacheKey , CacheKey the classloader and refQueue (reference queue) configuration.

A cache value is ConcurrentMap <Object, Supplier>.

Secondary cache key, subKey, generated by subKeyFactory (KeyFactory) interface is factory classes based on the number of agent classes.

Supplier secondary cache value is the implementation class, Factory.

Proxy class class () method for obtaining a secondary cache get, finally generated proxy class is a class of ProxyClassFactory apply method, a method of generating the byte code files apply, Class finally generated by invoking native methods defineClass0.

Acting class after class of anti-compiled code
Note: To see the decompiled class files, need to add a system variable, sun.misc.ProxyGenerator.saveGeneratedFile is true, can also be specified in the test manual System.getProperties code () .put ( "sun.misc.ProxyGenerator.saveGeneratedFiles", "true ");


package com.sun.proxy;

import com.xt.design.pattern.proxy.dynamic.jdk.HelloService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements HelloService {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;

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

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

public final void sayHello() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}

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

static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.xt.design.pattern.proxy.dynamic.jdk.HelloService").getMethod("sayHello");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}

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 is
62 is
63 is
64
65
66
67
68
69
70
71 is
72
73 is
seen from the proxy class file the generated class:

Proxy proxy class inherits the class, proxy class to implement the interface
proxy class and there have Proxy argument constructor, and the parameters for the InvocationHandler object.
Proxy class to call methods are invoked by InvocationHandler.
Method returns the object type of packaging is, if the original is returned to the basic data types, such as int, it is converted into a packaging return.
The reason JDK dynamic proxy is required proxy class must implement the interface is: generated proxy class to inherit Proxy, Java is a single inheritance, implement, we can only generate a proxy class that implements the interface through.

But why proxy class to inherit Proxy? ? ? Proxy inherited just received a reference structure, which will InvocationHandler passed, specific methods are invoked by InvocationHandler come, why not refer directly to InvocationHandler, thus avoiding the inherent limitations of single agent class must implement the interface to be brought?

On Stack Overflow some people say this is the standard.
--------------------- 

Guess you like

Origin www.cnblogs.com/ly570/p/10954516.html