AOP Slicing programming

Source: Internet
Author: User

The underlying implementation of AOP is actually reflection, and the Reflection class Java.lang.reflect.Proxy in the JDK is the only class in Java that can access the scheduler. Similarly, the common dynamic Agent Library Cglib also realizes the encapsulation of dynamic agents through the reflection mechanism. AspectJ and spring AOP, with relatively high technical maturity, implement a set of reflect mechanisms at the bottom, with the difference between how the two define the specification implementation.

Whether it's ASPECTJ or spring AOP, all of these AOP programming is implemented based on reflection and runtime dynamic Agent control. The following through proxy and Cglib to achieve their own dynamic proxy plane.

Suppose I want to implement a set of annotations-based trasaction transaction management, implemented through an AOP dynamic proxy. Annotations and interfaces are implemented as follows

/** * @author Barudisshu * * * @Retention (Retentionpolicy.runtime) @Target ({Elementtype.method}) public @interface Transactionann {    string[] name () default {};    Boolean[] ReadOnly () default false;    Int[] Level () default connection.transaction_read_committed;    String value () Default "";}
/** * @author Barudisshu */public interface Transaction {    void open ();    void RollBack ();    void commit ();    void Closeifstillopen ();}
Proxy Dynamic Agent

The mechanism for dynamic proxies is as follows

Implement an agent factory

