Spring methodbeforeadvice implementation Principle Exploration & Implementation of a simple advice

Source: Internet
Author: User

I. Class Structure

The entire process of methodbeforeadvice is roughly the dynamic proxy interfaces invocationhandler and proxy provided by JDK.

So first, we will discuss how dynamic proxies are used here.

1. Obtain the class dynamically generated by the dynamic proxy ($ proxy0.class)

Reference blog: http://sin90lzc.iteye.com/blog/1037448

Field field = System.class.getDeclaredField("props");    field.setAccessible(true);    Properties props = (Properties) field.get(null);    props.put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");  

2. decompile $ proxy0.class

Frontend 2.0 plus (cracked) download)

Decompile the Java file to view the generated source code,

// This class is generated by the dynamic proxy. Finally, getbean is the object of the obtained class, // but cannot be accessed during the compilation phase, so it can only be converted to methods related to interface type or parent type access // here the seller interface is implemented as specified in the spring configuration file, and the springproxy interface implemented is marker interface, it indicates that this is a proxy class generated by spring // and then implements the advised interface. You can use the advised interface to obtain the proxy configuration information public final class $ proxy0 extends proxy implements seller, springproxy, advised {public $ proxy0 (invocationhandler) // constructor. During construction, an invocationhandler is passed to process subsequent method calls {super (invocationhandler ); // The invocationhandler here is actually an instance of jdkdynamicaopproxy }..... // take two typical examples to see how this class works // This method uses invocationhandler to call m2 // m2 = Class. forname ("Java. lang. object "). getmethod ("tostring", new class [0]); Public final string tostring () {try {return (string) super. h. invoke (this, M2, null);} catch (error _ ex) {} catch (throwable) {Throw new undeclaredthrowableexception (throwable );}} // Add notification method // M18 = Class. forname ("org. springframework. AOP. framework. advised "). getmethod ("addadvice", new class [] {// integer. type, class. forname ("org. aopalliance. AOP. advice ") //}); Public final void addadvice (int I, advice) throws aopconfigexception {try {super. h. invoke (this, M18, new object [] {integer. valueof (I), advice}); return;} catch (error _ ex) {} catch (throwable) {Throw new undeclaredthrowableexception (throwable );}} // method of the target class to be proxy // m3 = Class. forname ("com. ISS. spring. advice. seller "). getmethod ("updated", new class [] {// class. forname ("Java. lang. string ") //}); Public final void trim (string s) {try {super. h. invoke (this, M3, new object [] {s}); return;} catch (error _ ex) {} catch (throwable) {Throw new undeclaredthrowableexception (throwable );}}......}

3. Call Process

Through the source code and class diagram above, we can find the generated $ proxy0 class, that is, the class object that is finally returned to the user,

Provides you with encapsulated interfaces for direct calls of these methods, instead of calling invocationhandler on your own.

You can convert the reference of this object to the target interface type to call the target method.

The procedure here is to call the invoke method of $ proxy0. $ proxy0 finds the method through the seller interface and obtains the method object.

Then it is passed to invocationhandler for calling,

Seller seller = (Seller)context.getBean("proxy");seller.sell("Genke");

You can also convert the reference of this object to advised to obtain the proxy configuration information.

The process here is to call the gettargetclass method of $ proxy0, and $ proxy0 finds the method through the advised interface to obtain the method object.

Then it is passed to invocationhandler for calling,

Advised advised = (Advised) context.getBean("proxy");System.out.println(advised.getTargetClass());

Invocationhandler determines whether it is an advised interface. If yes, it will be executed directly without any notification.

If it is not an advised interface method, get the notification chain or interceptor first. After all the interceptors are executed, the method of the target object will be executed,

Note: methodbeforeadvice is discussed here. For the execution sequence of several advice and the method execution sequence of the target object, see the source code exploration of four advice types in spring.

2. Implement a simple notification (advice)

Advice. Java

Package COM. ISS. spring. myadvice; import Java. lang. reflect. method;/*** provides a notification interface * @ author administrator **/public interface advice {public void before (object target, method, object [] ARGs );}

Bean. Java

Package COM. ISS. spring. myadvice;/*** maintain bean information * @ author administrator **/public class bean {private string ID; private string clazz ;/*.......... getter and setter .......... */}

Configuration. Java

Package COM. ISS. spring. myadvice; import Java. util. list;/*** this interface is used to maintain related configuration file information * @ author administrator **/public interface configuration {public list <string> getproxyinterfaces (); public list <string> getinterceptornames (); Public String gettarget ();}

Configurationimpl. Java

Package COM. ISS. spring. myadvice; import Java. util. arraylist; import Java. util. list;/*** implement configuration, maintain configuration information * inherit bean, maintain bean information * @ author administrator **/public class configurationimpl extends bean implements configuration {private list <string> proxyinterfaces; private list <string> interceptornames; private string target; private list <class> interfaces; private list <Object> interceptor; private object targetsource; Public configurationimpl () {proxyinterfaces = new arraylist <string> (); interceptornames = new arraylist <string> (); interfaces = new arraylist <class> (); interceptor = new arraylist <Object> ();}/*... getter and setter... */}

Myhandler. Java

