Dynamic agent principle and source code analysis based on CGLIB implementation

Source: Internet
Author: User
Tags aop constructor throwable
CGLIB Introduction: CGLIB (Code Generation Library) is an open source project. is a powerful, high-performance, high-quality code generation class library that can extend Java classes and implement Java interfaces at run time. Hibernate uses it to implement the dynamic generation of the PO (persistent object persisted) bytecode. Problem analysis for JDK agent: The agent provides a way to control the target object to be accessed. When an object is accessed, it introduces an indirect layer. The JDK has introduced dynamic proxies since the 1.3 release and is often used to dynamically create proxies. The dynamic proxy for the JDK is very simple to use, but it has a limitation that objects that use dynamic proxies must implement one or more interfaces. What to do if you want to delegate an inherited class that does not implement an interface. Now we can use the Cglib package to implement.
Cglib Use Description: Cglib is a powerful, high-performance code generation package. It is widely used by many AOP frameworks, such as spring AOP and DYNAOP, to provide them with methods of interception (interception). The most popular or mapping tool hibernate also uses the Cglib to proxy single-ended single-ended (many-to-one-to-single) associations (deferred fetching of collections, implemented by other mechanisms). Easymock and Jmock are packages that test Java code by using mock-up (Moke) objects. They all create mock-up (Moke) objects for classes that do not have interfaces by using Cglib. The bottom of the Cglib package is to convert bytecode and generate new classes by using a small, fast bytecode processing framework asm. In addition to the Cglib package, scripting languages such as groovy and BeanShell are also bytecode that uses ASM to generate Java. It is of course discouraged to use ASM directly, as it requires you to be familiar with the format and instruction set of the JVM's internal structure including the class file. Cglib Code Package Structure: core (kernel code) emitutils reflectutils keyfactory classemitter/codeemitter namingpolicy/defaultnamingpolicy Generatorstrategy/defaultgeneratorstrategy debuggingclasswriter classgenerator/abstractclassgenerator Beans ( Bean Operation Class) Beancopier Bulkbean beanmap immutablebean beangenerator reflect Fastclass proxy methodinterceptor, Dispatcher, L Azyloader, Proxyrefdispatcher, NoOp, Fixedvalue, Invocationhandler (Provide and JDK proxy functions) enhancer callbackgenerator Callbac K callbackfilter util Stringswitcher Parallelsorter transform cglib dynamic Proxy implementation: to implement a dynamic proxy for an object, we can do this: first implement a simple business class:
Package com.tds.cglib;

public class Businessobject {public

	void dosomething () {
		
		System.out.println ("method is executing ...");}
}
Then implement a class that implements the proxy:
Package com.tds.cglib;

Import Java.lang.reflect.Method;

Import Net.sf.cglib.proxy.Enhancer;
Import Net.sf.cglib.proxy.MethodInterceptor;
Import Net.sf.cglib.proxy.MethodProxy;

public class Businessinterfaceproxy implements methodinterceptor{

	private Object target;

	public object getinstance (object target) {
		
		this.target = target;
		Enhancer enhancer = new enhancer ();
		
		Enhancer.setsuperclass (This.target.getClass ());
		Enhancer.setcallback (this);
		
		return Enhancer.create ();
	}
	
	@Override Public
	Object Intercept (Object obj, Method method, object[] args, Methodproxy proxy) throws Throwable {
  SYSTEM.OUT.PRINTLN ("Things begin ...");
		Proxy.invokesuper (obj, args);
		SYSTEM.OUT.PRINTLN ("Things End ...");
		return null;
	}
	
	
}
This class is the key to implement Cglib dynamic agent, to implement Cglib dynamic agent, it is necessary to implement Methodinterceptor (Method Interceptor Interface), the source code of this interface is as follows:
Package net.sf.cglib.proxy;
 /** * General-purpose {@link enhancer} callback which provides for "around advice". * @author Juozas Baliuka <a href= "mailto:baliuka@mwm.lt" >baliuka@mwm.lt</a> * @version $Id: Methodinterceptor.java,v 1.8 2004/06/24 21:15:20 Herbyderby EXP $ * Public interface Methodinterceptor extends Callback
     {/** * All generated proxied methods-this method instead of the original method. * The original method may either is invoked by normal reflection using the method object, * or by using the Methodpro
     XY (faster). * @param obj "This", the enhanced Object * @param method intercepted method * @param args argument array; Primitive types is wrapped * @param proxy used to invoke super (non-intercepted method); May is called * as many times as needed * @throws Throwable any exception could be thrown; If so, super method is not being invoked * @return any value compatible with the signature of the ProxiEd method.
     Method returning void would ignore this value. * @see Methodproxy */public Object intercept (object obj, Java.lang.reflect.Method Method, object[] args, Met

Hodproxy proxy) throws Throwable;
 }
