Spring technology Insider: Implementation Principles of Spring AOP (V)

Source: Internet
Author: User

Spring technology Insider: Implementation Principles of Spring AOP (V)

7. Implementation of Advice notifications
When the AopProxy proxy object is generated, its interceptor is also generated. Next we will analyze how Aop enhances the target object. In the implementation of configuring the interceptor for AopProxy, there is a process of obtaining the interceptor configuration, which is implemented by DefaultAvisorChainFactory, and this factory class is responsible for generating the interceptor chain in its getInterceptorsAndDynamicInterceptionA-
In the dvice method, there is an adapter registration process. By configuring the interceptor pre-designed by Spring, Spring adds it to the processing of Aop implementation. To learn more about this process, first go to Defau-
The implementation of ltAdvisorChainFactory starts. The following Code shows that in the DefaultAdvisorChainFactory implementation, a single piece of GlobalAdvisorAdapterRegistry is constructed first, and then the configured Advisor notifiers are traversed one by one, these Notification links are all configured in interceptorNames. From the advised parameter object passed in by getInterceptorsAndDynamicInterceptionAdvice, You can conveniently retrieve the configured Notification. With these notification tools, the next step is
GlobalAdvisorAdapterRegistry to adapt and register the interceptor.

/*** A simple but definitive way of working out an advice chain for a Method, * given an {@ link Advised} object. always rebuilds each advice chain; * caching can be provided by subclasses. * @ author Juergen Hoeller * @ author Rod Johnson * @ author Adrian Colyer * @ since 2.0.3 */@ SuppressWarnings (serial) public class implements AdvisorChainFactory, Serializable {public ListGetInterceptorsAndDynamicInterceptionAdvice (Advised config, Method method, Class targetClass) {// This is somewhat tricky... we have to process introductions first, // but we need to preserve order in the ultimate list. listInterceptorList = new ArrayList(Config. getAdvisors (). length); boolean hasIntroductions = hasMatchingIntroductions (config, targetClass); // get the registry GlobalAdvisorAdapterRegistry, which is a single-piece mode Implementation of AdvisorAdapterRegistry = GlobalAdvisorAdapterRegistry. getInstance (); for (Advisor advisor: config. getAdvisors () {if (advisor instanceof PointcutAdvisor) {// Add it conditionally. pointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; if (config. isPreFiltered () | pointcutAdvisor. getPointcut (). getClassFilter (). matches (targetClass) {MethodInterceptor [] interceptors = registry. getInterceptors (advisor); MethodMatcher mm = pointcutAdvisor. getPointcut (). getMethodMatcher (); if (MethodMatchers. matches (mm, method, targetClass, hasIntroductions) {if (mm. isRuntime () {// Creating a new object instance in the getInterceptors () method // isn' t a problem as we normally cache created chains. for (MethodInterceptor interceptor: interceptors) {interceptorList. add (new InterceptorAndDynamicMethodMatcher (interceptor, mm) ;}} else {interceptorList. addAll (Arrays. asList (interceptors) ;}}} else if (advisor instanceof IntroductionAdvisor) {IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (config. isPreFiltered () | ia. getClassFilter (). matches (targetClass) {Interceptor [] interceptors = registry. getInterceptors (advisor); interceptorList. addAll (Arrays. asList (interceptors);} else {Interceptor [] interceptors = registry. getInterceptors (advisor); interceptorList. addAll (Arrays. asList (interceptors);} return interceptorList ;}

The getInterceptors method of GlobalAdvisorAdapterRegistry makes a great contribution to the implementation of AOP. This method encapsulates the entrance for advice to be woven into the implementation. Let's start with the implementation of GlobalAdvisorAdapterRegistry, it basically acts as an adapter, but it is also a single-piece mode. The Code is as follows:

/*** Keep track of a single instance so we can return it to classes that request it. * // use static variables to keep a unique instance private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry ();/*** Return the singleton {@ link DefaultAdvisorAdapterRegistry} instance. */public static AdvisorAdapterRegistry getInstance () {return instance ;}

At this point, we know that a series of adapter adapters are set in DefaultAdvisorAdapterRegistry. This is the implementation of these adapters and provides weaving capabilities for Spring advice. Next, let's take a look at what happened to DefaultAdvisorAdapterRegistry? Adapter has two functions:
1. Call the support method of the adapter to determine the type of advice notification obtained, and register different AdviceInterceptor according to different advice types, that is, the interceptor we saw earlier.
2. These AdviceInterceptor are designed by the Spring AOP framework to provide services for implementing different advice functions. With these AdviceInterceptor, you can easily use various advice provided by Spring to design AOP applications. That is to say, it is these AdviceInterceptor that ultimately realizes the advice notification weaving function in the AopProxy object.

/** * Default implementation of the {@link AdvisorAdapterRegistry} interface. * Supports {@link org.aopalliance.intercept.MethodInterceptor}, * {@link org.springframework.aop.MethodBeforeAdvice}, * {@link org.springframework.aop.AfterReturningAdvice}, * {@link org.springframework.aop.ThrowsAdvice}. * * @author Rod Johnson * @author Rob Harrop * @author Juergen Hoeller */@SuppressWarnings(serial)public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {    private final List adapters = new ArrayList(3);    /**     * Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.     */    public DefaultAdvisorAdapterRegistry() {        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());        registerAdvisorAdapter(new AfterReturningAdviceAdapter());        registerAdvisorAdapter(new ThrowsAdviceAdapter());    }    public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {        if (adviceObject instanceof Advisor) {            return (Advisor) adviceObject;        }        if (!(adviceObject instanceof Advice)) {            throw new UnknownAdviceTypeException(adviceObject);        }        Advice advice = (Advice) adviceObject;        if (advice instanceof MethodInterceptor) {            // So well-known it doesn't even need an adapter.            return new DefaultPointcutAdvisor(advice);        }        for (AdvisorAdapter adapter : this.adapters) {            // Check that it is supported.            if (adapter.supportsAdvice(advice)) {                return new DefaultPointcutAdvisor(advice);            }        }        throw new UnknownAdviceTypeException(advice);    }    public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {        List
  
    interceptors = new ArrayList
   
    (3);        Advice advice = advisor.getAdvice();        if (advice instanceof MethodInterceptor) {            interceptors.add((MethodInterceptor) advice);        }        for (AdvisorAdapter adapter : this.adapters) {            if (adapter.supportsAdvice(advice)) {                interceptors.add(adapter.getInterceptor(advisor));            }        }        if (interceptors.isEmpty()) {            throw new UnknownAdviceTypeException(advisor.getAdvice());        }        return interceptors.toArray(new MethodInterceptor[interceptors.size()]);    }    public void registerAdvisorAdapter(AdvisorAdapter adapter) {        this.adapters.add(adapter);    }}
   
  

You can refer to Advice in the call to getInterceptors of DefaultAdvisorRegistry, from the names of the notification adapters MethodBeforeAdviceAdapter, listener, and ThrowsAdviceAdaper. Here, they are added to the List of adapters as adapters. They are classes at the same level implementing the AdvisorAdapter interface, but they are responsible for different adaptation tasks, one-to-one service for different advice implementations.
The following code uses MethodBeforeAdviceAdapter as an example:

Class implements AdvisorAdapter, Serializable {public boolean supportsAdvice (Advice advice) {return (advice instanceof bandwidth);} // retrieve advice from the Notification Server public MethodInterceptor getInterceptor (Advisor advisor) {MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor. getAdvice (); return new MethodBeforeAdviceInterceptor (advice );}}

It is very clear here that Spring AOP has designed a specific Interceptor to encapsulate these functions in order to implement advice weaving. Although the application does not directly use these interceptors, it is an indispensable preparation for advice to play its role. Let's take MethodBeforeAdviceInterceptor as an example to see how advice is encapsulated. In the invoke callback method, we can see that the before callback of advice is triggered first, and then the proceed method of MethodInvocation is called. As you can see, it is already associated with the previous Proceed Analysis in ReflectionMethodInvocation. Recall that in the proceed method of ReflectionMethodInvocation triggered by the AopProxy proxy object, after obtaining the interceptor, the call to the interceptor invoke method was started. According to the AOP rules, the ReflectiveMethodInvocation-triggered interceptor invoke method will eventually trigger Spring's encapsulation of different advice interceptors based on different advice types, such as MethodBeforeAdvice, in the end, different types of advice will trigger Spring's interceptor encapsulation for different advice. For example, for MethodBeforeAdvice, The invoke method of MethodBeforeAdviceInterceptor is triggered. In the MethodBeforeAdviceInterceptor method, the before method of advice is called. This is the enhancement effect of the target object required by MethodBeforeAdvice: Notification enhancement before method call.

Public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {private MethodBeforeAdvice advice;/*** Create a new MethodBeforeAdviceInterceptor for the given advice. * @ param advice the MethodBeforeAdvice to wrap * // create the corresponding MethodBeforeAdviceInterceptor object public MethodBeforeAdviceInterceptor (MethodBeforeAdvice Advice) {Assert. notNull (advice, Advice must not be null); this. advice = advice;} // this invoke method is the callback method of the Interceptor. It will trigger the callback public Object invoke (MethodInvocation mi) throws Throwable {this when the proxy Object method is called. advice. before (mi. getMethod (), mi. getArguments (), mi. getThis (); return mi. proceed ();}}

Complete the call of MethodBeforeAdviceInterceptor, and then start the afterReturning callback of the advice notification. The Code is as follows:

/**     * Create a new AfterReturningAdviceInterceptor for the given advice.     * @param advice the AfterReturningAdvice to wrap     */    public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {        Assert.notNull(advice, Advice must not be null);        this.advice = advice;    }    public Object invoke(MethodInvocation mi) throws Throwable {        Object retVal = mi.proceed();        this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());        return retVal;    }

The implementation of ThrowsAdvice is similar to the above and encapsulated in the corresponding AdviceInterceptor. The callback method of ThrowsAdvice is more complex. He maintains a exceptionHandlerMap to correspond to different method call scenarios, the handler acquisition in the exceptionHandlerMap is related to the exception that triggers ThrowsAdvice enhancement.

/** * Interceptor to wrap an after-throwing advice. * * 

The signatures on handler methods on the {@code ThrowsAdvice} * implementation method argument must be of the form:
* * {@code void afterThrowing([Method, args, target], ThrowableSubclass);} * *

Only the last argument is required. * *

Some examples of valid methods would be: * *

public void afterThrowing(Exception ex)
*
public void afterThrowing(RemoteException)
*
public void afterThrowing(Method method, Object[] args, Object target, Exception ex)
*
public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)
* *

This is a framework class that need not be used directly by Spring users. ** @ author Rod Johnson * @ author Juergen Hoeller */public class implements MethodInterceptor, AfterAdvice {private static final String AFTER_THROWING = afterThrowing; private static final Log logger = LogFactory. getLog (ThrowsAdviceInterceptor. class); private final Object throwsAdvice;/** Methods on throws advice, keyed by exception class */private final Map Predictionhandlermap = new HashMap ();/*** Create a new ThrowsAdviceInterceptor for the given ThrowsAdvice. * @ param throwsAdvice the advice object that defines the exception * handler methods (usually a {@ link org. springframework. aop. throwsAdvice} * implementation) */public ThrowsAdviceInterceptor (Object throwsAdvice) {Assert. notNull (throwsAdvice, Advice must not be null); this. throwsAdvice = throwsAdvice; // configure the ThrowsAdvice callback Method Method [] methods = throwsAdvice. getClass (). getMethods (); for (Method method: methods) {if (method. getName (). equals (AFTER_THROWING) & (method. getParameterTypes (). length = 1 | method. getParameterTypes (). length = 4) & Throwable. class. isAssignableFrom (method. getParameterTypes () [method. getParameterTypes (). length-1]) {// Have an exception handler // configure exception handling this. exceptionHandlerMap. put (metho D. getParameterTypes () [method. getParameterTypes (). length-1], method); if (logger. isDebugEnabled () {logger. debug (Found exception handler method: + method) ;}} if (this. exceptionHandlerMap. isEmpty () {throw new IllegalArgumentException (At least one handler method must be found in class [+ throwsAdvice. getClass () +]) ;}} public int getHandlerMethodCount () {return this. exceptionHandlerMap. Size ();}/*** Determine the exception handle method. can return null if not found. * @ param exception the exception thrown * @ return a handler for the given exception type */private Method getExceptionHandler (Throwable exception) {Class exceptionClass = exception. getClass (); if (logger. isTraceEnabled () {logger. trace (Trying to find handler for exception of type [+ exceptionClass. getName () + ]);} Method handler = this. exceptionHandlerMap. get (exceptionClass); while (handler = null &&! ExceptionClass. equals (Throwable. class) {exceptionClass = exceptionClass. getSuperclass (); handler = this. exceptionHandlerMap. get (exceptionClass);} if (handler! = Null & logger. isDebugEnabled () {logger. debug (Found handler for exception of type [+ exceptionClass. getName () +]: + handler);} return handler;} public Object invoke (MethodInvocation mi) throws Throwable {try {// place the method call of the target Object in try catch, and triggered in catch. // ThrowsAdvice callback. The exception is then thrown out without handling return mi too much. proceed ();} catch (Throwable ex) {Method handlerMethod = getExceptionHandler (ex); if (handlerMet Hod! = Null) {invokeHandlerMethod (mi, ex, handlerMethod) ;}throw ex ;}// call private void invokeHandlerMethod (MethodInvocation mi, Throwable ex, method method) throws Throwable {Object [] handlerArgs; if (method. getParameterTypes (). length = 1) {handlerArgs = new Object [] {ex};} else {handlerArgs = new Object [] {mi. getMethod (), mi. getArguments (), mi. getThis (), ex };}try {method. invoke (this. throwsAdvice, handlerArgs);} catch (InvocationTargetException targetEx) {throw targetEx. getTargetException ();}}}

 

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.