The emergence of Java dynamic proxy mechanism allows Java developers to dynamically obtain proxy classes without manually writing proxy classes. They can simply specify a set of interfaces and delegate class objects. (Recommended:java video tutorial)
The proxy class will be responsible for dispatching all method calls to the delegate object for reflection execution. During the dispatch execution process, developers can also adjust as needed Delegate class objects and their functions, this is a very flexible and flexible proxy framework. Next we start learning about dynamic agents.
Brief description of dynamic proxy
In the dynamic proxy mechanism of java, there are two important classes or interfaces, one is InvocationHandler( Interface), the other is Proxy (Class).
1. Description of InvocationHandler (interface):
InvocationHandler is the interface implemented by the invocation handler of a proxy instance. Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.
Every dynamic proxy class must implement the InvocationHandler interface, and each proxy class instance is associated with When we reach a handler, when we call a method through the proxy object, the call of this method will be forwarded to be called by the invoke method of the InvocationHandler interface. Let’s take a look at the only method of the InvocationHandler interface, the invoke method:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
This method receives three parameters and returns an Object type. Their respective meanings are as follows:
proxy: refers to The real object we are proxying for
method: refers to the Method object we want to call the method of the real object
args: refers to the parameters received when calling a method of the real object The Object returned by parameter
refers to the return type of the real object method. The above will be understood in depth in the following examples.
the value to return from the method invocation on the proxy instance.
2. Description of Proxy (Class):
Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.
The function of Proxy class is to dynamically create a proxy object. We often use the newProxyInstance method:
public static Object newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h) throws IllegalArgumentException
Understanding of parameters:
// 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载 loader - the class loader to define the proxy class // 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口 interfaces - the list of interfaces for the proxy class to implement // 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上 h - the invocation handler to dispatch method invocations to
Understanding of return results: An instance of a proxy object
a proxy instance with the specified invocation handler of a proxy class that is defined by the specified class loader and that implements the specified interfaces
Simple Java proxy
We create a Java project for testing and understanding of dynamic proxy, The project structure is as follows:
# 1. First define an interface Interface and add two methods.
package com.huhx.proxy; public interface Interface { void getMyName(); String getNameById(String id); }
2. Define a real class that implements the above interface, RealObject:
package com.huhx.proxy; public class RealObject implements Interface { @Override public void getMyName() { System.out.println("my name is huhx"); } @Override public String getNameById(String id) { System.out.println("argument id: " + id); return "huhx"; } }
3. Define a proxy object, which is also implemented The above Interface interface:
package com.huhx.proxy; public class SimpleProxy implements Interface { private Interface proxied; public SimpleProxy(Interface proxied) { this.proxied = proxied; } @Override public void getMyName() { System.out.println("proxy getmyname"); proxied.getMyName(); } @Override public String getNameById(String id) { System.out.println("proxy getnamebyid"); return proxied.getNameById(id); } }
4. SimpleMain In the Main method, test the above results:
package com.huhx.proxy; public class SimpleMain { private static void consume(Interface iface) { iface.getMyName(); String name = iface.getNameById("1"); System.out.println("name: " + name); } public static void main(String[] args) { consume(new RealObject()); System.out.println("========================================================"); consume(new SimpleProxy(new RealObject())); } }
5. The running results are as follows :
my name is huhx argument id: 1 name: huhx ======================================================== proxy getmyname my name is huhx proxy getnamebyid argument id: 1 name: huhx
Java’s dynamic proxy
After completing the above simple Java proxy, now we start to learn Java’s dynamic proxy, It goes one step further than the idea of proxies because it can dynamically create proxies and dynamically handle calls to the proxied methods. All calls made on the dynamic proxy are redirected to a single call handler, whose job is to reveal the type of call and determine the appropriate countermeasure. Below we use cases to deepen our understanding of Java dynamic proxies:
1. Create a processor that inherits InvocationHandler: DynamicProxyHandler
package com.huhx.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Arrays; public class DynamicProxyHandler implements InvocationHandler { private Object proxied; public DynamicProxyHandler(Object proxied) { System.out.println("dynamic proxy handler constuctor: " + proxied.getClass()); this.proxied = proxied; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("dynamic proxy name: " + proxy.getClass()); System.out.println("method: " + method.getName()); System.out.println("args: " + Arrays.toString(args)); Object invokeObject = method.invoke(proxied, args); if (invokeObject != null) { System.out.println("invoke object: " + invokeObject.getClass()); } else { System.out.println("invoke object is null"); } return invokeObject; } }
2. We write A test Main method, DynamicProxyMain:
package com.huhx.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import com.huhx.proxy.Interface; import com.huhx.proxy.RealObject; public class DynamicProxyMain { public static void consumer(Interface iface) { iface.getMyName(); String name = iface.getNameById("1"); System.out.println("name: " + name); } public static void main(String[] args) throws Exception, SecurityException, Throwable { RealObject realObject = new RealObject(); consumer(realObject); System.out.println("=============================="); // 动态代理 ClassLoader classLoader = Interface.class.getClassLoader(); Class>[] interfaces = new Class[] { Interface.class }; InvocationHandler handler = new DynamicProxyHandler(realObject); Interface proxy = (Interface) Proxy.newProxyInstance(classLoader, interfaces, handler); System.out.println("in dynamicproxyMain proxy: " + proxy.getClass()); consumer(proxy); } }
3. The running results are as follows:
my name is huhx argument id: 1 name: huhx ============================== dynamic proxy handler constuctor: class com.huhx.proxy.RealObject in dynamicproxyMain proxy: class com.sun.proxy.$Proxy0 dynamic proxy name: class com.sun.proxy.$Proxy0 method: getMyName args: null my name is huhx invoke object is null dynamic proxy name: class com.sun.proxy.$Proxy0 method: getNameById args: [1] argument id: 1 invoke object: class java.lang.String name: huhx
From the above output results, we can draw the following conclusions:
The InvocationHandler associated with the proxy object will execute its invoke method only when the proxy object calls a method.
Understanding of the three parameters of invoke: Object proxy is the object of the proxy, Method method is the Method class that calls the method in the real object, Object[] args is the parameters of the method that is called in the real object
The principle of Java dynamic proxy
1. The key code of dynamic proxy is Proxy.newProxyInstance(classLoader, interfaces, handler). Let’s follow the source code and take a look:
public static Object newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h) throws IllegalArgumentException { // handler不能为空 if (h == null) { throw new NullPointerException(); } 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. */ // 通过loader和接口,得到代理的Class对象 Class> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { final Constructor> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) { // create proxy instance with doPrivilege as the proxy class may // implement non-public interfaces that requires a special permission return AccessController.doPrivileged(new PrivilegedAction
2. Let’s take a look Source code of newInstance method:
private static Object newInstance(Constructor> cons, InvocationHandler h) { try { return cons.newInstance(new Object[] {h} ); } catch (IllegalAccessException | InstantiationException e) { throw new InternalError(e.toString()); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString()); } } }
3. When we call a method through the proxy object, the call of this method will be forwarded to the invoke method of the InvocationHandler interface. transfer.
I couldn’t find the code that reflected this sentence in the source code, so I added the following code to the main method of the test class:
if (proxy instanceof Proxy) { InvocationHandler invocationHandler = Proxy.getInvocationHandler(proxy); invocationHandler.invoke(proxy, realObject.getClass().getMethod("getMyName"), null); System.out.println("--------------------------------------"); }
这段代码的输出结果如下,与上述中调用代理对象中的getMyName方法输出是一样的,不知道Jvm底层是否是这样判断的:
dynamic proxy handler constuctor: class com.huhx.proxy.RealObject dynamic proxy name: class com.sun.proxy.$Proxy0 method: getMyName args: null my name is huhx invoke object is null --------------------------------------
更多java知识请关注java基础教程栏目。
The above is the detailed content of The principle of Java dynamic proxy. For more information, please follow other related articles on the PHP Chinese website!