From the source can be seen, this interface only a method--intercept, this method has 4 parameters, respectively, is an enhanced object, that is, to implement the interface class of an object; method means to be intercepted; The parameter of the method to be intercepted by the args, which represents the method object to trigger the parent class, and the client test code as follows:
Package com.tds.cglib;

public class Cglibtest {public

	static void Main (string[] args) {
		
		Businessinterfaceproxy cglib = new Businessinter Faceproxy ();
		Businessobject Businessobject = (businessobject) cglib.getinstance (New Businessobject ());
		System.out.println (Businessobject.getclass (). GetName ());
		System.out.println (Businessobject.getclass (). Getsuperclass (). GetName ());
		Businessobject.dosomething ();
	}
	
}
The results of the operation are as follows: com.tds.cglib.businessobject$ $EnhancerByCGLIB $$934b0d42 Com.tds.cglib.BusinessObject
Things begin ...
Method is executing ...
The end of things ...
As can be seen from the running result, the newly generated object is indeed the object produced by the subclass of the original object class. We focus on a getinstance method, which mainly does three things: Set the parent class of the Enhancer object, set the callback object of the enhancer, and create the proxy object; The focus is create this method, we look at create this method of source code:
/**
     * Generate a new class if necessary and uses the specified
     * callbacks (if any) to create a new object Instanc E.
     * Uses the No-arg constructor of the superclass.
     * @return A new instance
     *
    /Public Object Create () {
        classonly = false;
        Argumenttypes = null;
        return Createhelper ();
    }
The main idea of this method is this: if necessary, create a new class, and create a new object instance with the specified callback object, use the constructor of the parent class's arguments to instantiate the part of the parent class, and then we will analyze the method body of the Create method. The first two lines are mainly set classonly and argumenttypes the values of the two fields, indicating that the object to be created is more than just a class, the parameter type is set to NULL, is to use the parent class without parameters of the construction method, focus on Createhelper This method, the source code is as follows:
private Object Createhelper () {validate ();
        if (superclass! = null) {Setnameprefix (Superclass.getname ()); } else if (interfaces! = null) {Setnameprefix (interfaces[reflectutils.findpackageprotected (interfaces)].getna
        Me ());
                                                    } return Super.create (key_factory.newinstance (superclass! = null)? Superclass.getname (): null,
                                                    Reflectutils.getnames (interfaces),
                                                    Filter, Callbacktypes,
                                                    Usefactory, Interceptduringconstruction,
    SERIALVERSIONUID)); }
This method first examines the object to be created, primarily verifying that the classonly,callbacks,callbacktypes and interfaces these parameters meet the requirements, and throws an exception if the relevant requirements are not met. Then, according to the two parameters of superclass and interfaces to generate a new class name prefix, and finally to the most important method, that is, the enhancer class of the parent class Abstractclassgenerator the Create method, Before calling this method, the Enhancerkey interface implementation class's Newinstance method is called to generate a string object with a value of Net.sf.cglib.proxy.enhancer$enhancerkey, and then The Create method of the Abstractclassgenerator class generates a proxy object based on this key, and the Create method body is as follows:
 Protected object Create (object key) {try {Class gen = null;
                Synchronized (source) {ClassLoader loader = getClassLoader ();
                Map cache2 = null;
                Cache2 = (MAP) source.cache.get (loader);
                    if (cache2 = = null) {cache2 = new HashMap ();
                    Cache2.put (Name_key, New HashSet ());
                Source.cache.put (loader, cache2);
                    } else if (UseCache) {Reference ref = (Reference) cache2.get (key); 
                Gen = (Class) ((ref = = null)? Null:ref.get ());
                    } if (Gen = null) {Object save = Current.get ();
                    Current.set (this);
                        try {this.key = key; if (attemptload) {try {gen = Loader.loadclass (GetClassName ()
   );                         } catch (ClassNotFoundException e) {//Ignore }} if (Gen = null) {byte[] b = St
                            Rategy.generate (this);
                            String className = classnamereader.getclassname (new Classreader (b));
                            Getclassnamecache (loader). Add (ClassName);
                        Gen = Reflectutils.defineclass (className, B, loader); } if (UseCache) {cache2.put (key, New Weakrefe
                        Rence (gen));
                    } return Firstinstance (gen);
                    } finally {Current.set (save);
        }}} return Firstinstance (gen);
        } catch (RuntimeException e) {throw e; } catch (Error e) {throw e;
        } catch (Exception e) {throw new Codegenerationexception (e); }
    }
There is a very important line of code in this method:
Byte[] B = strategy.generate (this);
This line of code is the byte code that produces the representative class, the detailed information can be debugged

From the above analysis, it is known that, in essence, the core class of dynamic agents based on Cglib is the enhancer class, which generates new classes of objects based on the parameters passed in.

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.