catalogue
Several common scenarios for notification
preface
The previous article talked about dynamic agents and interceptor chains, Spring - dynamic proxy and interceptor . Because dynamic proxy is the foundation of spring AOP, you can read the previous article first to better understand this article. We can enhance the function of the proxy object through dynamic proxy. Spring AOP is also used to enhance the proxy object, but it makes the enhancement of the proxy object easier and more conducive to development and use.
Several concepts of AOP
I'll first get the explanation of Spring's official website, and then try to explain it with my understanding.
- Advice
In fact, it is the function we need to enhance. For example, the method marked with @ Before, @ After and other annotations is a notification, which defines some behaviors to be performed at the pointcut, that is, how we want to enhance.
- Join point
Connection points are places where the program allows notification enhancements, such as before, after, or when an exception occurs. Spring AOP only supports method join points, that is, it can only be enhanced with the dimension of methods. Unlike other frameworks, it can also be enhanced when constructors or attribute assignments.
- Pointcut
Connection point is a conceptual thing. For example, the concept of connection point tells you that Spring AOP can be enhanced in the dimension of method. But what you can do is not necessarily what you will do. Because it is impossible to enhance all methods, and the tangent point is to specify the specific connection point, that is, which method to enhance.
- Aspect
In Spring AOP, if a class is annotated with the @ aspect annotation, it is an aspect. In fact, if you want to understand the aspect well, you must first understand the pointcut and notification. The aspect is the combination of pointcut and notification. In fact, if you read the last article, you should realize that it is very similar to the Advisor in Spring AOP, However, the Advisor only contains one pointcut and notification, and many pointcuts and notifications can be defined in the aspect. However, in the end, Spring will parse them into advisors. In fact, it is like a conceptual thing. For example, a company can't work itself, but the employees in the company are working. Aspect is responsible for management. What really does is the pointcut and notification it contains.
-
Introduction
Introduction is to introduce other interfaces into the existing interfaces to enhance the functions of the current interface
-
target
That is, the proxied object, which needs to be enhanced
- proxy
When the target object is proxied, it becomes a proxy object. I believe the students who read the last article can understand
- Weaving
Weaving can be understood as the process of applying the aspect to the target object to create a proxy. Some frameworks are woven at compile time, that is, modifying the source code directly near the code of the proxy object. Some frameworks are woven at run time, such as the proxy dynamic proxy method of Spring AOP, which will not change the code of the proxy object.
Code example
- Introduce required dependencies
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.6</version> </dependency>
- Test interfaces and implementation classes
public interface IOrder { Integer query(String type); } @Service public class OrderService implements IOrder { @Override public Integer query(String type) throws Exception { System.out.println("Query type is" + type + "Order quantity"); //An error occurred during the simulation query try { //int a = 1 / 0; } catch (Exception ex) { throw new Exception("I was wrong"); } return 1; } }
- Add facet class
@Aspect public class QueryAspect { @Pointcut("execution(* com.proxy.IOrder.query(..))") public void pointCut(){}; @Before(value = "pointCut()") public void methodBefore(JoinPoint joinPoint) throws Exception { System.out.println("Before calling the target method @Before Parameter information can be obtained in advance:" + Arrays.toString(joinPoint.getArgs())); //Error simulating before //int a = 1 / 0; } @After(value = "pointCut()") public void methodAfter(JoinPoint joinPoint) { System.out.println("After calling the target method @After"); // Simulate After exception int a = 1 / 0; } @AfterReturning(value = "pointCut()", returning = "result") public void methodAfterReturning(JoinPoint joinPoint, Object result) { System.out.println("After the target method returns @AfterReturning, The returned result can be obtained at this time " + result); //Error simulating AfterReturning //int a = 1 / 0; } @AfterThrowing(value = "pointCut()", throwing = "ex") public void methodAfterThrowing(JoinPoint joinPoint, Exception ex) { System.out.println("After throwing an exception, @AfterThrowing " + ex); } //@Around(value = "pointCut()") public Object methodAround(ProceedingJoinPoint pdj) { Object result = null; System.out.println("Before calling the target method @Around "); try { //Call target method result = pdj.proceed(); } catch (Throwable ex) { System.out.println("Exception information captured:" + ex); } System.out.println("After calling the target method @Around "); return result; } }
- Add configuration class and configure aspect bean
@Configuration @EnableAspectJAutoProxy @ComponentScan(value = {"com.proxy"}) public class AopConfig { @Bean public QueryAspect queryAspect() { return new QueryAspect(); } }
- Writing test classes
public class ProxyMain { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopConfig.class); IOrder proxy = (IOrder) applicationContext.getBeanFactory().getBean("orderService"); try { Object result = proxy.query("Erke"); System.out.println("The query result is:" + result); } catch (Exception e) { System.out.println("Test class caught error:" + e); } } }
- Comment out the @ Around notification first and view the running results
-
1:When there are no exceptions Before calling the target method @Before Parameter information can be obtained in advance:[Erke] Execute the target method. The query type is hongxingerke order quantity After the target method returns @AfterReturning, At this time, you can get the returned result 1 After calling the target method @After The query result is:1 2:When the target method is abnormal Before calling the target method @Before Parameter information can be obtained in advance:[Erke] Execute the target method. The query type is hongxingerke order quantity After throwing an exception, @AfterThrowing java.lang.Exception: I was wrong After calling the target method @After Test class caught error: java.lang.Exception: I was wrong It can be seen that when the target method is abnormal,@AfterReturning Your notice will not be executed, but @After Your notice will continue Continued implementation 3: When @Before When notifying exceptions Before calling the target method @Before Parameter information can be obtained in advance:[Erke] Test class caught error: java.lang.ArithmeticException: / by zero so@AfterThrowing No capture @Before Notified exception,@After and @AfterReturning None of the notifications were executed 4: When @AfterReturning When notifying exceptions Before calling the target method @Before Parameter information can be obtained in advance:[Erke] Execute the target method. The query type is hongxingerke order quantity After the target method returns @AfterReturning, At this time, you can get the returned result 1 After calling the target method @After Test class caught error: java.lang.ArithmeticException: / by zero so@AfterThrowing No capture @AfterReturning Notified exception, and @After The notification will continue 5: When @After When notifying exceptions Before calling the target method @Before Parameter information can be obtained in advance:[Erke] Execute the target method. The query type is hongxingerke order quantity After the target method returns @AfterReturning, At this time, you can get the returned result 1 After calling the target method @After Test class caught error: java.lang.ArithmeticException: / by zero It can be seen that all three notifications will be executed
- From the above execution results, we can find that
- @AfterThrowing can only catch exceptions at the tangent point.
- @The Before notification must be executed, and if there are exceptions in the execution process, the following steps will not be carried out.
- @The After notification is executed After the @ AfterReturning notification, and if the pointcut method throws an exception, the @ AfterReturning notification will not be executed.
- The execution process of these three notifications is roughly as follows
// @Before notification execution first try { try { //@Before notifies that if there are no exceptions, the target method will be executed at this time } catch (Throwable throwable) { //An exception occurred in the target method. The @ AfterThrowing notification will be executed at this time throw throwable; } //If the target method does not run out of exception, execute the notification of @ AfterReturn at this time } catch (Exception exception) { } finally { //The @ After notification will be executed as long as @ Before does not throw an exception }
- You must know how to use the above three notifications. What about @ Around notifications? We will comment out the other three notifications and only keep the @ Around notification to observe the execution results
@Around(value = "pointCut()") public Object methodAround(ProceedingJoinPoint pdj) { Object result = null; System.out.println("Before calling the target method @Around "); try { //Call target method result = pdj.proceed(); } catch (Throwable ex) { System.out.println("Exception information captured:" + ex); } System.out.println("After calling the target method @Around "); return result; }
-
results of enforcement
1:When the pointcut method has no exceptions Before calling the target method @Around Execute the target method. The query type is hongxingerke order quantity After calling the target method @Around The query result is:1 2: When the pointcut method is abnormal Before calling the target method @Around Execute the target method. The query type is hongxingerke order quantity Exception information captured: java.lang.Exception: I was wrong After calling the target method @Around The query result is:null
-
It can be seen that the function of @ Around notification is more powerful than the other three. It cuts the pointcut method into the notification and can be enhanced in various places of the pointcut method. It can be said that it has all the functions of the above three notifications. The above three notifications perform their respective functions and can only complete one enhancement. So If the enhanced requirement is simple, it only needs to be enhanced at a certain point. Then select the notice above. Its advantage is simple and efficient. If the functions to be enhanced are complex and need to be enhanced at multiple connection points, you need to use @ Around. Its advantage lies in its strong functionality.
Several common scenarios for notification
- @Before notification can obtain the parameter information of the target method in advance, so it can be used as permission authentication (some parameters can go down, and some can stop here). It can also be used to save the interface access record (because this notification will be executed, and other exceptions may not save the access record)
- @After returning notification can obtain the execution result of the target method, so it can enhance the obtained result, such as adding some information to the result or deleting some information. You can also save a copy of the results of the target method or send a copy to other systems. Mainly to enhance the results.
- @After notification, because the notification will be executed regardless of whether the target method fails or not, it can be used to perform some operations to close resources.
- @The AfterThrowing notification is mainly used to handle exceptions, such as data backup and restore
- @The Around notification is mainly used when complex enhancements are required.
About @ Pointcut
In fact, we should already know from the above that it defines a tangent point, as in the above example
@Pointcut("execution(* com.proxy.IOrder.query(..))") public void pointCut(){};
The @ Pointcut specifies the Pointcut method. The pointCut() method is a signature. The signature is only used to simplify the use of the Pointcut without writing it over and over again execution(* com.proxy.IOrder.query(..))
@ In addition to execution, there are other options in Pointcut, such as within, target, args, annotation, etc. execution is the label of the most commonly used matching method. This article only introduces this one.
The syntax of exception() is as follows:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
- Modifier pattern: modifier representing method, such as public, private, etc.
- RET type pattern: indicates the return value type of the method, * indicates the return value of any type
- Declaring type pattern: indicates the path of the class where the method is located.
- Name pattern: represents the method name. You can use the full method name or query * to match all methods starting with query
- Param pattern: indicates the parameter type. Multiple parameter types can be specified, separated by commas, or * can be used to match parameters of any type. For example, (int, *) indicates that the first parameter type is int and the second is a method of any type. You can also use (..) to match the parameters of zero or more arbitrary methods.
- Throws pattern: indicates the exception thrown by the method
You can also use & & (and), | (or)( (non expression)
- @ Pointcut("execution(Integer com.proxy.IOrder.query(..) "): represents a query method matching integer type, but the parameters of the method are not limited.
- @Pointcut("execution(* com.proxy.IOrder.query(int)) "): indicates that the query method matches any type, but there can only be one parameter of type int in the parameter list.
- @Pointcut ("execution (integer com. Proxy. Iorder. Query (String)) 𞓜 execution (integer com. Proxy. Iorder. Query (int))"): indicates the query method with matching parameter type of String or int
summary
This paper introduces some concepts of AOP, introduces the way Spring AOP defines aspects, pointcuts and notifications with examples, and also introduces the use scenarios of different notifications. As an introduction to Spring AOP, this article mainly focuses on code use. It aims to know how to use Spring AOP after reading this article. If you still don't know how to use it or encounter any problems in the process of using it, you can point it out in the comment area and I will reply and discuss with you in time, because your problem may also be my problem. I will reply in time. Subsequent articles will start with the source code and discuss it How Spring implements enhancements in different aspects.