/** * Proxy Factory class * @author Barudisshu */public class Aspectfactory {    /** Singleton implementation *    /Private aspectfactory () {    }    @ Suppresswarnings ("unchecked") public    static <T> t getinstance (t Target,aspect ... aspects) {        Aspecthandler handler = new Aspecthandler (target, aspects);        Class clazz = Target.getclass ();        Return (T) proxy.newproxyinstance (Thread.CurrentThread (). Getcontextclassloader (), Clazz.getinterfaces (), handler);}    }

Encapsulating and inheriting the scheduler

/** * @author Barudisshu */public class Aspecthandler implements Invocationhandler {private Object target = null;  Private aspect[] aspects = NULL;  private int index =-1;    public aspecthandler (int index, Object target, aspect[] aspects) {this.index = index;    This.target = target;  This.aspects = aspects;    } public Aspecthandler (Object target, aspect[] aspects) {this.target = target;  This.aspects = aspects;  } public Object Gettarget () {return target;  The public void Settarget (Object target) {this.target = target;  } public aspect[] Getaspects () {return aspects;  } public void Setaspects (Aspect ... aspects) {this.aspects = aspects;  }/** * Delegate method * * @param proxy Object * @param method Proxy Methods * @param args Method parameter */public object Invoke (object Proxy, method, object[] args) throws Throwable {if (index = =-1) {return new Aspecthandler (0, Targe    T, aspects). Invoke (proxy, method, args);    } Object result = null; if (Index < aspects.length) {result = Aspects[index++].aspect (this, proxy, method, args);    } else if (index++ = = aspects.length) {result = Method.invoke (target, args);  } return result; }}
/** * @author Barudisshu */public interface Aspect {public  Object Aspect (Invocationhandler ih, Object Proxy, Method m Ethod, object[] args) throws throwable;}
Implement real objects, real objects inherit aspect, and will be delegated through Aspecthandler
/** * @author Barudisshu */public class Transactionaspect implements Aspect {public Object Aspect (Invocationhandler IH        , object proxy, method, object[] args) throws Throwable {object result = NULL;        Transactionann Transactionann = method.getannotation (Transactionann.class);            if (Transactionann! = null) {Transaction Transaction = new Transactionadapter ();            TODO: Get annotation information or set value string[] names = Transactionann.name ();            String values = Transactionann.value ();            Int[] level = Transactionann.level ();            boolean[] readOnly = Transactionann.readonly ();                try {//execute operation result = Ih.invoke (proxy, method, args);                TODO: Handling Transaction.open ();            Transaction.commit ();                }catch (Throwable t) {//If exception transaction.rollback ();                Throwable cause = T.getcause ();if (cause! = null) {/should define your own Exception here throw new Transact                Ionexception (Cause.getmessage (), cause);                } else {throw new TransactionException (T.getmessage (), t);            }}finally {//finally Transaction.closeifstillopen ();        }} else {//execute operation result = Ih.invoke (proxy, method, args);    } return result; }}

Based on the timing diagram, we just need to create the appropriate client to dispatch

/** * @author Barudisshu */public class Aspectclient {public    static void Main (string[] args) {        persistenceservice Persistenceservice = aspectfactory.getinstance (New Persistenceserviceimpl (), New Transactionaspect ());        Persistenceservice.save (3, "321");}    }
/** * @author Barudisshu */public interface Persistenceservice {    @TransactionAnn (name = "Save")    void Save (Long ID , String data);    @TransactionAnn (level = connection.transaction_read_uncommitted)    String load (long ID);}
/** * @author Barudisshu */public class Persistenceserviceimpl implements Persistenceservice {    @Override    public void save (Long ID, String data) {        throw new TransactionException ("Exception is rollback!!!") ");    }    @Override public    String load (long id) {        return null;    }}
Here we show the throw aRun-timeException transcationexception, running the client will execute the Transaction.rollback () method.

Since you have a proxy proxy for the JDK, why do you need to use other external libraries such as cglib? In fact, Proxy is simply the implementation of the agent, in the actual use can not meet the requirements, such as the above design, proxy's newproxyinstance static method is achieved through the clone, may need to consider whether it is a shallow copy or deep copy of the problem.

If implemented in Cglib, the problem is much simpler.

cglib Dynamic Agent

Create an agent factory for a single case

public class Cglibproxyfactory {    private cglibproxyfactory () {    }    @SuppressWarnings ("unchecked")    public static <T> T Createproxy (t target, Aopinterceptor Interceptor) {        Methodinterceptor methodinterceptor = New Cglibmethodinterceptor (Interceptor);        Enhancer enhancer = new enhancer ();        Enhancer.setsuperclass (Target.getclass ());        Enhancer.setinterfaces (Target.getclass (). Getinterfaces ());        Enhancer.setcallback (methodinterceptor);        Return (T) enhancer.create ();}    }

The cglib is implemented directly by means of the interceptor, only to inherit the interceptor

 
/** * @author Barudisshu */public interface Aopinterceptor {    void Before (method method, object[] args);    void after (method, object[] args);    void Afterthrowing (method, object[] args, throwable throwable);    void Afterfinally (Method method, object[] args);
Add a real object for transaction processing
/** * @author Barudisshu */public class Transactioncglib implements Aopinterceptor {private Transaction Transaction; @Override public void before (method method, object[] args) {if (Isrequiresnew (method)) {Transacti            on = new Transactionadapter ();        Transaction.open (); }} @Override public void After (method method, object[] args) {if (transaction! = NULL) {Tran        Saction.commit (); }} @Override public void Afterthrowing (method, object[] args, throwable throwable) {if (transacti        On! = null) {transaction.rollback ();            }} @Override public void Afterfinally (method method, object[] args) {if (transaction! = NULL) {            Transaction.closeifstillopen ();        transaction = NULL; }} Protected Boolean Isrequiresnew (method) {Transactionann transactionannotation = Method.getannotat        Ion (Transactionann.class); if (TransacTionannotation! = null) {if ("Requires_new". Equals (Transactionannotation.value ())) {return Tru            E    }} return false; }}

OK, very simple, transaction real objects will be methodinterceptor encapsulated, and implement callbacks in enhancer. Just add the appropriate client calls below to

/** * @author Barudisshu */public class Cglibclient {public    static void Main (string[] args) {        persistenceservice Persistenceservice = Cglibproxyfactory.createproxy (New Persistenceserviceimpl (), New Transactioncglib ());        Persistenceservice.save (3L, "321");}    }

Note different from the implementation in proxy

/** * @author Barudisshu */public class Persistenceserviceimpl implements Persistenceservice {    @TransactionAnn (" Requires_new ") Public    void Save (Long ID, String data) {        System.out.println (" generally save ... ");    }    @TransactionAnn ("not_supported") public    String load (long id) {        return null;    }}

Given the ASPECTJ and spring AOP facets, here's a brief description of the ASPECTJ configuration.

ASPECTJ Deployment
    1. Download to eclipse website http://www.eclipse.org/aspectj/downloads.php, directly with 7zip decompression or double-click installation.
    2. copy Aspectj1.x/lib/aspectjrt.jar to%java_home%\jre\lib\ext, note that this step is important, otherwise you will not find the path.
    3. set the AJC compiler path in the IDE (compiler is used to compile the AJ file into a. class file), take idea as an example
compiler must be aspectjtools, do not choose the wrong.

OK, almost, write a test example.

/** * @author Barudisshu */public aspect HelloWorld {    pointcut callpointcut (): Call        (void Cn.barudisshu.aop.MyClass.foo (int,java.lang.string));    Before (): Callpointcut () {        System.out.println ("Hello World");        System.out.println ("in the advice attached to the call pointcut");    }    After (): Callpointcut () {        System.out.println ("All things have Done");}    }

Method entry Point

/** * @author Barudisshu */public class MyClass {public    void foo (int number,string name) {        System.out.println ("I nside foo (int,string) ");    }    public static void Main (string[] args) {        //Create An instance of MyClass        MyClass myObject = new MyClass (); 
   
    //make the call to Foo        Myobject.foo (1, "Russ Miles");    }
   

The following code will output

Hello Worldin The advice attached to the call Pointcutinside foo (int,string) all things have done

AOP Slicing programming

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.