Package COM. ISS. spring. myadvice; import Java. lang. reflect. invocationhandler; import Java. lang. reflect. method;/*** proxy class, execute the $ proxy0 passed Method * @ author administrator **/public class myhandler implements invocationhandler {private configuration config; Public myhandler (configuration config) {This. config = config ;}@ overridepublic object invoke (Object proxy, method, object [] ARGs) throws throwable {If (Config = NULL) return NULL; If (method. getdeclaringclass () = configuration. class) // if it is a call to obtain configuration information, it will be executed directly, ignoring the interceptor {return method. invoke (config, argS);} If (config instanceof configurationimpl) {for (Object Interceptor: (configurationimpl) config) // All interceptors or notifications need to be executed. getinterceptor () {If (interceptor instanceof advice) // If the interceptor class implements the advice interface, call the before method {(advice) interceptor of the interceptor ). before (configurationimpl) config ). gettargetsource (), method, argS) ;}} return method. invoke (configurationimpl) config ). gettargetsource (), argS); // Method for executing the target object }}

Xmlcontext. Java

Package COM. ISS. spring. myadvice; import Java. io. ioexception; import Java. lang. reflect. proxy; import Java. util. arraylist; import Java. util. list; import Org. dom4j. document; import Org. dom4j. extends entexception; import Org. dom4j. element; import Org. dom4j. io. saxreader; import Org. springframework. core. io. classpathresource;/*** use dom4j to parse XML and save it to configuration ** @ author administrator **/public class xmlcontext {PR Ivate static final string spring_configuration_impl_class = "com. ISS. spring. myadvice. configurationimpl "; private string path; private document DOC; private list <bean> beans; Public xmlcontext (string path) throws disable entexception, ioexception {This. path = path; try {Doc = new saxreader (). read (PATH);} catch (exception e) {Doc = new saxreader (). read (New classpathresource (PATH ). getFile (); // classp if not found on path Find} beans = new arraylist <bean> (); parse () ;}/ *** on the Ath, find the corresponding bean * @ Param name bean ID * @ return */private bean getbeanbyid (string name) {for (bean: Beans) {If (bean. GETID (). equals (name) {return bean;} return NULL;}/*** provides the getbean called by the user, if the class is configured as the proxy class, $ proxy0 proxy object * is returned. Otherwise, the bean object itself * @ Param name bean ID * @ return * @ throws classnotfoundexception * @ throws instantiationexception *@ Throws illegalaccessexception */public object getbean (string name) throws classnotfoundexception, instantiationexception, illegalaccessexception {bean = getbeanbyid (name); If (bean = NULL) system. out. println (name); If (bean. getclazz (). equals (spring_configuration_impl_class) {configurationimpl Config = (configurationimpl) bean; List <class> interfaces = new arraylist <class> (); For (string I: config. Getproxyinterfaces () {interfaces. add (class. forname (I);} interfaces. add (configuration. class); config. setinterfaces (interfaces); // set all interface lists <Object> interceptors = new arraylist <Object> (); For (string I: config. getinterceptornames () {interceptors. add (getbean (I);} config. setinterceptor (interceptors); // set all interceptor config. settargetsource (getbean (config. gettarget (); // sets the return proxy of the target object. newproxyinstanc E (config. getclass (). getclassloader (), interfaces. toarray (new class [0]), new myhandler (config); // return the generated intermediate class $ proxy0 object, the call function will be processed by myhandler} else {// assume that it is a simple beanreturn class without attributes. forname (getbeanbyid (name ). getclazz ()). newinstance () ;}}/*** start parsing, get all xml configuration information */private void parse () {If (Doc = NULL) return; element root = Doc. getrootelement (); For (Object OBJ: Root. elements () {element = (element) OBJ; I F (element. getname (). equals ("Bean") parsebean (element) ;}/ *** parses a single bean node * @ Param bean */private void parsebean (element bean) {bean OBJ = NULL; If (bean. attributevalue ("class "). equals (spring_configuration_impl_class) {OBJ = new configurationimpl (); configurationimpl temp = (configurationimpl) OBJ; For (Object Property: bean. elements ("property") {parseproperty (element) property, temp) ;}} else {OBJ = N EW Bean ();} obj. setid (bean. attributevalue ("ID"); obj. setclazz (bean. attributevalue ("class"); beans. add (OBJ);}/*** resolve a single property node * @ Param property * @ Param config */private void parseproperty (element property, configurationimpl config) {If (property. attributevalue ("name "). equals ("proxyinterfaces") {for (object Value: property. element ("list "). elements ("value") {element V = (element) value; config. get Proxyinterfaces (). add (v. gettext () ;}} else if (property. attributevalue ("name "). equals ("interceptornames") {for (object Value: property. element ("list "). elements ("value") {element V = (element) value; config. getinterceptornames (). add (v. gettext () ;}} else if (property. attributevalue ("name "). equals ("target") {/** first find local. If local is null, find bean */string bean = property. element ("Ref "). attributevalue ("local") = NULL? Property. element ("Ref "). attributevalue ("Bean"): property. element ("Ref "). attributevalue ("local"); config. settarget (bean );}}}

Test instance:

Beans. xml

<bean id="BreadSeller" class="com.iss.spring.advice.BreadSeller"></bean><bean id="MyAdvice" class="com.iss.spring.advice.MyAdvice"></bean><bean id="proxy" class="com.iss.spring.myadvice.ConfigurationImpl"><property name="proxyInterfaces"><list><value>com.iss.spring.advice.Seller</value></list></property><property name="interceptorNames"><list><value>MyAdvice</value></list></property><property name="target"><ref local="BreadSeller" /></property></bean>

Myadvice. Java

public class MyAdvice implements Advice{@Overridepublic void before(Object target, Method method, Object[] args){System.out.println(target+" is say hello to "+args[0] + " and then "+method);}}

Main

Public static void main (string [] ARGs) {try {xmlcontext context = new xmlcontext ("beans. XML "); seller = (seller) context. getbean ("proxy"); // The seller interface defines a handler (string) method seller. dependencies ("genke"); configuration Config = (configuration) context. getbean ("proxy"); system. out. println (config. gettarget ();} catch (exception e) {e. printstacktrace ();}}
 
 

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.