Reference resources:
AOP
AOP is the abbreviation of Aspect Oriented Programming, which means: facet-oriented programming, a technology for unified maintenance of program functions through precompilation and run-time dynamic agents.With AOP, individual parts of business logic can be isolated, which reduces the coupling between parts of business logic, improves the reusability of programs, and improves the efficiency of development.
Terminology related to AOP
Advice
The notification describes the work to be done by the facet and when it will be executed.For example, if our log slice needs to record the length of each interface call, we need to record the current time before and after the interface call, and then take the difference.
- Before: Call the notification function before the target method is called;
- Post Notification: The notification function is invoked After the target method is invoked, regardless of the method's return result;
- AfterReturning: Invoke notification function after successful execution of target method;
- AfterThrowing: Invokes the notification function after the target method throws an exception;
- Around notification: The notification wraps the target method and executes custom behavior before and after the target method call.
JoinPoint
When notifications are applied, such as when an interface method is called, is the connection point to the log slice
Pointcut
The tangent points define the scope within which the notification function is applied.For example, log facets can be applied to all interfaces, which are the interface methods of all controller s.
Aspect
Aspects are a combination of notifications and tangent points that define when and where notifications should be applied
Introduction
Add a new method or property to an existing class without modifying it.
Weaving
The process of applying facets to the target object and creating a new proxy object.
Creating facets using annotations in Spring
Relevant Notes
- @Aspect: Used to define facets
- @Before: The notification method executes before the target method call
- @After: The notification method executes after the target method returns or throws an exception
- @AfterReturning: The notification method will execute after the target method returns
- @AfterThrowing: The notification method executes after the target method throws an exception
- @Around: The notification method encapsulates the target method
- @Pointcut: Define the tangent expression
Tangent expression
Specifies the scope in which the notification will be applied, and the expression format:
Execution (package to which a method modifier returns a type method. class name. method name (method parameter)
//The public methods of all classes in the com.macro.mall.tiny.controller package apply the notifications in the facets execution(public * com.macro.mall.tiny.controller.*.*(..)) //Notifications in facets apply to all methods in all classes under the com.macro.mall.tiny.service package and its subpackages execution(* com.macro.mall.tiny.service..*.*(..)) //Notifications in facets apply to all methods in the com.macro.mall.tiny.service.PmsBrandService class execution(* com.macro.mall.tiny.service.PmsBrandService.*(..))
Example
Add Log Information Encapsulation Class WebLog
Used to encapsulate log information that needs to be logged, including descriptions of operations, time consumed, url s, request parameters, and return results.
package com.macro.mall.tiny.dto; /** * Controller Layer's Log Encapsulation Class * Created by macro on 2018/4/26. */ public class WebLog { /** * Pedagogical operation */ private String description; /** * Operating Users */ private String username; /** * Operation time */ private Long startTime; /** * Time consumed */ private Integer spendTime; /** * Root Path */ private String basePath; /** * URI */ private String uri; /** * URL */ private String url; /** * Request Type */ private String method; /** * IP address */ private String ip; /** * Request parameters */ private Object parameter; /** * Return of Request */ private Object result; //getter,setter method omitted }
Add Face Class WebLogAspect
A log facet is defined to get the information needed for the log in a surround notification and apply to all public methods in the controller layer.
/** * Unified Log Processing Face * * @author yisheng.mikelv@foxmail.com 2020/3/12 17:22 */ @Aspect @Component @Order(1) public class WebLogAspect { private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class); @Pointcut("execution(public * org.developer.es.api.controller.*.*(..))") public void webLog(){ } @Before("webLog()") public void doBefore(JoinPoint joinPoint) throws Throwable{ } @AfterReturning(value = "webLog()", returning = "ret") public void doAfterReturning(Object ret) throws Throwable{ } //Wrap Notification=Pre+Target Method Execution+Post Notification @Around("webLog()") public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable{ long startTime = System.currentTimeMillis(); //Get the current request object ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); //Record request information WebLog webLog = new WebLog(); //The proceed method is used to initiate the target method execution Object result = joinPoint.proceed(); //Get Called Signature Signature signature = joinPoint.getSignature(); //Convert to method signature MethodSignature methodSignature = (MethodSignature) signature; //Methods to get controller s Method method = methodSignature.getMethod(); //If there is an ApiOperation annotation, get the value of the description if(method.isAnnotationPresent(ApiOperation.class)){ ApiOperation apiOperation = method.getAnnotation(ApiOperation.class); webLog.setDescription(apiOperation.value()); } long endTime = System.currentTimeMillis(); String urlStr = request.getRequestURL().toString(); webLog.setBasePath(StrUtil.removeSuffix(urlStr, URLUtil.url(urlStr).getPath())); webLog.setIp(request.getRemoteUser()); webLog.setMethod(request.getMethod()); webLog.setParameter(getParameter(method, joinPoint.getArgs())); webLog.setResult(result); webLog.setSpendTime((int) (endTime - startTime)); webLog.setStartTime(startTime); webLog.setUri(request.getRequestURI()); webLog.setUrl(request.getRequestURL().toString()); logger.info("{} \n", JSONUtil.parse(webLog)); return result; } /** * Get request parameters based on method and parameters passed in */ private Object getParameter(Method method, Object[] args) { List<Object> argList = new ArrayList<>(); //Get the parameters of the method Parameter[] parameters = method.getParameters(); for (int i = 0; i < parameters.length; i++) { //Use RequestBody comment-modified parameters as request parameters RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class); if(requestBody != null){ argList.add(args[i]); } //RequestParam annotated parameters as request parameters RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class); if (requestParam != null) { Map<String, Object> map = new HashMap<>(); String key = parameters[i].getName(); if (!StringUtils.isEmpty(requestParam.value())) { key = requestParam.value(); } map.put(key, args[i]); argList.add(map); } } if (argList.size() == 0) { return null; } else if (argList.size() == 1) { return argList.get(0); } else { return argList; } } }
Run result:
Expand
SpringBoot officially recommends logback-spring.xml
logback.xml: When an application is started, it is recognized directly by the log framework logback and used without going through SpringBoot
logback-spring.xml:The logback logging framework is not directly recognized, and the log configuration file is parsed by Spring Boot
SpringBoot loads logback-spring.xml
Reference resources:
logback profile loading process in Spring Boot
// org.springframework.boot.logging.logback.LogbackLoggingSystem @Override protected String[] getStandardConfigLocations() { return new String[] { "logback-test.groovy", "logback-test.xml", "logback.groovy", "logback.xml" }; }
Here you can see that the logback configuration file format supported in spring boot is to add'-spring'after the file name based on the logback-test.xml (logback-test.xml, logback.xml, etc.), such as logback-test-spring, logback-spring, etc.
/** * Return the spring config locations for this system. By default this method returns * a set of locations based on {@link #getStandardConfigLocations()}. * @return the spring config locations * @see #getSpringInitializationConfig() */ protected String[] getSpringConfigLocations() { String[] locations = getStandardConfigLocations(); for (int i = 0; i < locations.length; i++) { String extension = StringUtils.getFilenameExtension(locations[i]); locations[i] = locations[i].substring(0, locations[i].length() - extension.length() - 1) + "-spring." + extension; } return locations; }
Focus on the org.springframework.boot.logging.logback.LogbackLoggingSystem