04introduction and use of spring AOP
AOP: Aspect Oriented Programming
OOP: Object Oriented Programming
Aspect oriented programming: Based on the new programming idea based on OOP, the main object oriented by OOP is class, while the main object oriented by AOP is aspect, which plays a very important role in log processing, security management, transaction management and so on. AOP is an important core point in Spring. Although the IOC container does not rely on AOP, AOP provides very powerful functions to supplement IOC. Generally speaking, it is a programming method that dynamically cuts a piece of code into the specified position of the specified method to run during the program running.
1. Concept of AOP
Why introduce AOP?
Calculator.java
package com.mashibing.inter; public interface Calculator { public int add(int i,int j); public int sub(int i,int j); public int mult(int i,int j); public int div(int i,int j); }
MyCalculator.java
package com.mashibing.inter; public class MyCalculator implements Calculator { public int add(int i, int j) { int result = i + j; return result; } public int sub(int i, int j) { int result = i - j; return result; } public int mult(int i, int j) { int result = i * j; return result; } public int div(int i, int j) { int result = i / j; return result; } }
MyTest.java
public class MyTest { public static void main(String[] args) throws SQLException { MyCalculator myCalculator = new MyCalculator(); System.out.println(myCalculator.add(1, 2)); } }
This code is very simple, which is the code implementation of the basic javase. At this time, what should we do if we need to add the log function? We can only add the log output in each method. At the same time, it will become very troublesome if we need to modify it.
MyCalculator.java
package com.mashibing.inter; public class MyCalculator implements Calculator { public int add(int i, int j) { System.out.println("add Method starts execution. The parameters are:"+i+","+j); int result = i + j; System.out.println("add Method start completion result is:"+result); return result; } public int sub(int i, int j) { System.out.println("sub Method starts execution. The parameters are:"+i+","+j); int result = i - j; System.out.println("add Method start completion result is:"+result); return result; } public int mult(int i, int j) { System.out.println("mult Method starts execution. The parameters are:"+i+","+j); int result = i * j; System.out.println("add Method start completion result is:"+result); return result; } public int div(int i, int j) { System.out.println("div Method starts execution. The parameters are:"+i+","+j); int result = i / j; System.out.println("add Method start completion result is:"+result); return result; } }
Consider abstracting the log processing into a tool class for implementation:
LogUtil.java
package com.mashibing.util; import java.util.Arrays; public class LogUtil { public static void start(Object ... objects){ System.out.println("XXX Method starts execution with the following parameters:"+ Arrays.asList(objects)); } public static void stop(Object ... objects){ System.out.println("XXX Method execution ends with:"+ Arrays.asList(objects)); } }
MyCalculator.java
package com.mashibing.inter; import com.mashibing.util.LogUtil; public class MyCalculator implements Calculator { public int add(int i, int j) { LogUtil.start(i,j); int result = i + j; LogUtil.stop(result); return result; } public int sub(int i, int j) { LogUtil.start(i,j); int result = i - j; LogUtil.stop(result); return result; } public int mult(int i, int j) { LogUtil.start(i,j); int result = i * j; LogUtil.stop(result); return result; } public int div(int i, int j) { LogUtil.start(i,j); int result = i / j; LogUtil.stop(result); return result; } }
After abstracting in the above way, the code is indeed much simpler, but you should have found that the output information does not contain the specific method name. We want to dynamically obtain the method name, parameters, results and other related information during the program running. At this time, we can use the dynamic agent.
CalculatorProxy.java
package com.mashibing.proxy; import com.mashibing.inter.Calculator; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; /** * A class that helps Calculator generate proxy objects */ public class CalculatorProxy { /** * * Create a dynamic proxy object for the passed in parameter object * @param calculator Proxied object * @return */ public static Calculator getProxy(final Calculator calculator){ //Class loader of the proxied object ClassLoader loader = calculator.getClass().getClassLoader(); //Interface of the proxied object Class<?>[] interfaces = calculator.getClass().getInterfaces(); //Method executor, which executes the target method of the proxy object InvocationHandler h = new InvocationHandler() { /** * Execution target method * @param proxy Proxy object for jdk. Do not operate this object at any time * @param method The method of the target object currently to be executed * @param args The parameter value passed in when this method is called * @return * @throws Throwable */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //Use reflection to execute the target method, and the return value of the target method after execution // System.out.println("this is the method of dynamic agent execution"); Object result = null; try { System.out.println(method.getName()+"Method starts execution. The parameters are:"+ Arrays.asList(args)); result = method.invoke(calculator, args); System.out.println(method.getName()+"Method execution is complete, and the result is:"+ result); } catch (Exception e) { System.out.println(method.getName()+"Exception occurred in method:"+ e.getMessage()); } finally { System.out.println(method.getName()+"Method execution is over......"); } //Return the result return result; } }; Object proxy = Proxy.newProxyInstance(loader, interfaces, h); return (Calculator) proxy; } }
We can see that this method is more flexible and does not need to add additional code to the business method, which is the common way. If you want to pursue perfection, you can also use the above log tool class to improve it.
LogUtil.java
package com.mashibing.util; import java.lang.reflect.Method; import java.util.Arrays; public class LogUtil { public static void start(Method method, Object ... objects){ // System.out.println("XXX method starts to execute, and the parameters used are:" + Arrays.asList(objects)); System.out.println(method.getName()+"Method starts execution. The parameters are:"+ Arrays.asList(objects)); } public static void stop(Method method,Object ... objects){ // System. Out. Println ("the execution of XXX method ends, and the result is:" + Arrays.asList(objects)); System.out.println(method.getName()+"Method starts execution. The parameters are:"+ Arrays.asList(objects)); } public static void logException(Method method,Exception e){ System.out.println(method.getName()+"Exception occurred in method:"+ e.getMessage()); } public static void end(Method method){ System.out.println(method.getName()+"Method execution is over......"); } }
CalculatorProxy.java
package com.mashibing.proxy; import com.mashibing.inter.Calculator; import com.mashibing.util.LogUtil; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; /** * A class that helps Calculator generate proxy objects */ public class CalculatorProxy { /** * * Create a dynamic proxy object for the passed in parameter object * @param calculator Proxied object * @return */ public static Calculator getProxy(final Calculator calculator){ //Class loader of the proxied object ClassLoader loader = calculator.getClass().getClassLoader(); //Interface of the proxied object Class<?>[] interfaces = calculator.getClass().getInterfaces(); //Method executor, which executes the target method of the proxy object InvocationHandler h = new InvocationHandler() { /** * Execution target method * @param proxy Proxy object for jdk. Do not operate this object at any time * @param method The method of the target object currently to be executed * @param args The parameter value passed in when this method is called * @return * @throws Throwable */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //Use reflection to execute the target method, and the return value of the target method after execution // System.out.println("this is the method of dynamic agent execution"); Object result = null; try { LogUtil.start(method,args); result = method.invoke(calculator, args); LogUtil.stop(method,args); } catch (Exception e) { LogUtil.logException(method,e); } finally { LogUtil.end(method); } //Return the result return result; } }; Object proxy = Proxy.newProxyInstance(loader, interfaces, h); return (Calculator) proxy; } }
Many students may feel perfect after seeing the above code, but it should be noted that this implementation of dynamic proxy calls the basic implementation of jdk. If the target object of the proxy does not implement any interface, it is impossible to create a proxy object for it, which is also a fatal defect. In Spring, we can easily implement the above functions without writing such complex code. Of course, the underlying implementation of Spring AOP also depends on dynamic agents.
Core concepts and terms of AOP
- Aspect: refers to the modularization of a concern, which may cross cut multiple objects. Transaction management is an example of crosscutting concerns in enterprise Java applications. In Spring AOP, facets can be implemented using the schema based approach of general classes or @ aspect annotation (@ AspectJ annotation) in ordinary classes.
- Join point: a specific point in the process of program execution, such as the time point of a method call or the time point of exception handling. In Spring AOP, a join point always represents the execution of a method.
- Advice: an action performed on a specific connection point of the slice. There are many types of notifications, including "around", "before" and "after". The types of notifications will be discussed in later chapters. Many AOP frameworks, including Spring, use interceptors as notification models and maintain a chain of interceptors centered on connection points.
- Pointcut: an assertion that matches the join point. Notifications are associated with the pointcut expressions and run on join points that satisfy pointcut (for example, when executing a method with the a specific name). How pointcut expressions match join points is the core of AOP: Spring uses AspectJ pointcut semantics by default.
- Introduction: declare additional methods or fields of a certain type. Spring allows the introduction of new interfaces (and a corresponding implementation) to any notified object. For example, you can use the introduction to make bean s implement the IsModified interface to simplify the caching mechanism (in the AspectJ community, the introduction is also called internal type declaration (inter)).
- Target object: an object notified by one or more facets. Also known as the advised object. Since Spring AOP is implemented through a runtime proxy, this object is always a proxied object.
- AOP proxy: an object created by the AOP framework to implement aspect contract (including notification method execution and other functions). In Spring, AOP proxy can be JDK dynamic proxy or CGLIB proxy.
- Weaving: the process of connecting aspects to other application types or objects and creating a notified object. This process can be done at compile time (for example, using the AspectJ compiler), class loading, or runtime. Spring, like other pure Java AOP frameworks, is woven at run time.
Notification type of AOP
- Before advice: a notification that runs before the connection point but cannot prevent the execution process from entering the connection point (unless it throws an exception).
- After returning advice: a notification executed after the connection point completes normally (for example, when the method does not throw any exceptions and returns normally).
- After throwing advice: a notification executed when a method throws an exception and exits.
- After (finally) advice: a notification executed when the connection point exits (whether it returns normally or exits abnormally).
- Around Advice: notifications around connection points, such as method calls. This is the most powerful type of notification,. Wrap notifications can complete custom behavior before and after method calls. It can choose whether to continue to execute the connection point, directly return the custom return value, or throw an exception to end the execution.
AOP application scenarios
- Log management
- Authority authentication
- security check
- Transaction control
2. Simple configuration of Spring AOP
In the above code, we implement the log function through dynamic agent, but it is troublesome. Now we will use the function of spring aop to realize this requirement. In fact, in a popular way, we will replace the tool class of LogUtil with another implementation method.
1. Add pom dependency
<!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.5</version> </dependency> <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance --> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.3.RELEASE</version> </dependency>
2. Write configuration
-
Add the target class and facet class to the IOC container, and add component annotations on the corresponding classes
-
Add @ Component annotation to LogUtil
-
Add @ Service annotation to MyCalculator
-
Add auto scan configuration
<!--Don't forget to add context Namespace--> <context:component-scan base-package="com.mashibing"></context:component-scan>
-
-
Set the facet class in the program
- Add @ Aspect annotation in LogUtil.java
-
Set when and where the methods in the aspect class are executed
package com.mashibing.util; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import java.lang.reflect.Method; import java.util.Arrays; @Component @Aspect public class LogUtil { /* Set when the following methods will run @Before:Run before target method: pre notification @After:Run after target method: Post notification @AfterReturning:After the target method returns normally: return notification @AfterThrowing:Start running after the target method throws an exception: exception notification @Around:Surround: surround notifications After the annotation is written, you need to set which methods to execute and use expressions execution(Access modifier return value type (full name of method) */ @Before("execution( public int com.mashibing.inter.MyCalculator.*(int,int))") public static void start(){ // System.out.println("XXX method starts to execute, and the parameters used are:" + Arrays.asList(objects)); // System.out.println(method.getName() + "the method starts to execute, and the parameters are:" + Arrays.asList(objects)); System.out.println("Method starts execution. The parameters are:"); } @AfterReturning("execution( public int com.mashibing.inter.MyCalculator.*(int,int))") public static void stop(){ // System. Out. Println ("the execution of XXX method ends, and the result is:" + Arrays.asList(objects)); // System.out.println(method.getName() + "method execution ends, and the result is:" + Arrays.asList(objects)); System.out.println("Method execution is complete, and the result is:"); } @AfterThrowing("execution( public int com.mashibing.inter.MyCalculator.*(int,int))") public static void logException(){ // System.out.println(method.getName() + "method exception:" + e.getMessage()); System.out.println("Exception occurred in method:"); } @After("execution( public int com.mashibing.inter.MyCalculator.*(int,int))") public static void end(){ // System.out.println(method.getName() + "method execution is over...); System.out.println("Method execution is over......"); } }
-
Enable annotation based aop
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" 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 https://www.springframework.org/schema/aop/spring-aop.xsd "> <context:component-scan base-package="com.mashibing"></context:component-scan> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
3. Testing
MyTest.java
import com.mashibing.inter.Calculator; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { public static void main(String[] args){ ApplicationContext context = new ClassPathXmlApplicationContext("aop.xml"); Calculator bean = context.getBean(Calculator.class); bean.add(1,1); } }
The dynamic proxy method of spring AOP is the jdk built-in method, and the component saved in the container is the proxy object com.sun.proxy.$Proxy object
4. Create proxy objects through cglib
MyCalculator.java
package com.mashibing.inter; import org.springframework.stereotype.Service; @Service public class MyCalculator { public int add(int i, int j) { int result = i + j; return result; } public int sub(int i, int j) { int result = i - j; return result; } public int mult(int i, int j) { int result = i * j; return result; } public int div(int i, int j) { int result = i / j; return result; } }
MyTest.java
public class MyTest { public static void main(String[] args){ ApplicationContext context = new ClassPathXmlApplicationContext("aop.xml"); MyCalculator bean = context.getBean(MyCalculator.class); bean.add(1,1); System.out.println(bean); System.out.println(bean.getClass()); } }
The proxy object can be created by cglib. At this time, there is no need to implement any interface. The proxy object is
class com.mashibing.inter.MyCalculator E n h a n c e r B y S p r i n g C G L I B EnhancerBySpringCGLIB EnhancerBySpringCGLIB1f93b605 type
To sum up: in the spring container, if there is an interface, the dynamic proxy provided by jdk will be used. If there is no interface, the dynamic proxy of cglib will be used. The implementation principle of dynamic agent will be described in detail later.
be careful:
1. Pointcut expression
When using expressions, you can also use wildcards in addition to the previous writing:
*:
1. Match one or more characters
execution( public int com.mashibing.inter.My*alculator.*(int,int))
2. Match any parameter,
execution( public int com.mashibing.inter.MyCalculator.*(int,*))
3. Only one layer of path can be matched. If there are multiple layers of directories under the project path, then * can only match one layer of path
4. The permission location cannot use *. If you want to represent all permissions, you can leave it blank
execution( * com.mashibing.inter.MyCalculator.*(int,*))
...:
1. Match multiple parameters of any type
execution( * com.mashibing.inter.MyCalculator.*(...))
2. Match any multi-layer path
execution( * com.mashibing...MyCalculator.*(...))
There are N different ways to write expressions, but there is the laziest and most accurate way:
The laziest way: execution(* * (...)) or execution(* *. * (...))
The most accurate way: execution (public int com. Mashing. Inter. Mycalculator. Add (int, int))
In addition, & &, |, |, are supported in expressions! The way
& &: two expressions at the same time
execution( public int com.mashibing.inter.MyCalculator.*(...)) && execution(* *.*(int,int) )
||: any expression can be satisfied
execution( public int com.mashibing.inter.MyCalculator.*(...)) && execution(* *.*(int,int) )
!: As long as it is not in this position, you can cut in
& &: two expressions at the same time
execution( public int com.mashibing.inter.MyCalculator.*(...))
2. Execution order of notification methods
In the previous code, you have always had doubts about the execution order of the notification. In fact, the execution result is not wrong. You should pay attention to:
1. Normal execution: @ Before - > @ after - > @ afterreturning
2. Abnormal execution: @ Before - > @ after - > @ afterthrowing
3. Get method details
In the above case, we did not get the detailed information of the Method, such as Method name, parameter list, etc. to get it, we just need to add the JoinPoint parameter.
LogUtil.java
package com.mashibing.util; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import java.util.Arrays; @Component @Aspect public class LogUtil { @Before("execution( public int com.mashibing.inter.MyCalculator.*(int,int))") public static void start(JoinPoint joinPoint){ Object[] args = joinPoint.getArgs(); String name = joinPoint.getSignature().getName(); System.out.println(name+"Method starts execution. The parameters are:"+ Arrays.asList(args)); } @AfterReturning("execution( public int com.mashibing.inter.MyCalculator.*(int,int))") public static void stop(JoinPoint joinPoint){ String name = joinPoint.getSignature().getName(); System.out.println(name+"Method execution is complete, and the result is:"); } @AfterThrowing("execution( public int com.mashibing.inter.MyCalculator.*(int,int))") public static void logException(JoinPoint joinPoint){ String name = joinPoint.getSignature().getName(); System.out.println(name+"Exception occurred in method:"); } @After("execution( public int com.mashibing.inter.MyCalculator.*(int,int))") public static void end(JoinPoint joinPoint){ String name = joinPoint.getSignature().getName(); System.out.println(name+"Method execution is over......"); } }
Just got the method information, but if you need to get the result, you need to add another method parameter and tell spring which parameter to use to receive the result
LogUtil.java
@AfterReturning(value = "execution( public int com.mashibing.inter.MyCalculator.*(int,int))",returning = "result") public static void stop(JoinPoint joinPoint,Object result){ String name = joinPoint.getSignature().getName(); System.out.println(name+"Method execution is complete, and the result is:"+result); }
The exception information can also be obtained in the same way
LogUtil.java
@AfterThrowing(value = "execution( public int com.mashibing.inter.MyCalculator.*(int,int))",throwing = "exception") public static void logException(JoinPoint joinPoint,Exception exception){ String name = joinPoint.getSignature().getName(); System.out.println(name+"Exception occurred in method:"+exception); }
4. spring's requirements for passing methods
Spring's requirements for notification methods are not very high. You can arbitrarily change the return value of the method and the access modifier of the method, but the only thing you can't modify is the parameters of the method. There will be an error in parameter binding. The reason is that the notification method is called by spring using reflection, and the value of the parameters of this method must be determined every time the method is called.
LogUtil.java
@After("execution( public int com.mashibing.inter.MyCalculator.*(int,int))") private int end(JoinPoint joinPoint,String aa){ // System.out.println(method.getName() + "method execution is over...); String name = joinPoint.getSignature().getName(); System.out.println(name+"Method execution is over......"); return 0; }
5. Extraction of expressions
If the expressions of multiple methods are consistent in actual use, consider extracting the pointcut expression:
a. an unimplemented empty method that returns void
b. mark @ Potintcut annotation on the method
package com.mashibing.util; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import java.util.Arrays; @Component @Aspect public class LogUtil { @Pointcut("execution( public int com.mashibing.inter.MyCalculator.*(int,int))") public void myPoint(){} @Before("myPoint()") public static void start(JoinPoint joinPoint){ Object[] args = joinPoint.getArgs(); String name = joinPoint.getSignature().getName(); System.out.println(name+"Method starts execution. The parameters are:"+ Arrays.asList(args)); } @AfterReturning(value = "myPoint()",returning = "result") public static void stop(JoinPoint joinPoint,Object result){ String name = joinPoint.getSignature().getName(); System.out.println(name+"Method execution is complete, and the result is:"+result); } @AfterThrowing(value = "myPoint()",throwing = "exception") public static void logException(JoinPoint joinPoint,Exception exception){ String name = joinPoint.getSignature().getName(); System.out.println(name+"Exception occurred in method:"+exception.getMessage()); } @After("myPoint()") private int end(JoinPoint joinPoint){ String name = joinPoint.getSignature().getName(); System.out.println(name+"Method execution is over......"); return 0; } }
6. Use of surround notifications
LogUtil.java
package com.mashibing.util; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import java.util.Arrays; @Component @Aspect public class LogUtil { @Pointcut("execution( public int com.mashibing.inter.MyCalculator.*(int,int))") public void myPoint(){} /** * Surround notifications are the most powerful notifications in spring * @param proceedingJoinPoint * @return */ @Around("myPoint()") public Object myAround(ProceedingJoinPoint proceedingJoinPoint){ Object[] args = proceedingJoinPoint.getArgs(); String name = proceedingJoinPoint.getSignature().getName(); Object proceed = null; try { System.out.println("Surround pre notification:"+name+"Method, the parameter is"+Arrays.asList(args)); //Using reflection to call the target method is method.invoke() proceed = proceedingJoinPoint.proceed(args); System.out.println("Surround return notification:"+name+"Method, the return value is"+proceed); } catch (Throwable e) { System.out.println("Surround exception notification"+name+"Method has an exception. The exception information is:"+e); }finally { System.out.println("Surround post notification"+name+"Method end"); } return proceed; } }
Summary: the execution order of the surrounding notice is better than that of the ordinary notice. The specific execution order is as follows:
Surround pre – > normal pre – > target method execution – > surround normal end / exception – > surround post – > normal post – > normal return or exception.
However, it should be noted that if an exception occurs, the surround notification will handle or catch the exception. Ordinary exception notifications cannot be received. Therefore, the best way is to throw an exception in the surround exception notification.
7. Sequence of multi slice operation
If there are multiple aspects to execute, what is the order?
LogUtil.java
package com.mashibing.util; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import java.util.Arrays; @Component @Aspect public class LogUtil { @Pointcut("execution( public int com.mashibing.inter.MyCalculator.*(int,int))") public void myPoint(){} @Before("myPoint()") public static void start(JoinPoint joinPoint){ // System.out.println("XXX method starts to execute, and the parameters used are:" + Arrays.asList(objects)); // System.out.println(method.getName() + "the method starts to execute, and the parameters are:" + Arrays.asList(objects)); Object[] args = joinPoint.getArgs(); String name = joinPoint.getSignature().getName(); System.out.println("Log:"+name+"Method starts execution. The parameters are:"+ Arrays.asList(args)); } @AfterReturning(value = "myPoint()",returning = "result") public static void stop(JoinPoint joinPoint,Object result){ // System. Out. Println ("the execution of XXX method ends, and the result is:" + Arrays.asList(objects)); // System.out.println(method.getName() + "method execution ends, and the result is:" + Arrays.asList(objects)); String name = joinPoint.getSignature().getName(); System.out.println("Log:"+name+"Method execution is complete, and the result is:"+result); } @AfterThrowing(value = "myPoint()",throwing = "exception") public static void logException(JoinPoint joinPoint,Exception exception){ // System.out.println(method.getName() + "method exception:" + e.getMessage()); String name = joinPoint.getSignature().getName(); System.out.println("Log:"+name+"Exception occurred in method:"+exception.getMessage()); } @After("myPoint()") private int end(JoinPoint joinPoint){ // System.out.println(method.getName() + "method execution is over...); String name = joinPoint.getSignature().getName(); System.out.println("Log:"+name+"Method execution is over......"); return 0; } /** * Surround notifications are the most powerful notifications in spring * @param proceedingJoinPoint * @return */ //@Around("myPoint()") public Object myAround(ProceedingJoinPoint proceedingJoinPoint){ Object[] args = proceedingJoinPoint.getArgs(); String name = proceedingJoinPoint.getSignature().getName(); Object proceed = null; try { System.out.println("Surround pre notification:"+name+"Method, the parameter is"+Arrays.asList(args)); //Using reflection to call the target method is method.invoke() proceed = proceedingJoinPoint.proceed(args); System.out.println("Surround return notification:"+name+"Method, the return value is"+proceed); } catch (Throwable e) { System.out.println("Surround exception notification"+name+"Method has an exception. The exception information is:"+e); }finally { System.out.println("Surround post notification"+name+"Method end"); } return proceed; } }
SecurityAspect.java
package com.mashibing.util; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import java.util.Arrays; @Component @Aspect public class SecurityAspect { @Before("com.mashibing.util.LogUtil.myPoint()") public static void start(JoinPoint joinPoint){ Object[] args = joinPoint.getArgs(); String name = joinPoint.getSignature().getName(); System.out.println("Security:"+name+"Method starts execution. The parameters are:"+ Arrays.asList(args)); } @AfterReturning(value = "com.mashibing.util.LogUtil.myPoint()",returning = "result") public static void stop(JoinPoint joinPoint,Object result){ String name = joinPoint.getSignature().getName(); System.out.println("Security:"+name+"Method execution is complete, and the result is:"+result); } @AfterThrowing(value = "com.mashibing.util.LogUtil.myPoint()",throwing = "exception") public static void logException(JoinPoint joinPoint,Exception exception){ String name = joinPoint.getSignature().getName(); System.out.println("Security:"+name+"Exception occurred in method:"+exception.getMessage()); } @After("com.mashibing.util.LogUtil.myPoint()") private int end(JoinPoint joinPoint){ String name = joinPoint.getSignature().getName(); System.out.println("Security:"+name+"Method execution is over......"); return 0; } /** * Surround notifications are the most powerful notifications in spring * @param proceedingJoinPoint * @return */ //@Around("myPoint()") public Object myAround(ProceedingJoinPoint proceedingJoinPoint){ Object[] args = proceedingJoinPoint.getArgs(); String name = proceedingJoinPoint.getSignature().getName(); Object proceed = null; try { System.out.println("Surround pre notification:"+name+"Method, the parameter is"+Arrays.asList(args)); //Using reflection to call the target method is method.invoke() proceed = proceedingJoinPoint.proceed(args); System.out.println("Surround return notification:"+name+"Method, the return value is"+proceed); } catch (Throwable e) { System.out.println("Surround exception notification"+name+"Method has an exception. The exception information is:"+e); }finally { System.out.println("Surround post notification"+name+"Method end"); } return proceed; } }
In spring, the default execution is in the dictionary Order of the section names. However, if you want to change the specific execution Order yourself, you can use the @ Order annotation. The smaller the value, the higher the priority.
LogUtil.java
package com.mashibing.util; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import java.util.Arrays; @Component @Aspect @Order(2) public class LogUtil { @Pointcut("execution( public int com.mashibing.inter.MyCalculator.*(int,int))") public void myPoint(){} @Before("myPoint()") public static void start(JoinPoint joinPoint){ // System.out.println("XXX method starts to execute, and the parameters used are:" + Arrays.asList(objects)); // System.out.println(method.getName() + "the method starts to execute, and the parameters are:" + Arrays.asList(objects)); Object[] args = joinPoint.getArgs(); String name = joinPoint.getSignature().getName(); System.out.println("Log:"+name+"Method starts execution. The parameters are:"+ Arrays.asList(args)); } @AfterReturning(value = "myPoint()",returning = "result") public static void stop(JoinPoint joinPoint,Object result){ // System. Out. Println ("the execution of XXX method ends, and the result is:" + Arrays.asList(objects)); // System.out.println(method.getName() + "method execution ends, and the result is:" + Arrays.asList(objects)); String name = joinPoint.getSignature().getName(); System.out.println("Log:"+name+"Method execution is complete, and the result is:"+result); } @AfterThrowing(value = "myPoint()",throwing = "exception") public static void logException(JoinPoint joinPoint,Exception exception){ // System.out.println(method.getName() + "method exception:" + e.getMessage()); String name = joinPoint.getSignature().getName(); System.out.println("Log:"+name+"Exception occurred in method:"+exception.getMessage()); } @After("myPoint()") private int end(JoinPoint joinPoint){ // System.out.println(method.getName() + "method execution is over...); String name = joinPoint.getSignature().getName(); System.out.println("Log:"+name+"Method execution is over......"); return 0; } /** * Surround notifications are the most powerful notifications in spring * @param proceedingJoinPoint * @return */ //@Around("myPoint()") public Object myAround(ProceedingJoinPoint proceedingJoinPoint){ Object[] args = proceedingJoinPoint.getArgs(); String name = proceedingJoinPoint.getSignature().getName(); Object proceed = null; try { System.out.println("Surround pre notification:"+name+"Method, the parameter is"+Arrays.asList(args)); //Using reflection to call the target method is method.invoke() proceed = proceedingJoinPoint.proceed(args); System.out.println("Surround return notification:"+name+"Method, the return value is"+proceed); } catch (Throwable e) { System.out.println("Surround exception notification"+name+"Method has an exception. The exception information is:"+e); }finally { System.out.println("Surround post notification"+name+"Method end"); } return proceed; } }
SecurityAspect.java
package com.mashibing.util; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import java.util.Arrays; @Component @Aspect @Order(1) public class SecurityAspect { @Before("com.mashibing.util.LogUtil.myPoint()") public static void start(JoinPoint joinPoint){ Object[] args = joinPoint.getArgs(); String name = joinPoint.getSignature().getName(); System.out.println("Security:"+name+"Method starts execution. The parameters are:"+ Arrays.asList(args)); } @AfterReturning(value = "com.mashibing.util.LogUtil.myPoint()",returning = "result") public static void stop(JoinPoint joinPoint,Object result){ String name = joinPoint.getSignature().getName(); System.out.println("Security:"+name+"Method execution is complete, and the result is:"+result); } @AfterThrowing(value = "com.mashibing.util.LogUtil.myPoint()",throwing = "exception") public static void logException(JoinPoint joinPoint,Exception exception){ String name = joinPoint.getSignature().getName(); System.out.println("Security:"+name+"Exception occurred in method:"+exception.getMessage()); } @After("com.mashibing.util.LogUtil.myPoint()") private int end(JoinPoint joinPoint){ String name = joinPoint.getSignature().getName(); System.out.println("Security:"+name+"Method execution is over......"); return 0; } /** * Surround notifications are the most powerful notifications in spring * @param proceedingJoinPoint * @return */ //@Around("myPoint()") public Object myAround(ProceedingJoinPoint proceedingJoinPoint){ Object[] args = proceedingJoinPoint.getArgs(); String name = proceedingJoinPoint.getSignature().getName(); Object proceed = null; try { System.out.println("Surround pre notification:"+name+"Method, the parameter is"+Arrays.asList(args)); //Using reflection to call the target method is method.invoke() proceed = proceedingJoinPoint.proceed(args); System.out.println("Surround return notification:"+name+"Method, the return value is"+proceed); } catch (Throwable e) { System.out.println("Surround exception notification"+name+"Method has an exception. The exception information is:"+e); }finally { System.out.println("Surround post notification"+name+"Method end"); } return proceed; } }
If you need to add surround notifications, what is the specific execution order?
Because the surround notification is introduced in the aspect layer when it is added, the surround notification will be executed in which aspect when it is added.
3. Configuration based AOP configuration
Before we explained the annotation based AOP configuration, let's start with the xml based configuration. Although there are many annotation methods used in current enterprise development, you can't help it. Therefore, you need to configure it simply. Annotation configuration is fast and simple, and the configuration method is perfect.
1. Delete all comments
2. Add profile
aop.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" 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 https://www.springframework.org/schema/aop/spring-aop.xsd "> <context:component-scan base-package="com.mashibing"></context:component-scan> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <bean id="logUtil" class="com.mashibing.util.LogUtil2"></bean> <bean id="securityAspect" class="com.mashibing.util.SecurityAspect"></bean> <bean id="myCalculator" class="com.mashibing.inter.MyCalculator"></bean> <aop:config> <aop:pointcut id="globalPoint" expression="execution(public int com.mashibing.inter.MyCalculator.*(int,int))"/> <aop:aspect ref="logUtil"> <aop:pointcut id="mypoint" expression="execution(public int com.mashibing.inter.MyCalculator.*(int,int))"/> <aop:before method="start" pointcut-ref="mypoint"></aop:before> <aop:after method="end" pointcut-ref="mypoint"></aop:after> <aop:after-returning method="stop" pointcut-ref="mypoint" returning="result"></aop:after-returning> <aop:after-throwing method="logException" pointcut-ref="mypoint" throwing="exception"></aop:after-throwing> <aop:around method="myAround" pointcut-ref="mypoint"></aop:around> </aop:aspect> <aop:aspect ref="securityAspect"> <aop:before method="start" pointcut-ref="globalPoint"></aop:before> <aop:after method="end" pointcut-ref="globalPoint"></aop:after> <aop:after-returning method="stop" pointcut-ref="globalPoint" returning="result"></aop:after-returning> <aop:after-throwing method="logException" pointcut-ref="globalPoint" throwing="exception"></aop:after-throwing> <aop:around method="myAround" pointcut-ref="mypoint"></aop:around> </aop:aspect> </aop:config> </beans>