Preface
AOP is the abbreviation for Aspect Oriented Programming. It is a concept that is opposite to object-oriented programming. In object-oriented programming, we tend to adopt concepts such as encapsulation, inheritance, and polymorphism to implement each function in the object. However, in actual situations, we also found that there is another requirement that a type of function is needed in many methods of many objects. For example, some methods for database access have transaction management requirements, and many methods require printing logs. In an object-oriented way, these same functions must be implemented in many places or called in many places. This is very cumbersome and is too closely coupled with these business-independent requirements. So later, aspect-oriented programming appeared to solve this type of problem, and made good supplements to object-oriented programming
concept
To understand tangent-oriented programming well, you must first understand some concepts of AOP. In Java, AspectJ implements the functions of AOP in a relatively complete way, but it is also more complex to use, so here is mainly to discuss Spring's AOP. Spring AOP adopts the principle of simplicity and adequateness to realize the core functions of AOP. Let’s talk about the specific concepts in AOP first
SprinBoot AOP implementation
We have used several chapters to describe the basic use of SpringBoot. So here we use SpringBoot and AOP to combine to implement a function of outputting all Rest interface input parameters and returning parameters logs.
Implement the rest service function.
According to the previous article, we will first build a SpringBoot project as shown in the following figure
demo project
SpringBoot project configuration
We configure SpringBoot projects as follows
server: port: 3030 servlet: context-path: /aop-demospring: jackson: date-format: yyyy-MM-dd HH:mm:ss serialization: indent-output: truelogging: level: com.yanggch: debug
The jackson-related configuration is to output objects into json strings and format the output.
Controller class that implements a rest interface
Here we implement two rest interfaces. One is to return hello information. One is to return the login information based on the input.
package com.yanggch.demo.aop.web;import com.yanggch.demo.aop.domain.LoginEntity;import com.yanggch.demo.aop.domain.SecurityEntity;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RestController;import java.util.Date;/** * Security-related rest service* * @author : Yang Gaochao* @since : 2018-05-27 */@RestController@RequestMapping("/api/v1/security")public class SecurityApi { @RequestMapping(value = "/login/{shopId}", method = RequestMethod.POST) public SecurityEntity login(@RequestBody LoginEntity loginEntity, @PathVariable Long shopId) { SecurityEntity securityEntity = new SecurityEntity(); securityEntity.setShopId(shopId); securityEntity.setAccount(loginEntity.getAccount()); securityEntity.setPwd(loginEntity.getPwd()); securityEntity.setLoginTime(new Date()); return securityEntity; } @RequestMapping(value = "/echo/{name}", method = RequestMethod.GET) public String login(@PathVariable String name) { return "hello," + name; }}First, we want to output the input parameters and return results of all Rest interfaces to the log through the AOP function.
Implement Web Aop functions.
package com.yanggch.demo.aop.comment;import com.fasterxml.jackson.databind.ObjectMapper;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/** * web interface log* * @author: Yang Gaochao* @since: 2018-05-27 */@Aspect@Componentpublic class WebLogAspect { private static Logger log = LoggerFactory.getLogger(WebLogAspect.class); private final ObjectMapper mapper; @Autowired public WebLogAspect(ObjectMapper mapper) { this.mapper = mapper; } @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)") public void webLog() { } @Before("webLog()") public void doBefore(JoinPoint joinPoint) { for (Object object : joinPoint.getArgs()) { if ( object instanceof MultipartFile || object instanceof HttpServletRequest || object instanceof HttpServletResponse ) { continue; } try { if (log.isDebugEnabled()) { log.debug( joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + " : request parameter : " + mapper.writeValueAsString(object) ); } } catch (Exception e) { e.printStackTrace(); } } } @AfterReturning(returning = "response", pointcut = "webLog()") public void doAfterReturning(Object response) throws Throwable { if (response != null) { log.debug("response parameter : " + mapper.writeValueAsString(response)); } }}Here are a few things to pay attention to.
test
In the foreground, the request is initiated through postman, and the background log input result is as follows
2018-05-27 19:58:42.941 DEBUG 86072 --- [nio-3030-exec-4] c.yanggch.demo.aop.comment.WebLogAspect : com.yanggch.demo.aop.web.SecurityApi.login : request parameter : {
"account" : "yanggch",
"pwd" : "123456"
}
2018-05-27 19:58:42.941 DEBUG 86072 --- [nio-3030-exec-4] c.yanggch.demo.aop.comment.WebLogAspect : com.yanggch.demo.aop.web.SecurityApi.login : request parameter : 2001
2018-05-27 19:58:42.942 DEBUG 86072 --- [nio-3030-exec-4] c.yanggch.demo.aop.comment.WebLogAspect : response parameter : {
"shopId" : 2001,
"account" : "yanggch",
"pwd" : "123456",
"loginTime" : "2018-05-27 11:58:42"
}
2018-05-27 19:58:45.796 DEBUG 86072 --- [nio-3030-exec-5] c.yanggch.demo.aop.comment.WebLogAspect : com.yanggch.demo.aop.web.SecurityApi.echo : request parameter : "yanggch"
2018-05-27 19:58:45.796 DEBUG 86072 --- [nio-3030-exec-5] c.yanggch.demo.aop.comment.WebLogAspect : response parameter : "hello,yanggch"
From this we can see that although we do not write the code for outputting the log in the rest interface method, we can automatically add the code for outputting the entry parameters and return parameters to each rest entry method through AOP and execute it correctly.
Other Instructions
The types of Advice and the AOP expression language for Pointcut are mentioned earlier. For specific references, please refer to them as follows.
Advice Type
AOP Expression Language
1. Method parameter matching
@args()
2. Method description matching
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
where returning type pattern, name pattern, and parameters pattern is necessary.
. ret-type-pattern: can be a class name that represents any return value, full path, etc.
*. name-pattern: Specify the method name, * represents all
.set represents all methods starting with set.
. parameters pattern: Specify method parameters (declared type), (..) represents all parameters, and () represents one parameter
. (,String) means that the first parameter is any value and the second is of type String.
3. Current AOP proxy object type matching
4. Target class matching
@target()
@within()
5. Matching methods marked with this annotation
@annotation()
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.