Unified processing of Web request logs using AOP in Spring boot

Source: Internet
Author: User
Tags throwable

AOP is the abbreviation of aspect oriented programming, which means: face-cutting programming, through the Pre-compilation method and Run-time dynamic agent implementation of the unified maintenance of the program functions of a Technology. AOP is an important part of the spring framework by defining an entry point for an existing program and then cutting into different executions before and after it, such as: opening a database connection/closing a database connection, opening a transaction/closing a transaction, logging, and so On. AOP does not break the original program logic, so it can be very good to isolate the various parts of the business logic, thus reducing the coupling between parts of business logic, improving the reusability of the program, and improving the efficiency of Development.

Here are two topics, one on how to introduce AOP in spring boot, and how to use AOP as a slice to unify the log of Web Requests.

All of the following operations are based on the chapter4-2-2 Project.

Preparatory work

Because you need to make a slice of the Web request to log logs, you first introduce the Web module and create a simple hello request processing.

    • pom.xmlThe introduction of Web modules in
12345 <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency>
    • Implement a simple request Processing: returns the function "hello xxx" by passing in the name Parameter.
1234567891011 @RestController public class Hellocontroller { @RequestMapping (value = "/hello", method = Requestmethod.get)@ResponseBodypublicstring Hello(@RequestParam string Name) { return "Hello" + name;}}

below, we can make a slice log record of the Above/hello Request.

Introducing AOP Dependencies

Introducing AOP in spring boot is as simple as introducing other modules, just pom.xml add the following dependencies in:

12345 <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-aop</artifactid> </dependency>

After the introduction of the AOP dependency package is completed, it is generally not necessary to do other Configuration. Perhaps people who have used the annotation configuration method in spring will ask if it needs to be added to the main class of the program @EnableAspectJAutoProxy and is not actually needed.

You can look at the following default configuration properties for aop, where spring.aop.auto properties are turned on by default, which means that the default is increased as long as the AOP dependency is introduced @EnableAspectJAutoProxy .

12345 # AOPspring.aop.auto=true # Add @EnableAspectJAutoProxy. Spring.aop.proxy-target-class=false # Whether subclass-based (CGLIB) proxies is to be created (true)as opposed to standard Java interface-based proxies (false).

And when we need to use Cglib to implement aop, we need to configure spring.aop.proxy-target-class=true , otherwise the default is to use the standard Java Implementation.

Implementing a log slice of the web layer

The facets that implement AOP are mainly the following elements:

    • Use @Aspect annotations to define a Java class as a slice class
    • Use to @Pointcut define a pointcut, which can be a regular expression, such as all functions under a package in the following example, or an Annotation.
    • Cut-in content at different points in the pointcut as needed
      • Use @Before to cut into content at the beginning of a pointcut
      • Use @After to cut into content at the end of a pointcut
      • Use to @AfterReturning cut into content after entry return content (can be used to do some processing of processing return values)
      • Use to @Around cut content before and after a pointcut, and control when to execute the pointcut itself
      • @AfterThrowingthe processing logic used to handle the exception that is thrown when the cut-in content part throws
1234567891011121314151617181920212223242526272829303132 @Aspect@Componentpublic class Weblogaspect { private Logger Logger = Logger.getlogger (getclass ()); @Pointcut ("execution (public * com.didispace.web). *.*(..))")public void webLog() {} @Before ("webLog ()") public void dobefore(joinpoint joinpoint) throws throwable { //receive request, Log Request contentServletrequestattributes attributes = (servletrequestattributes) requestcontextholder.getrequestattributes (); HttpServletRequest request = Attributes.getrequest ();//record the requested contentLogger.info ("URL:" + request.getrequesturl (). toString ());Logger.info ("http_method:" + request.getmethod ());Logger.info ("IP:" + request.getremoteaddr ());Logger.info ("class_method:" + joinpoint.getsignature (). getdeclaringtypename () + "." + joinpoint.getsignature (). getName () );Logger.info ("ARGS:" + arrays.tostring (joinpoint.getargs ()));}@AfterReturning (returning = "ret", pointcut = "webLog ()") public void doafterreturning(Object ret) throws throwable { //finished processing the request, return contentLogger.info ("RESPONSE:" + ret);} }

You can see the example above, by @Pointcut defining the pointcut for com.didispace.web all functions under the Package (the Web layer all request processing to make a pointcut), and then through the @Before implementation, the request content of the log record (this article only describes the process, you can adjust the content as needed), and finally through @AfterReturning Records the object returned by the Request.

By running the program and accessing: http://localhost:8080/hello?name=didi , you can get the following log output

1234567 2016-05-19 13:42:13,156 info weblogaspect:41-url:http://localhost:8080/hello2016-05-19 13:42:13,156 Info weblogaspect:42-http_method:http://localhost:8080/hello2016-05-19 13:42:13,157 INFO weblogaspect:43-ip:0:0:0:0:0: 0:0:12016-05-19 13:42:13,160 INFO weblogaspect:44-class_method:com.didispace.web.hellocontroller.hello2016-05-19 13:42:13,160 Info weblogaspect:45-args: [didi]2016-05-19 13:42:13,170 info Weblogaspect:52-response:hello Didi
Optimization: synchronization issues in AOP facets

In the Weblogaspect section, respectively, through the Dobefore and doafterreturning two separate functions to achieve the tangent head and the pointcut after the return of the execution of the content, if we want to count the processing time of the request, we need to record time at dobefore, The consumed time of the request processing is calculated at the doafterreturning by the current time and the time recorded at the Beginning.

So can we define a member variable in the Weblogaspect slice to be accessed by Dobefore and doafterreturning? Is there a sync problem?

It is true that there is a synchronization problem in defining the basic type directly here, so we can introduce the Threadlocal object and record it as Follows:

12345678910111213141516171819202122232425262728 @Aspect@Componentpublic class Weblogaspect { private Logger Logger = Logger.getlogger (getclass ());Threadlocal<long> StartTime =New threadlocal<> ();@Pointcut ("execution (public * com.didispace.web). *.*(..))")public void webLog() {} @Before ("webLog ()") public void dobefore(joinpoint joinpoint) throws throwable { Starttime.set (system.currenttimemillis ());//omit log Record contents}@AfterReturning (returning = "ret", pointcut = "webLog ()") public void doafterreturning(Object ret) throws throwable { //finished processing the request, return contentLogger.info ("RESPONSE:" + ret);Logger.info ("spend time:" + (system.currenttimemillis ()-starttime.get ()));}  }
Optimization: Precedence of AOP facets

Due to the implementation of aop, the program is well decoupled, but also brings some problems, such as: we may be on the web layer to do multiple facets, verify the user, check the header information and so on, this time often encounter the processing order of the aspect of the Problem.

so, we need to define the priority of each slice, and we need @Order(i) annotations to identify the priority of the Slices. the smaller the value of i, the higher the priority . Suppose we also have a tangent that is used to verify that the CheckNameAspect name must be didi, which we set for it, @Order(10) and Weblogaspect is set in the above @Order(5) , so Weblogaspect has a higher priority, this time the order of execution is this:

    • What @Before to do in priority @Order(5) , and what to do @Order(10)
    • Content to be executed in and out of @After @AfterReturning priority @Order(10) @Order(5)

So we can summarize this:

    • Operations in front of pointcuts, by order value from small to large execution
    • Operations after pointcuts, executed by order value from large to small

Unified processing of Web request logs using AOP in Spring boot

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.