Proxy is a common design pattern whose purpose is to provide other objects with a proxy to control access to an object. The proxy class is responsible for preprocessing messages for the delegate class, filtering and forwarding messages, and for subsequent processing of messages after they are executed by the delegate class.

In order to maintain consistency of behavior, proxy classes and delegate classes often implement the same interface, so there is no difference between them to visitors. Through the middle layer of proxy class, it can effectively control the direct access to the delegate class object, and also can hide and protect the delegate class object well. At the same time, it also reserves space for the implementation of different control strategies, so as to obtain greater flexibility in the design. The Java dynamic proxy mechanism practices the design philosophy of the proxy pattern almost perfectly in a clever way.

Java dynamic proxy classes are located under the java.lang.Reflect package and generally involve the following two classes:

(1) Interface InvocationHandler:

Only one method is defined in this interface

 public object invoke(Object obj,Method method, Object[] args) 

In practice, the first parameter obj generally refers to the proxy class, method is the proxy method, as in the example above, request(), args is the parameter array of the method. This abstract method is implemented dynamically in the proxy class.

(2)Proxy: this class is a dynamic Proxy class, which mainly contains the following contents:

Protected Proxy(InvocationHandler H) : constructor that assigns a value to the internal H.

Static Class getProxyClass (ClassLoaderloader, Class[] interfaces) : Gets a proxy Class where loader is the classloader and interfaces are an array of all interfaces owned by the real Class.

Static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h) : Returns an instance of the proxy class that can be used as the proxied class (using the proxied class’s methods declared in the Subject interface)

Dynamic proxy steps:

1. Create a class that implements the interface InvocationHandler, which must implement the Invoke method

2. Create proxied classes and interfaces

3. Create a Proxy using the Proxy static method newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)

4. Invoke methods through proxies

Public static void main(String[] args) {// realSubject = new realSubject (); /** * InvocationHandlerImpl implements the InvocationHandler interface and can dispatch and forward method calls from the proxy class to the delegate class. */ InvocationHandler Handler = new InvocationHandlerImpl(realSubject); ClassLoader loader = realSubject.getClass().getClassLoader(); Class[] interfaces = realSubject.getClass().getInterfaces(); /** * This method is used to generate dynamic Proxy class instances for the specified class loader, a set of interfaces, and the calling handler */ Subject Subject = (Subject) proxy. newProxyInstance(loader, interfaces, handler); System.out.println(" Dynamic proxy object type: "+subject.getClass().getName()); String hello = subject.SayHello("hello"); System.out.println(hello); } @CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<? >[] interfaces, InvocationHandler h) throws IllegalArgumentException {// If h is not null, throw exception objects.requirenonnull (h); final Class<? >[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm ! = null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Get the proxy Class type object */ Class<? > cl = getProxyClass0(loader, intfs); /* * Get the constructor object by reflection and generate the proxy class instance */ try {if (sm! = null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } // Get the proxy object Constructor (i.e. $Proxy0(InvocationHandler h)) 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; }}); } // Generate an instance of the proxy class and pass InvocationHandlerImpl to its constructor 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); }}Copy the code

The key method is getProxyClass0, which first checks whether the proxy class has been generated from the cache. If not, the bytecode of the proxy class is generated and then added to the cache for the convenience of finding it next time, thus improving the running efficiency of the program.

/ / generated bytecode byte [] proxyClassFile = ProxyGenerator. GenerateProxyClass (proxyName, interfaces, accessFlags); 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()); }Copy the code
  • Conclusion:

  • Dynamic proxy classes: Dynamically generated by reflection while the program is running.

  • Dynamic proxy classes typically proxy all classes under an interface.

  • Dynamic proxies do not know in advance what is being proxied, only at run time.

  • A dynamic Proxy InvocationHandler must first InvocationHandler interface and dynamically create the Proxy class using the newProxyInstance method in the Proxy class.

  • Java dynamic proxy can only proxy interfaces. To proxy classes, you need to use third-party libraries such as CLIGB.

Java dynamic proxies have the advantage of non-invasive code extensions, that is, method enhancements; Allows you to enhance some methods without modifying the source code; You can do whatever you want before or after a method (even without executing the method). In addition, it can also reduce the amount of code, if the use of static proxy, class methods more when you have to write a lot of code.