Spring AOP Advanced-Source Implementation (2) Advisor and Aspect in Spring AOP

Keywords: Java Spring xml github encoding

The full source address of this example is: https://github.com/yu-linfeng/BlogRepositories/tree/master/repositories/Spring%20AOP%E9%AB%98%E7%BA%A7%E2%80%94%E2%80%94%E6%BA%90%E7%A0%81%E5%AE%9E%E7%8E%B0%EF%BC%882%EF%BC%89Spring%20AOP%E4%B8%AD%E9%80%9A%E7%9F%A5%E5%99%A8%EF%BC%88Advisor%EF%BC%89%E4%B8%8E%E5%88%87%E9%9D%A2%EF%BC%88Aspect%EF%BC%89

 

The reason why I haven't officially entered the source code of Spring AOP is that I had a little trouble reading Spring AOP to generate proxy objects, so I had to stop for a while and sort out two conceptual problems about Spring AOP.

Notifier has not been mentioned in previous blogs. In Spring Actual Warfare, it is simply explained that <aop:advisor> is used to define a notifier in xml, and then it is not explained, but to define a facet with <aop:aspect>. In the chapter of Spring Technology Insider about Spring AOP, three concepts of AOP are introduced: notification, cut-point and notifier. At this time, I had a lot of doubts about the notifier. After consulting the relevant information and not having a satisfactory answer, I decided to explore it myself.

First, we discuss how to define notifiers. Define a notification class, which contains pre-notification and post-notification. Note that if AOP is implemented by using < aop: advisor > to define the notification, the notification class needs to implement the Advice interface. The pre-notification method corresponds to MethodBeforeAdvice, and the post-notification method corresponds to AfterReturning Advice.

 1 package com.demo;
 2 
 3 import org.springframework.aop.AfterReturningAdvice;
 4 import org.springframework.aop.MethodBeforeAdvice;
 5 import org.springframework.stereotype.Component;
 6 
 7 import java.lang.reflect.Method;
 8 
 9 /**
10  * Created by Kevin on 2017/11/15.
11  */
12 @Component("advisorTest")
13 public class AdvisorTest implements MethodBeforeAdvice, AfterReturningAdvice{
14 
15     /**
16      * Before advice
17      * @param method
18      * @param args
19      * @param target
20      * @throws Throwable
21      */
22     @Override
23     public void before(Method method, Object[] args, Object target) throws Throwable {
24         System.out.println("Before advice");
25     }
26 
27     /**
28      * after returning advise
29      * @param returnValue
30      * @param method
31      * @param args
32      * @param target
33      * @throws Throwable
34      */
35     @Override
36     public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
37         System.out.println("after returning advise");
38     }
39 }

Define a target object that needs to be proxied.

 1 package com.demo;
 2 
 3 import org.springframework.stereotype.Component;
 4 
 5 /**
 6  * Target objects, classes and methods that need to be proxied
 7  * Created by Kevin on 2017/11/15.
 8  */
 9 @Component("testPoint")
10 public class TestPoint {
11 
12     public void test() {
13         System.out.println("Method call");
14     }
15 }

The goal is to print "pre-notification" and "post-notification" before and after test method invocation, respectively.

The notifications defined in applicationContext.xml are as follows:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xmlns:context="http://www.springframework.org/schema/context"
 5        xmlns:aop="http://www.springframework.org/schema/aop"
 6        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
 7 
 8     <context:component-scan base-package="com.demo"/>
 9 
10     <aop:config>
11         <aop:pointcut id="test" expression="execution(* com.demo.TestPoint.test())"/>
12         <aop:advisor advice-ref="advisorTest" pointcut-ref="test"/>
13     </aop:config>
14 
15 </beans>

The final operation results are in line with expectations. So the question arises. What if we only want to configure the pre-notification at the defined cut-off point < aop: pointcut id = "test" expression = "execution (* com.demo. TestPoint. test ()"/>? The answer is that this is not possible. That is to say, if we define Advisor, there are limitations in some places, narrowly speaking, by defining Advisor Notifier, we can only define an aspect with only one notification and one entry point. Of course, a notification is inaccurate because it can be proxyed as long as different notification interfaces are implemented, but if multiple notification interfaces are implemented, it is not possible to use only one. Notifier is a special aspect.

Next, we discuss the use of defining aspects. It is a great convenience that notification classes can be implemented without any notification interfaces if they are defined in <aop:aspect>. Similarly, to implement the functions of the above example, define a notification class, including pre-notification and post-notification.

 1 package com.demo;
 2 
 3 import org.springframework.stereotype.Component;
 4 
 5 /**
 6  * Created by Kevin on 2017/11/15.
 7  */
 8 @Component("aspectTest")
 9 public class AspectTest {
10 
11     /**
12      * Before advice
13      */
14     public void doBefore() {
15         System.out.println("Before advice");
16     }
17 
18     /**
19      * after returning advise
20      */
21     public void doAfter() {
22         System.out.println("after returning advise");
23     }
24 }

The target object is consistent with the above example, followed by the configuration of the facets in applicationContext.xml.

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xmlns:context="http://www.springframework.org/schema/context"
 5        xmlns:aop="http://www.springframework.org/schema/aop"
 6        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
 7 
 8     <context:component-scan base-package="com.demo"/>
 9 
10     <aop:config>
11         <aop:aspect ref="aspectTest">
12             <aop:pointcut id="test" expression="execution(* com.demo.TestPoint.test())"/>
13             <aop:before method="doBefore" pointcut-ref="test"/>
14             <aop:after-returning method="doAfter" pointcut-ref="test"/>
15         </aop:aspect>
16     </aop:config>
17 </beans>

We can see that we define a facet by <aop:aspect> and only define <aop:before> if only pre-notification is needed, which is quite different from <aop:advisor>. Therefore, we can define notification flexibly in the way of <aop:aspect> defining facets, instead of constraining it as a notifier.

In fact, notifier is a special aspect. The first two blogs didn't mention it because AspectJ annotations were used in those two examples, and there were no corresponding concepts in AspectJ annotations.

The <aop:advisor> scenario used most in practice is configuring transactions in Spring. In addition, it is seldom used and is not recommended. Because the biggest problem is the need to implement notification interfaces when defining notifications, which goes against the original intent of a little Spring "non-intrusive" programming.

This blog is inserted in the source code in order to better clarify the various conceptual issues in Spring AOP, because I said at the beginning, and then formally began the interpretation of Spring AOP source code.

 

 

This is a public number that adds buff to programmers.

Posted by artin on Tue, 08 Jan 2019 10:33:10 -0800