Analysis of the implementation principle of Java Dynamic Agent

Source: Internet
Author: User

Code writing
  1. Interface Authoring
    public interface TargetInterface {
    void targetMethod();
    }
  2. Implementing Class Authoring
    public class Target implements TargetInterface {
    @Override
    public void targetMethod() {
    System.out.println("target method invoking ...");
    }
    }
  3. Enhanced class authoring
    public class ProxyHandler implements InvocationHandler {
    private Object proxyTarget;
    public ProxyHandler(Object proxyTarget) {
    this.proxyTarget = proxyTarget;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("do somethings before target method invoke");
    Object result = method.invoke(proxyTarget, args);
    System.out.println("do somethings after target method invoke");
    return result;
    }
    }
  4. Test class Authoring
    public class ProxyTest {
    public static void main(String[] args) {
    System.out.println(Thread.currentThread().getContextClassLoader());
    TargetInterface target = new Target();
    ClassLoader loader = target.getClass().getClassLoader();
    Class<?>[] interfaces = target.getClass().getInterfaces();
    InvocationHandler proxyHandler = new ProxyHandler(target);
    TargetInterface proxyTarget = (TargetInterface) Proxy.newProxyInstance(loader, interfaces, proxyHandler);
    proxyTarget.targetMethod();
    }
    }
Source code Analysis (the source is too much, the ellipsis is expressed by "...")

The Proxytarget enhancement class in the code is made up of proxy.newproxyinstance (...). Generated, view the source code of the method:
``public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException{
...
// step1:从缓存中查找代理类,若未缓存则生成后缓存,否则直接从缓存中获取.
Class<?> cl = getProxyClass0(loader, intfs);
try {
...
//step2:反射生成代理类实例
return newInstance(cons, ih);
...
} catch (NoSuchMethodException e) {
...
}
}

As can be seen in the code, the generation of proxy classes is divided into two main steps:
-Generate proxy class
-Reflection Generation proxy class instance

Step1:
  1. Proxy.getproxyclass0
    private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {
    ...
    // Proxy类中维护了一个WeakCache对象,用于缓存动态生成的类,WeakCache.get方法不仅执行查找操作,当对象不存在时也会执行生成操作,下面来看下该方法的源码
    return proxyClassCache.get(loader, interfaces);
    }
  2. Weakcache.get
    public V get(K key, P parameter) {
    ...
    while (true) {
    if (supplier != null) {
    //已从缓存中查找到对象,直接返回
    V value = supplier.get();
    if (value != null) {
    return value;
    }
    }
    if (factory == null) {
    //已从缓存中查找到对象,且调用该对象的get方法生成代理类后直接返回,get方法实现下文详述
    factory = new Factory(key, parameter, subKey, valuesMap);
    }
    if (supplier == null) {
    //将新生成的对象缓存
    supplier = valuesMap.putIfAbsent(subKey, factory);
    if (supplier == null) {
    supplier = factory;
    }
    } else {
    ...
    }
    }
    }
    }

    This approach is constantly looping and repeating, both of which are taking into account thread safety issues. No further scrutiny is done here.
  3. Faotory.get
    public synchronized V get() {
    ...
    try {
    //实现生成代理类对象,此方法在内部类ProxyClassFactory中实现
    value = Objects.requireNonNull(valueFactory.apply(key, parameter));
    } finally {
    ...
    }
    ...
    return value;
    }
  4. proxyclassfactory.apply
    public Class apply(ClassLoader loader, Class[] interfaces) {
    //校验interfaces
    ...
    String proxyPkg = null;
    ...
    //生成packagename,默认为com.sun.proxy
    if (proxyPkg == null) {
    // if no non-public proxy interfaces, use package
    proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
    }
    //生成classname,采用AutomicLong自增方式
    long num = nextUniqueNumber.getAndIncrement();
    String proxyName = proxyPkg + proxyClassNamePrefix + num;
    // 生成字节码文件
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
    proxyName, interfaces);
    // 调用native方法,加载生成的字节码文件,并返回代理类的引用
    try {
    return defineClass0(loader, proxyName,
    proxyClassFile, 0, proxyClassFile.length);
    } catch (ClassFormatError e) {
    ...
    }
    }

    After the generated Proxyclassfile bytecode is written to the file and deserialized, the information is as follows:

Package Com.sun.proxy. $Proxy;
Import Java.lang.reflect.InvocationHandler;
Import Java.lang.reflect.Method;
Import Java.lang.reflect.Proxy;
Import java.lang.reflect.UndeclaredThrowableException;
Import X.constant.proxy.targetinterface;
Public final Class 1 extends Proxy implements Targetinterface {
private static Method m3;
private static Method M1;
private static Method M0;
private static Method m2;
Public 1 (Invocationhandler Paraminvocationhandler) throws {
Super (Paraminvocationhandler);
}
Public final void Targetmethod () throws {
try {
This.h.invoke (this, M3, null);
Return
}catch (error| RuntimeException localerror) {
Throw localerror;
}catch (Throwable localthrowable) {
throw new Undeclaredthrowableexception (localthrowable);
}
}
Public final Boolean equals (Object paramobject) {
...
}
Public final int hashcode () {
...
}
Public final String toString () throws {
...
}
static {
try {
M3 = Class.forName ("X.constant.proxy.targetinterface"). GetMethod ("Targetmethod", new Class[0]);
M1 = Class.forName ("Java.lang.Object"). GetMethod ("equals", new class[] {class.forname ("Java.lang.Object")});
M0 = Class.forName ("Java.lang.Object"). GetMethod ("Hashcode", new Class[0]);
M2 = Class.forName ("Java.lang.Object"). GetMethod ("ToString", new Class[0]);
Return
}catch (Nosuchmethodexception localnosuchmethodexception) {
throw new Nosuchmethoderror (Localnosuchmethodexception.getmessage ());
}
catch (ClassNotFoundException localclassnotfoundexception)
{
throw new Noclassdeffounderror (Localclassnotfoundexception.getmessage ());
}
}
}

As you can see, the class is located under the Com.sun.proxy. $Proxy package, inherits the proxy object and implements our custom Targetinterface interface; The constructor requires a Invocationhandler object as a parameter The enhanced Targetmethod method invokes the Invoke method of the Invocationhandler object.

Step2

The enhanced class information is loaded into the JVM and gets a reference to the class, and the proxy class object is generated by invoking the constructor of the class using the reflection mechanism and passing in our custom Invocationhandler object as a parameter, which is no longer parsed.

By reading the source code, we can find the implementation process of the Java Dynamic Agent:
1. Dynamically generate a proxy class for the interface according to interface, and implement the method defined in interface by invoking the Invoke method in Invocationhandler
2. Dynamically load the proxy class and get the object of the proxy class in a reflection manner.
In the final analysis, its implementation is also achieved through bytecode generation ASM technology.

Analysis of the implementation principle of Java Dynamic Agent

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.