JDK Dynamic Agent

Source: Internet
Author: User

Simply put, the proxy pattern is to add a layer of proxy objects between the target object and the Access object, and all the Access objects implement the call to the target object through the proxy object.

The proxy object and the target object implement the same interface, and the proxy object invokes the target object, and for the outside, the proxy object can override the target object being called. In this way, the proxy object can add additional logic to normal access, such as caching, permission control, logging, and so on.

But this static proxy mode needs to add additional proxy class implementation, Java 5 began to introduce a dynamic agent mechanism, implemented at runtime to create a proxy object dynamically, which is actually a method call interception, AOP is the use of this model.


examples of use of dynamic proxies

Package com.dynamic.jdk;

/**
* Interface definition for Target class
* <p/>
* Created by Vincent Tse on 12/2/15.
*/
Public interface MyInterface {
void DoSomething ();
}
Package com.dynamic.jdk;

/**
* Specific implementation of the target class
* <p/>
* Created by Vincent Tse on 12/2/15.
*/
public class Myinterfaceimpl implements MyInterface {

@Override
public void dosomething () {
System.out.println ("Here is my real operation!");
}
}
Package com.dynamic.jdk;

Import Java.lang.reflect.InvocationHandler;
Import Java.lang.reflect.Method;

/**
* Custom Invocationhandler
* Encapsulation of specific calling procedures
* <p/>
* Created by Vincent Tse on 12/2/15.
*/
public class Myinvocationhandler implements Invocationhandler {
Target is the object that actually executes the method
Private Object target;

Public Myinvocationhandler (Object target) {
Super ();
This.target = target;
}

/**
* Methods for proxy object invocation
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public object invoke (object proxy, Method method, object[] args) throws Throwable {
System.out.println ("Before Target ' s operation!");
Object result = Method.invoke (target, args);
SYSTEM.OUT.PRINTLN ("After Target ' s operation");
return result;
}
}
Package com.dynamic.jdk;

Import Java.lang.reflect.Proxy;

/**
* Test class
* <p/>
* Created by Vincent on 12/2/15.
*/
public class Dynamictest {

public static void Main (string[] args) {

Build target Object
MyInterface MyInterface = new Myinterfaceimpl ();

Instantiates an Invocationhandler object, passing in the target object
Myinvocationhandler Invocationhandler = new Myinvocationhandler (MyInterface);

Invoke Proxy's method to generate agent object
MyInterface proxy = (myinterface) proxy.newproxyinstance (Myinterface.getclass (). getClassLoader (),
New Class[]{myinterface.class}, Invocationhandler);

Methods for invoking Proxy objects
Proxy.dosomething ();
}
}

Output Result:

Before Target ' s operation!

Here is my real operation!

After Target ' s operation!


Easy to use, then see the source code analysis of the Principles

Starting with the Newproxyinstance () method of proxy, this method is used to generate the proxy object, which needs to pass in the ClassLoader, the implemented interface, and a Invocationhandler object.

public static Object newproxyinstance (ClassLoader loader,
Class<?>[] interfaces,
Invocationhandler h)
Throws IllegalArgumentException
{
Objects.requirenonnull (h);

Final class<?>[] Intfs = Interfaces.clone ();
Final SecurityManager sm = System.getsecuritymanager ();
if (SM! = null) {
Checkproxyaccess (Reflection.getcallerclass (), loader, intfs);
}

Generating a proxy class from an incoming class loader and implementation interface
class<?> cl = GETPROXYCLASS0 (loader, intfs);

/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (SM! = null) {
Checknewproxypermission (Reflection.getcallerclass (), CL);
}
Reflection gets the constructor of the proxy class
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;
}
});
}
The reflection generates an instance, passes the Invocationhandler in, and then invokes the Invoke method on it.
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);
}
}


GetProxyClass0 () method is used to generate the proxy class, first check the implementation of the number of interfaces, more than 65535 to throw an exception, the sense should not have implemented so many interfaces of the class bar.

private static class<?> GetProxyClass0 (ClassLoader loader,
Class<?> interfaces) {
if (Interfaces.length > 65535) {
throw new IllegalArgumentException ("Interface limit exceeded");
}

Gets the proxy class from a cache and rebuilds if not
return Proxyclasscache.get (loader, interfaces);
}


Proxyclasscache is a static weakcache, defined in the proxy class.

There are two factory in the Weakcache, one is Subkeyfactory, is a mapping function (key, parameter)->sub-key, and the other is valuefactory, which is a mapping function (key, parameter)->value. The Get method of Weakcache requires two parameters, one is key and the other is parameter.

The use and principle of specific weakcache is not mentioned here, please refer to the source code.

Private static final Weakcache<classloader, class<?>[], class<?>>
Proxyclasscache = new Weakcache<> (new Keyfactory (), New Proxyclassfactory ());

the incoming keyfactory and proxyclassfactory are static classes defined in the proxy class, respectively, corresponding to the the Subkeyfactory and valuefactory in Weakcache implement the Bifunction interface and implement the Apply () method. What is done in Proxyclassfactory's apply () method is to generate the logic of the proxy class, and most crucially

byte[] Proxyclassfile = Proxygenerator.generateproxyclass (
Proxyname, interfaces, AccessFlags);

The above method is used to generate the byte code of the proxy class, the proxy class will have an interface implementation method, in the implementation of the method will invoke the Invocationhandler invoke () method, interested in the generated bytecode can be written to the local, with the anti-compilation tool to open the look.


so When is Proxyclassfactory's apply () method called, back to Weakcache's Get () method

Generate subkey to get the corresponding supplier
Object subkey = Objects.requirenonnull (Subkeyfactory.apply (key, parameter));
supplier<v> Supplier = Valuesmap.get (subkey);
Factory Factory = null;
Loop until value is obtained from supplier
Generate factory without supplier and add it to the cache (the source says it is an install process)
while (true) {
if (supplier! = NULL) {
V value = Supplier.get ();
if (value = null) {
return value;
}
}

if (factory = = null) {
Factory is an internal class that implements the supplier interface and implements the Get () method
The Apply () method of Valuefactory (aka Proxyclassfactory) is actually called in the Get () method
You can debug it in.
Factory = new Factory (key, parameter, subkey, VALUESMAP);
}

if (supplier = = NULL) {
Supplier = Valuesmap.putifabsent (subkey, Factory);
if (supplier = = NULL) {
supplier = Factory;
}
} else {
if (Valuesmap.replace (subkey, supplier, Factory)) {
supplier = Factory;
} else {
Supplier = Valuesmap.get (subkey);
}
}
}

good hard, finally generated the proxy class, back to The Newproxyinstance method, which has a class object of the proxy class, can be used to generate an instance by reflection (called a constructor with the Invocationhandler parameter), and then the proxy object is created after the instance is generated.

This article is from the "Shephenson Technology blog" blog, make sure to keep this source http://vincettse.blog.51cto.com/6578391/1720947

JDK 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.