1. Introduction
During the development process, we often need to write many examples:
@GetMapping("/id/get") public Result getById( String id) throws Exception{ log.info("Request parameter is:"+id); verify(new VerifyParam("Department id", id)); Result result = new Result("Successfully obtained through id!", service.queryById(id)); log.info("Return message is:"+result.toString()); return result; }Print request parameters and return parameters, and these operations exist in each method, making our code more redundant. For this reason, we can use dynamic proxy to use print parameters and print return messages as sections, and use point-cut expressions to cut them into each method.
2. Steps
1. Introduce Aop-related dependencies:
<!--AOP-related dependencies--><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId></dependency>
After introducing dependencies, spring-aop will load the dependencies it needs. Spring uses aspectJ by default to implement notifications.
Among them, aspectjweaver.jar contains files that analyze aspectJ point-cut expressions. This dependency is also required when using point-cut expressions to handle transactions.
2. Configuration:
1) Create a configuration class:
/** * @Function Description: AOP class used for controller layer operations* @author Administrator */@Component // Handle objects to spring for management @Aspect // Represent this class as an aspect class ControllerAop {}The @Aspect annotation represents that it is an aspect management class, where point-cut expressions can be defined, and the aspectJ framework will parse it.
2) Define point-cut expression:
@Pointcut("execution(public * com.hzt.manage.*.web.controller..*.*(..))") // Pointcut expression public void privilege() { }Where @Pointcut represents this method as a point-cut expression. Its value is a point-cut expression, where the value can be omitted and its rough format is:
@Annotation (Expression tag + expression format)
For the format, the AspectJ point-cut indicators supported by Spring AOP are as follows:
1. execution: the connection point used to match the method execution;
2. within: used to match the execution of methods within the specified type;
3. This: Execution method used to match the current AOP proxy object type; note that the type matching of the AOP proxy object, which may include introducing interfaces and type matching;
4. Target: Execution method used to match the current target object type; note that the type matching of the target object is the type matching, so that the introduction of the interface is not included;
5. args: The execution method is used to match the parameters passed in by the currently executed method as the specified type;
6. @within: used to match so hold methods within the specified annotation type;
7. @target: Execution method used to match the current target object type, where the target object holds the specified annotation;
8. @args: Used to match the execution of the parameters passed in the currently executed method that holds the specified annotation;
9. @annotation: used to match the method that currently executes the method holds the specified annotation;
10. bean: Spring AOP extension, AspectJ does not have an execution method for matching Bean objects with a specific name;
11. Reference pointcut: means referring to other naming entry points, only @ApectJ style supports it, but not Schema style.
Args defines the parameters when executing the point-cut expression method:
@Pointcut(value="execution(public * com.hzt.manage.*.web.controller..*.*(..))&&args(param)",argNames="param") // Pointcut expression public void privilege1(String param) { }We focus on the expression of the connection point of the execution method, and its rough structure is:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
1. Modifier matching (modifier-pattern?) (can be omitted)
2. Return value matching (ret-type-pattern) can represent any return value for *, such as (String) represents only filtering the entry point that returns String type, class names of the full path, etc. (cannot be omitted)
3. Declaring-type-pattern? For example, *.manage represents the first-level package as arbitrary and the second-level package as the name of the manage. *..manage represents the subclass packages under all manage packages. com..*.comtroller represents all controller packages under com packages, etc., and * means that all packages match. (Not omitted)
4. Method name matching (name-pattern) can specify the method name or * represents all, get* represents all methods starting with get, or you can specify the prefix *get represents any method with arbitrary suffix of get (not omitted)
5. Parameter matching ((param-pattern)) can specify a specific parameter type, multiple parameters are separated by "," and each parameter can also be "*" to match parameters of any type, such as (String) means a method to match a String parameter; (*,String) means a method to match two parameters, the first parameter can be of any type, and the second parameter is of a String type; (..) can be used to represent any parameter (not omitted)
6. Exception type matching (throws-pattern?)
3. Define the facet method
@Around("privilege()") public Object around(ProceedingJoinPoint pjd) throws Throwable { // Get the method name String className = pjd.getSignature().getClass().getName(); // Get the execution method name String methodName = pjd.getSignature().getName(); /** Initialization log printing*/ Logger log = LoggerFactory.getLogger(className); // Define the return parameter Object result = null; // Record the start time long start = System.currentTimeMillis(); // Get method parameters Object[] args = pjd.getArgs(); String params = "The front-end request parameters are:"; //Get the request parameter collection and traverse and splice for (Object object : args) { params += object.toString() + ","; } params = params.substring(0, params.length() - 1); //Print the request parameter parameter log.info(className+" class "+methodName + "" + params); // Execute the target method result = pjd.proceed(); // Print the return message log.info("The method returns the message as:" + (result instanceof Results ? (Result) result : result)); // Get the execution time log.info(methodName + "The method execution time is:" + (System.currentTimeMillis() - start)); return result; }5. @Around surround notification, as shown in the above code, it is surround notification, which has the ProceedingJoinPoint parameter
Where the pjd.proceed(); method represents the execution of the target method and obtaining a return value of Object type. We can process the return value, such as decoration processing, etc.
The value of return is the result of the method execution. In the above code, first obtains the class name, method name, method request parameters, etc., performs printing splicing, and records the start time of method execution, and prints it to the log.
Then execute the method, obtain the method return result, print the execution time and execution result.
Finally, the execution result is returned. That is, the AOP section encoding of the request message and the return message is completed.
Where @Around represents it as a surrounding notification method, it has the following types:
1. @Before pre-notification, which has the request parameter JoinPoint, which is used to connect the connection details of the current connection point, generally including the method name and parameter value. The method body is executed before the method is executed, and the method parameters cannot be changed, nor the method execution results cannot be changed.
@Before(value = "privilege()") public void before(JoinPoint joinPoint) { }2. @After Post notification: Notification that execution is performed regardless of whether an exception occurs after the target method is executed. In the post-notification, the execution result of the target method cannot be accessed (because an exception may occur), and the execution result of the method cannot be changed.
@Before(value = "privilege()") public void after(JoinPoint joinPoint) { }3. @AfterReturning returns a notification. The notification that is executed only when the target method is executed is the same as the post-arranged method. It can access the method execution result (because of normal execution) and the connection details of the method, but cannot change the method execution result.
@AfterReturning(value = "privilege()") public void afterReturning(JoinPoint joinPoint,Object result) { }The return value stored in result is the method.
4. @AfterThrowing Exception Notification: Code that will be executed only when an exception occurs in the target method. The throwing attribute represents an exception thrown during execution of the method body, and its value must be consistent with the value of Exception in the method.
@AfterThrowing(value="privilege()", throwing="ex") public void exceed(JoinPoint joinPoint, Exception ex) { }3. Test
Write a Controller method
@RestController@RequestMapping("/api/v1/dept")public class DeptController extends BaseController{ /** Logging class*/ private Logger log = LoggerFactory.getLogger(getClass()); /** My own service */ @Autowired private DeptService service; /** * @Function description: Method for querying department content based on id* @return Dept */ @GetMapping("/id/get") public Result getById( String id) throws Exception{ verify(new VerifyParam("department id", id)); return new Result("Successfully obtained through id!", service.queryById(id)); }}In this way, the method in our controller layer is greatly concise.
Test results:
2018-04-10 22:59:27.468 INFO 1460 --- [nio-8088-exec-5] nProceedingJoinPoint$MethodSignatureImpl: The front-end request parameter of getById is: 22
2018-04-10 22:59:27.470 INFO 1460 --- [nio-8088-exec-5] nProceedingJoinPoint$MethodSignatureImpl: The method returns the message as:Result [result_code=suc, result_message=Successfully obtained department information through id!, data=Dept [id=22, no=22, name=22, manager=22, description=22, phone=22, createTime=Thu Apr 19 23:38:37 CST 2018, editTime=null]]
2018-04-10 22:59:27.470 INFO 1460 --- [nio-8088-exec-5] nProceedingJoinPoint$MethodSignatureImpl: The execution time of the getById method is: 2
This allows you to print request parameters, return results, execution time, etc. with elegant, concise and concise printing!