AOP is introduced
AOP overview
AOP is aspect-oriented Programming, that is, aspect-oriented Programming. An Aspect is a new modularity mechanism used to describe cross-cutting concerns scattered across objects, classes, or functions. Separating crosscutting concerns from points of concern is a core concept of section-oriented programming. Separation of concerns allows domain-specific code to be separated from business logic, which no longer needs to contain calls to domain-specific code, such as logging, security, and so on, for some common modules. The code is more neat and clear by cutting out the code, and the repeated code is extracted for separate maintenance. When it is needed, the code of these common modules will be uniformly called. Such a class is a basic module, which is convenient for unified maintenance and expansion and update. AOP is a mechanism that provides aspect injection for business implementations, binding defined aspects into business logic through pointcuts. For example, all controller layers in the SpringBoot microservice need to print some regular logs for HTTP requests. If the code is printed every time in controller, it will be redundant. If the common code is encapsulated, each Controller class will also need to call it. So AOP is the perfect time to introduce AOP to uniformly manage http-related logging logic by writing code that doesn’t need to be called by the Controller layer, just creating an aspect and binding controller through pointcuts, as the following examples show.
AOP related terms
Spring AOP
Aspect
Transaction management is a good example of a crosscutting concern in J2EE applications. In Spring AOP, aspects are either through regular classes (basic schema methods) or through the use of annotations@Aspect
To implement the general class.Joint point
: refers to a point during program execution, such as the execution of a method or the handling of an exception. In Spring AOP, a join point often representsA method execution
.Advice
: refers to the action performed by the section at a particular join point. There are different types of notifications, including"around"
."before"
and"after"
Notice. Many AOP frameworks, including Spring, model advice as an interceptor and maintain a chain of interceptors around join points.Pointcut
: refers to an assertion that matches the join point. Advice is associated with a pointcut expression and runs at any join point that is matched by a pointcut (for example, executing a method with a specific name). At the heart of AOP isPointcut expressions match the idea of join points
. Spring uses by defaultAspectJ pointcut expression language
Introduction
: represents the declaration of additional methods or attributes of a type. Spring AOP allows you to introduce a new interface to any notified object (and a corresponding implementation). For example, an import can be used to implement a beanIsModified
Interface to simplify the caching mechanism. (In the AspectJ community, an introduction is also called an inter-type declaration.)Target Object
: refers to the object notified by one or more facets. Also refers to the notified object ("advised object"
), since Spring AOP is implemented through runtime governance items, this target object is often aProxy objects
.AOP Proxy
: refers to objects created through an AOP framework to implement aspect contracts (perform notification methods, etc.). In the Spring framework, an AOP proxy is oneJDK dynamic proxy
Or a personAdditional agent
.Weaving
: connects the slice to other application types or objects to create a notification object. This can be done at compile time (such as using the AspectJ compiler), load time, or run time. Spring AOP, such as other pure Java AOP frameworks, is generally available inThe runtime
Finish weaving.
AOP Advice related terms
Before advice
: Notifications performed before a join point. But this notification does not stop the flow of join point execution (unless it throws an exception)After Returning Advice
: notification executed after a join point completes normally (for example, if a method does not return an exception)After Throwing Advice
: Notification executed when a method throws an exception exit.After(finally) advice
: Notification that is executed when a join point exits (either normal or abnormal return).Around Advice
: Notifications around a join point, such as method calls. This is one of the most powerful types of notification. Wraparound advice enables custom behavior before and after a method call. It is also responsible for choosing whether to proceed with the join point or simplify the execution of the notified method by either returning its own return value or throwing an exception.
AOP is integrated with SpringBoot
1) Introduction of POM.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.1</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.14</version>
</dependency>
</dependencies>
Copy the code
Among them, mainly introduced the related about aop support section programming depends on: org. Aspectj. Aspectjweaver and org., aspectj. Aspectjrt dependence. Aspectjweaver is the woven package of AspectJ, and AspectJrt is the runtime package of AspectJ.
2) Configuration files
server:
context-path: /demo/v1
port: 9000
Copy the code
3) the controller class
package com.example.andya.demo.controller;
import org.springframework.web.bind.annotation.*;
/ * * *@author Andya
* @createThe 2020-04-12 ye that * /
@RestController
@RequestMapping("/aopTest")
public class AopController {
@RequestMapping(value = "/sayHi/{name}", method = RequestMethod.GET)
public String sayHi(@PathVariable(value = "name") String name) {
return "hi, "+ name; }}Copy the code
4) AOP layer classes
package com.example.andya.demo.aop;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/ * * *@author Andya
* @createThe 2020-04-12 * / seated
@Aspect
@Component
public class WebLogAspect {
private Logger LOG = LoggerFactory.getLogger(WebLogAspect.class);
ThreadLocal<Long> startTime = new ThreadLocal<>();
/** * defines pointcuts for requests from all packages under Controller */
@Pointcut("execution(public * com.example.andya.demo.controller.. *. * (..) ) *. "")
public void webLog(a){}/** * Pre-notification: notification * executed before the pointcut@param joinPoint
* @throws Throwable
*/
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
startTime.set(System.currentTimeMillis());
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = servletRequestAttributes.getRequest();
// Prints request parameters
LOG.info("========================================== Start ==========================================");
LOG.info("URL:" + request.getRequestURL().toString());
LOG.info("HTTP_METHOD:" + request.getMethod());
// Display header in the first format
Enumeration<String> enumeration = request.getHeaderNames();
Map<String, String> headerMap = new HashMap<>();
while (enumeration.hasMoreElements()) {
String headerName = enumeration.nextElement();
headerMap.put(headerName, request.getHeader(headerName));
}
String headerJsonStr = JSON.toJSONString(headerMap);
if (headerJsonStr.length() > 0) {
LOG.info("HTTP_HEADERS INFO IS: {}", headerJsonStr);
}
// display header in the second format
LOG.info("HTTP_HEADERS: "); Enumeration<? > enumeration1 = request.getHeaderNames();while (enumeration1.hasMoreElements()) {
String key = (String) enumeration1.nextElement();
String value = request.getHeader(key);
LOG.info("{}, {}", key, value);
}
LOG.info("IP:" + request.getRemoteAddr());
LOG.info("CLASS_METHOD:" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
try {
LOG.info("REQUEST BODY : [{}]", JSON.toJSONString(joinPoint.getArgs()[0]));
// log.info ("ARGS: {}", arrays.tostring (joinPoint.getargs ()));
} catch (Exception e) {
LOG.error("REQUEST BODY PARSE ERROR!");
}
HttpSession session = (HttpSession) servletRequestAttributes.resolveReference(RequestAttributes.REFERENCE_SESSION);
LOG.info("The SESSION ID." + session.getId());
}
// /**
// * after notification
// * @param ret
// * @throws Throwable
/ / * /
// @AfterReturning(returning = "ret", pointcut = "webLog()")
// public void doAfterReturning(Object ret) throws Throwable {
// // Returns the content after processing the request
// LOG.info("RESPONSE : " + ret);
// LOG.info("SPEND TIME : " + (System.currentTimeMillis() - startTime.get()));
//
/ /}
/** ** final notification *@throws Throwable
*/
@After("webLog()")
public void doAfter(a) throws Throwable {
LOG.info("=========================================== End ===========================================");
// Empty one line between each request
LOG.info("");
}
Surrounded by / * * * notice * around the first parameter must be org. Aspectj. Lang. * ProceedingJoinPoint type@param proceedingJoinPoint
* @return
* @throws Throwable
*/
@Around("webLog()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = proceedingJoinPoint.proceed();
String resultStr = JSON.toJSONString(result);
// Print out the parameter
LOG.info("RESPONSE ARGS : {}", resultStr);
// Execution time
LOG.info("TIME-CONSUMING : {} ms", System.currentTimeMillis() - startTime);
returnresult; }}Copy the code
Among them:
@Aspect
The annotation is to indicate that this class is a faceted class,@Component
The annotation is to add the aspect class to the Ioc container.@Pointcut
Define pointcuts for all functions under the entire Controller package.joinPoint.getArgs()
Gets parameter information for the target method.joinPoint.getSignature()
Gets the signature of the notification and passesjoinPoint.getSignature().getDeclaringTypeName()
To obtainThe proxy class
The name,joinPoint.getSignature().getName()
To obtainProxy method
The name.
5) Run the class
package com.example.andya.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); }}Copy the code
6) Access the URL
http://127.0.0.1:9000/demo/v1/aopTest/sayHi/andya
7) Running results
. . . . . .2020-04-12 15:21:31.737 INFO 18548 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2020-04-12 15:21:31.782 INFO 18548 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 9000 (http)The 15:21:31 2020-04-12. 18548-786 the INFO [main] com. Example. Andya. Demo. DemoApplication: Started DemoApplication in 2.928seconds (JVM running for 4.26)2020-04-12 15:21:41.084 INFO 18548 -- [NIO-9000-EXEC-2] O.A.C.C.C. [.[localhost].[/demo/v1] : Initializing Spring FrameworkServlet 'dispatcherServlet' 2020-04-12 15:21:41.085 INFO 18548 -- [NIO-9000-exec-2] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': Initialization started the 2020-04-12 15:21:41. 102 INFO - 18548 [nio - 9000 - exec - 2] O.S.W eb. Servlet. DispatcherServlet: FrameworkServlet 'dispatcherServlet': Initialization Completed in 17 MS 2020-04-12 15:21:41.126 INFO 18548 -- [NIO-9000-EXEC-2] com.example.andya.demo.aop.WebLogAspect :========================================== Start ==========================================
2020-04-12 15:21:41.126 INFO 18548 --- [nio-9000-exec-2] com. Example. Andya. Demo. Aop. WebLogAspect: URL: HTTP:/ / 127.0.0.1:9000 / demo/v1 / aopTest/sayHi/andya
2020-04-12 15:21:41.126 INFO 18548 --- [nio-9000-exec-2] com. Example. Andya. Demo. Aop. WebLogAspect: HTTP_METHOD: a GET2020-04-12 15:21:41.155 INFO 18548 --- [nio-9000-exec-2] com.example.andya.demo.aop.WebLogAspect : HTTP_HEADERS INFO IS: {"accept-language":"zh-CN"."cookie":"JSESSIONID=1014BD34FFE9D2660CB47B282C63FA7D"."host":"127.0.0.1:9000"."connection":"Keep-Alive"."accept-encoding":"gzip, deflate"."accept":"text/html, application/xhtml+xml, image/jxr, */*"."user-agent":"Mozilla / 5.0 (Windows NT 10.0; WOW64; Trident / 7.0; The rv: 11.0) like Gecko"}
2020-04-12 15:21:41.156 INFO 18548 --- [nio-9000-exec-2] com.example.andya.demo.aop.WebLogAspect : HTTP_HEADERS:
2020-04-12 15:21:41.156 INFO 18548 --- [nio-9000-exec-2] com.example.andya.demo.aop.WebLogAspect : accept: text/html, application/xhtml+xml, image/jxr, */ * 2020-04-12 15:21:41. 156 INFO - 18548 [nio - 9000 - exec - 2] com. Example. Andya. Demo. Aop. WebLogAspect: accept - language: Useful - CN 2020-04-12 15:21:41. 18548-156 the INFO/nio - 9000 - exec - 2 com. Example. Andya. Demo. Aop. WebLogAspect: the user-agent: Mozilla / 5.0 (Windows NT 10.0; WOW64; Trident / 7.0; The rv: 11.0) like Gecko 15:21:41 2020-04-12. 18548-156 the INFO/nio - 9000 - exec - 2 com. Example. Andya. Demo. Aop. WebLogAspect: accept-encoding: Gzip, deflate the 15:21:41 2020-04-12. 18548-156 the INFO/nio - 9000 - exec - 2 com. Example. Andya. Demo. Aop. WebLogAspect: host: 127.0.0.1:9000 2020-04-12 15:21:41. 18548-156 the INFO/nio - 9000 - exec - 2 com. Example. Andya. Demo. Aop. WebLogAspect: connection: Keep - Alive 15:21:41 2020-04-12. 18548-156 the INFO/nio - 9000 - exec - 2 com. Example. Andya. Demo. Aop. WebLogAspect: cookies: JSESSIONID = 1014 bd34ffe9d2660cb47b282c63fa7d 15:21:41 2020-04-12. 18548-156 the INFO [nio - 9000 - exec - 2] com.example.andya.demo.aop.WebLogAspect : IP: 127.0.0.1 15:21:41 2020-04-12. 18548-157 the INFO/nio - 9000 - exec - 2 com. Example. Andya. Demo. Aop. WebLogAspect: CLASS_METHOD: Com. Example. Andya. Demo. Controller. AopController. SayHi 15:21:41 2020-04-12. 18548-157 the INFO [nio - 9000 - exec - 2] com.example.andya.demo.aop.WebLogAspect : REQUEST BODY : [" andya "] 2020-04-12 15:21:41. 160 INFO - 18548 [nio - 9000 - exec - 2] com. Example. Andya. Demo. Aop. WebLogAspect: The SESSION ID: 0357 b2624c73c5f79bc977ad628db45f 15:21:41 2020-04-12. 18548-162 the INFO [nio - 9000 - exec - 2] com.example.andya.demo.aop.WebLogAspect : RESPONSE ARGS : "Hi, andya" 15:21:41 2020-04-12. 18548-163 the INFO/nio - 9000 - exec - 2 com. Example. Andya. Demo. Aop. WebLogAspect: TIME-CONSUMING : 37 ms 15:21:41 2020-04-12. 163 INFO - 18548 [nio - 9000 - exec - 2] com. Example. Andya. Demo. Aop. WebLogAspect: = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = End = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 2020-04-12 15:21:41. 163 INFO 18548 --- [nio-9000-exec-2] com.example.andya.demo.aop.WebLogAspect :Copy the code
Refer to the SPING Technology Insider for an in-depth analysis of SPRING architecture and design principles