Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the principle of JDK dynamic agent

2025-04-10 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/02 Report--

What is the principle of JDK dynamic agent? aiming at this problem, this article introduces the corresponding analysis and solution in detail, hoping to help more partners who want to solve this problem to find a more simple and feasible method.

The use of JDK dynamic Agent and the underlying Analysis of the principle

Java's implementation of the design pattern, the proxy pattern, can only be proxied for interfaces. Proxy mode: provides a proxy object to hold a reference to the target object, through the operation of the proxy object can achieve the purpose of manipulating the target object. The main reason for using the proxy mode is that the user does not want or cannot directly manipulate the target object, and an intermediate object of the agent is needed to maintain contact. For example, the Mapper interface in Mybatis does not have an implementation class, so consumers cannot directly manipulate the implementation class, so a proxy Mapper is generated. For example, Bean in Spring AOP, the user wants to enhance the use of Bean or other processing, so Spring needs to return a proxy Bean to achieve the purpose.

Interface 1:

Public interface ITodo {void doString (String desc);}

Once realized:

Public class Todo implements ITodo {@ Override public void doString (String desc) {System.out.println ("doString:" + desc);}}

Goal, to enhance the original method of the interface. Implementation: JDK dynamic proxy

An agent tool class:

Public class ProxyInstance implements InvocationHandler {/ / proxy target, that is, the proxy class private Object target; / / proxy class holds the proxy class public ProxyInstance (Object target) {this.target = target;} public T getProxy () {/ / get the instance, here use newProxyInstance return (T) Proxy.newProxyInstance (target.getClass (). GetClassLoader (), target.getClass (). GetInterfaces (), this) } / / here is the agent's processing flow @ Override public Object invoke (Object proxy, Method method, Object [] args) throws Throwable {System.out.println ("proxy before"); Object obj=method.invoke (target,args); System.out.println ("proxy after"); return obj }} Test class: public class Test {public static void main (String [] args) {/ / Open the code System.getProperties (). Put ("sun.misc.ProxyGenerator.saveGeneratedFiles", "true") that generates the file in the save agent; ITodo todo = new ProxyInstance (new Todo ()). GetProxy (); todo.doString ("- nothing-") Console: proxy beforedoString:-nothing-proxy after

Through the console, you can see that the original methods of the interface have been enhanced, and other code is executed before and after the method execution. This is the dynamic proxy function of JDK. The usage components of JDK dynamic proxy: an interface, an implementation, an agent tool class, and need to follow the following rules:

The agent tool class holds the target class

Passed in as a parameter

The agent tool class needs to implement interface InvocationHandler

The proxy class needs to use the constructor of Proxy to get the instance

Generally use newProxyInstance

Define agent processing logic

Methods for generating proxy classes through reflection

So only methods defined in the interface can be proxied.

All methods of the interface will be rewritten to the final type

Used to load the newly generated proxy class $Proxy {n}

Parameter 1: class loader

Parameter 2: interface Class array

Parameter 3: InvocationHandler interface implementation class

The construction parameter is the interface implemented by the proxied class

The object called by the proxy class is an instance generated by the Proxy class and is not the same object as the proxied class.

Each call needs to be called through reflection

The proxy tool class needs to override the invoke method

Public Object invoke (Object proxy, Method method, Object [] args)

The proxy object $Proxy {n} generated by proxy for JDK is therefore dynamic and exists only in memory

Method calls methods for JDK such as reflection acquisition

Args is the parameter of the calling method

Because the class is generated, all require the class loader to reload

Bottom principle analysis

For the above example, the source code of the generated proxy class is as follows

The package com.sun.proxy;import cn.tinyice.demo.proxy.jdk.ITodo;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;// proxy object integrates java.lang.reflect.Proxy and implements the parent interface of the proxied object / / the location of the method is adjusted here to facilitate the analysis of public final class $Proxy0 extends Proxy implements ITodo {private static Method M1; private static Method m2; private static Method m3 Private static Method m0; static {/ / needs to rewrite the equals, toString, hashCode and target methods of the interface, so first get the runtime representation of the original method java.lang.reflect.Method try {M1 = Class.forName ("java.lang.Object"). GetMethod ("equals", Class.forName ("java.lang.Object")) M2 = Class.forName ("java.lang.Object"). GetMethod ("toString"); m3 = Class.forName ("cn.tinyice.demo.proxy.jdk.ITodo"). GetMethod ("doString", Class.forName ("java.lang.String")); M0 = Class.forName ("java.lang.Object"). GetMethod ("hashCode");} catch (NoSuchMethodException var2) {throw new NoSuchMethodError (var2.getMessage ()) } catch (ClassNotFoundException var3) {throw new NoClassDefFoundError (var3.getMessage ());}} / / Constructor input parameter: InvocationHandler instance is the proxy class instance public $Proxy0 (InvocationHandler var1) throws {/ / determines that InvocationHandler is not empty, and then assigns the variable h super (var1) } / /-Agent main concern: target method rewriting-public final void doString (String var1) throws {try {/ / super.h=InvocationHandler instance Call its invoke method, which determines the source of three parameters for the user's rewritten method: Object array of method,args= parameters of proxy=this,method = target (type conversion occurs) super.h.invoke (this, m3, new Object [] {var1}) } catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException (var4) }} / /-equals, toString, hashCode rewrite, actually call the corresponding method of InvocationHandler-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 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);}

The source code is mainly divided into four parts.

Proxy class definition:

The newly generated proxy class is defined as: public final class $Proxy0 extends Proxy implements ITodo {...}, which is to regenerate a new interface implementation class and copy and enhance the functions of the original implementation class.

Static block initialization methods for equals, hashCode, toString and original implementation classes

Equals, hashCode, and toString are Object methods, which are mainly used to verify the uniqueness of the Java object, which is no longer the same memory address as the original implementation class and other operations.

DoString is the original method that implements the class.

The constructor is passed into InvocationHandler

InvocationHandler is the code written by the user, and this step is to cut into the

Override all methods defined in static blocks

All overridden methods have become final types. All methods call the invoke method of InvocationHandler. So this invoke method is the core method of enhancement.

By understanding the above, you can basically understand the underlying principles of JDK dynamic agents. In a word: rewrite method calls custom invoke to achieve enhancement

Source code generation process

Call entry: get the proxy class

Public static Object newProxyInstance (ClassLoader loader,Class [] interfaces, InvocationHandler h) throws IllegalArgumentException {...}

Core generation?

Class cl = getProxyClass0 (loader, intfs)

ProxyClassCache.get (loader, interfaces)

ProxyClassCache is statically defined in the Proxy class

Private static final WeakCache > proxyClassCache = new WeakCache (new KeyFactory (), new ProxyClassFactory ()); proxyClassCache description:

WeakCache instance, a weak reference cache object. The storage structure is as follows, which is the three object storage of K _

ConcurrentMap map = new ConcurrentHashMap ()

This object requires two factory classes, one for generating subKey and one for generating value

KeyFactory and ProxyClassFactory are all BiFunction.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report