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.