Objective
In the previous section, the integration knowledge of the current development log4j2
and the logback
log framework is introduced. In many cases, when we develop a system, regardless of the considerations, such as audit requirements, or anti-repudiation, or to preserve the angle of operation traces, there will generally be a global logging module function. This module typically records every action that changes the data, and if it is on a Web application, it also logs the URL of the request, the requested IP, the current operator, the method description of the operation, and so on. In many cases, we need to record the requested parameter information, usually using 拦截器
, 过滤器
or waiting for a AOP
unified interception. In this section, I'll focus on how to leverage AOP
the implementation of unified web
logging.
- A little knowledge
- What is AOP
- Basic concepts of AOP
- Agent mechanism
- Pointcut Indicator Simple Introduction
- Unified Logging
- Resources
- Summarize
- At last
- Cliché
A little knowledge of what is AOP
AOP
Full Name: Aspect oriented Programming. is an aspect-oriented programming, using the pre-compilation method and run-time dynamic agent to realize the unity of the program function of a technology. It's also Spring
a very important part, and IOC
as important as it is. It can be used to AOP
isolate the various parts of business logic, so that the coupling degree between parts of business logic is reduced, the reusability of the program is improved, and the efficiency of development is improved.
Simply put, it is possible to complete the processing of the AOP
related business on the basis of the existing procedures without code embedding, and the business can only focus on the logic of its own business, without having to relate to some business-related matters, such as the most common 日志
,, 事务
权限检验
, and 性能统计
统一异常处理
and so on.
spring
The official website gives the AOP
following information:
Basic concepts of AOP
About AOP
The relevant introduction can click on the official website link to view: aop-introduction
Below is a simple explanation:
Facets (Aspect): Facets are a modular focus, which may be a cross-cutting of multiple objects;
Join point: A connection point refers to a particular point in the execution of a program, such as when a method is called or when an exception is handled;
- Notification (Advice): Refers to an action performed on a particular connection point on a slice. Spring facets can be applied in 5 notifications:
- Pre-notification (before): a notification executed before the target method or connection point is invoked;
- Post notification (after): a notification that is executed after a connection point has been completed;
- return notification (after-returning): A notification that executes after a connection point has been successfully executed;
- Exception Notification (after-throwing): Refers to the notification that is executed after the method throws an exception;
- Surround Notification (Around): Refers to a method that wraps a connection point notification before and after the method call that is notified.
Pointcut (Pointcut): an assertion that matches a connection point. A notification is associated with a pointcut expression and runs on a connection point that satisfies this cut-in, such as when a particular name is executed.
Introduction (Introduction): Ingestion is also known as an internal type declaration, declaring additional methods or fields of a type.
Target object: The target object is an object that is notified by one or more facets.
AOP Proxy: An AOP proxy is a pair of objects created by the AOP framework to implement a tangent contract (including functions such as notification methods)
Weaving (wearving): refers to connecting facets to other application types or objects, and creating an object to be notified. or the process of forming a proxy object's method.
The following diagram provides a brief description of the above concepts:
Agent mechanism
Spirng
AOP
There are two kinds of dynamic agent implementation mechanism, namely: JDK动态代理
and CGLib动态代理
. The following two kinds of agent mechanism are introduced briefly.
JDK动态代理
Yes 面向接口
代理模式
, if the proxy target does not have an interface then spring can do nothing, and spring uses the Java reflection mechanism to produce a new anonymous implementation class for the proxy interface, overriding the AOP enhancement method.
CGLib
is a powerful, high-performance code production class library, you can implement the runtime dynamic extension Java class, spring during the run through Cglib inherit the class to be dynamic proxy, rewrite the parent class method, implement AOP aspect-oriented programming.
Compare the two:
JDK动态代理
is interface-oriented, which is faster than cglib when creating a proxy implementation class, and it is faster to create an agent. And JDK动态代理
you can only generate proxies for the implemented 接口
classes, not for classes.
CGLib动态代理
is implemented through the 字节码
underlying inheritance to the proxy class (if the proxy class is decorated by the final keyword, then sorry will fail), the creation of the agent is not a JDK dynamic agent fast, but faster than the JDK dynamic agent.
As for the relevant principles, we search for it, @@facesymbol@@‖∣
Pointcut Indicator Simple Introduction
To be able to define the pointcut position flexibly, Spring AOP provides a variety of pointcut indicators. The following is a simple introduction.
- Execution: Connection point matching execution method
From which you can see execution
the syntax structure of the pointcut indicator is: execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
. This is also the most commonly used indicator.
Within: Used to match method execution within a specified type;
This: used to match the execution method of the current AOP proxy object type, note that the type of the AOP proxy object matches, which may include the introduction of interface and type matching;
Target: The execution method used to match the current target object type; Note that the target object type matches, so that the introduction interface is not included and the type match;
Args: The method used to match the current execution of the passed parameter to the specified type;
@within: Used to match so hold the method within the specified annotation type;
@target: The execution method used to match the current target object type, where the target object holds the specified annotation;
@args: Used to match the current execution of the method passed in the parameter holding the specified annotation execution;
@annotation: The method used to match the current execution method holding the specified annotation;
bean:spring an AOP extension, ASPECTJ does not have a method for executing a bean object that matches a particular name for an indicator;
Reference Pointcut: Indicates references to other named Pointcuts, only @apectj style support, schema style is not supported.
For the relevant syntax and use, you can view: 53391244. There is a more detailed introduction. There is no more elaboration here.
Unified Logging
After we have introduced the relevant knowledge, we begin to use AOP
the unified logging functionality. This article uses @Around
the wrapping mode directly, and customizes a log annotation class to personalize the logging information.
0. Join the Aop
dependency.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId></dependency>
1. Write a custom log annotation class Log
.
/** * 日志注解类 * @author oKong * */@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD})//只能在方法上使用此注解public @interface Log { /** * 日志描述,这里使用了@AliasFor 别名。spring提供的 * @return */ @AliasFor("desc") String value() default ""; /** * 日志描述 * @return */ @AliasFor("value") String desc() default ""; /** * 是否不记录日志 * @return */ boolean ignore() default false;}
Friendship tip: Familiar with Spring
the common annotation class of friends, @AliasFor
should not be unfamiliar. It is Spring
provided as an annotation, which is primarily to give the annotated attribute a name for the other. Make it easier to understand when using annotations (for example, to alias the Value property). is typically a pairing alias. Because it is Spring
provided by the framework, it can be used or a AnnotationUtils.synthesizeAnnotation
AnnotationUtils.getAnnotation
method call to get the annotations, so there is a simple example in the following code.
2. Write the Slice class.
/** * Log Slice class * @author Xiedeshou * *///Add @aspect Declare a facet @aspect@component@slf4jpublic class Logaspect {//Set Pointcut: Stop right here. Class @Pointcut truncated by @restcontroller annotations ("Within (@org. Springframework.web.bind.annotation.RestController *)") public void PO Intcut () {}/** * Tangent method, logging * @return * @throws throwable */@Around ("Pointcut ()") Public Object Doaround (Proceedingjoinpoint joinpoint) throws Throwable {Long beginTime = System.currenttimemill Is ();//1, start time//use Requestcontextholder to get Requst object servletrequestattributes requestattr = (servletrequestattr ibutes) requestcontextholder.currentrequestattributes (); String uri = Requestattr.getrequest (). Getrequesturi (); Log.info ("Start timer: {} URI: {}", new Date (), URI); Access to the parameters of the target method can dynamically change the parameter value object[] args = Joinpoint.getargs (); The method name gets the String methodName = Joinpoint.getsignature (). GetName (); Log.info ("Request method: {}, request parameter: {}", MethodName, arrays.tostring (args)); May be in reverse proxy request come in, get the IP there is incorrect line here directly excerpt from the Internet to obtain the IP code log.info ("Request ip:{}", Getipaddr (Requestattr.getrequest ())); Signature Signature = Joinpoint.getsignature (); if (! ( Signature instanceof Methodsignature) {throw new IllegalArgumentException ("Non-method annotations are not supported"); }//Call the actual Method Object object = Joinpoint.proceed (); Gets the method of execution Methodsignature methodsign = (methodsignature) signature; Method method = Methodsign.getmethod (); Determine if the log is included without logging Loganno = Annotationutils.getannotation (method, Log.class); if (Loganno! = null && loganno.ignore ()) {return object; } log.info ("Log annotation description: {}", Loganno.desc ()); Long endTime = System.currenttimemillis (); Log.info ("End timer: {}, URI: {}, Time consuming: {}", new Date (), uri,endtime-begintime); Analog anomaly//system.out.println (1/0); return object; }/** * Specify interceptor rules, or you can use within (@org. SPRINGFRAmework.web.bind.annotation.RestController *) * This simple point can be generic * @param exception Object */@AfterThrowing (pointcut= "Pointc UT () ", throwing=" E ") public void afterthrowable (Throwable e) {log.error (" the facet has an exception: ", E); Here you can do a unified exception handling//Custom an exception wrapper after excluding//throw new aopexception ("xxx"); }/** * Go to: my.oschina.net/u/994081/blog/185982 */public static String getipaddr (HttpServletRequest request) {String ipAddress = null; try {ipAddress = Request.getheader ("X-forwarded-for"); if (ipAddress = = NULL | | ipaddress.length () = = 0 | | "Unknown". Equalsignorecase (ipAddress)) {ipAddress = Request.getheader ("Proxy-client-ip"); } if (ipAddress = = NULL | | ipaddress.length () = = 0 | | "Unknown". Equalsignorecase (ipAddress)) {ipAddress = Request.getheader ("Wl-proxy-client-ip"); } if (ipAddress = = NULL | | ipaddress.length () = = 0 | | "Unknown". Equalsignorecase (Ipaddress)) {ipAddress = Request.getremoteaddr (); if (Ipaddress.equals ("127.0.0.1")) {//////IP inetaddress inet = null based on the network card to which the native configuration is taken; try {inet = Inetaddress.getlocalhost (); } catch (Unknownhostexception e) {log.error ("Get IP exception: {}", E.getmessage ()); E.printstacktrace (); } ipAddress = Inet.gethostaddress (); }}//For cases through multiple proxies, the first IP is the client real IP, multiple IPs according to ', ' Split if (ipAddress! = null && IPADDRESS.L Ength () > () {//"***.***.***.***". Length ()//= 15 if (Ipaddress.indexof (",") > 0) {ipAddress = ipaddress.substring (0, Ipaddress.indexof ( ",")); }}} catch (Exception e) {ipAddress = ""; } IpAddress = This.getrequest (). GETREMOTEADDR (); return ipAddress; } }
3. Start class to add annotations @EnableAspectJAutoProxy
, effective annotations. Another argument is that by default the introduction of Pom dependency is enabled by default. No matter, add is, plus is a good habit, because I do not know whether the subsequent version will modify the default value it ~
@SpringBootApplication@EnableAspectJAutoProxy@Slf4jpublic class Chapter24Application { public static void main(String[] args) { SpringApplication.run(Chapter24Application.class, args); log.info("Chapter24启动!"); }}
4. Write the control layer.
/** * aop统一异常示例 * @author xiedeshou * */@RestControllerpublic class DemoController { /** * 简单方法示例 * @param hello * @return */ @RequestMapping("/aop") @Log(value="请求了aopDemo方法") public String aopDemo(String hello) { return "请求参数为:" + hello; } /** * 不拦截日志示例 * @param hello * @return */ @RequestMapping("/notaop") @Log(ignore=true) public String notAopDemo(String hello) { return "此方法不记录日志,请求参数为:" + hello; }}
Friendly tip: After you have written the slice class, the IDE will identify the method that conforms to the cut-off condition of the slice.
5. Launch the app and access the API to see the console output the corresponding information.
Visited:/AOP, output
2018-08-23 22:54:59.003 INFO 12928 --- [nio-8080-exec-3] c.l.l.s.chapter24.config.LogAspect : 开始计时: Fri Aug 23 22:54:59 CST 2018 URI: /aop2018-08-23 22:54:59.004 INFO 12928 --- [nio-8080-exec-3] c.l.l.s.chapter24.config.LogAspect : 请求方法:aopDemo, 请求参数: [oKong]2018-08-23 22:54:59.005 INFO 12928 --- [nio-8080-exec-3] c.l.l.s.chapter24.config.LogAspect : 请求ip:192.168.2.1072018-08-23 22:54:59.005 INFO 12928 --- [nio-8080-exec-3] c.l.l.s.chapter24.config.LogAspect : log注解描述:请求了aopDemo方法2018-08-23 22:54:59.005 INFO 12928 --- [nio-8080-exec-3] c.l.l.s.chapter24.config.LogAspect : 结束计时: Fri Aug 23 22:54:59 CST 2018, URI: /aop,耗时:2
Resources
- 53391244
- 72887209
Summarize
This paper mainly introduces the use AOP
of unified web
logging function. This example does not show the log in function, you can do it yourself. In the actual development process, in general, the log is stored for asynchronous storage processing, this need to note that the log records can not affect the normal method request, if synchronized, will put the cart before the horse. This article is just a simple use of the wrapping mechanism to explain, we can also try other annotations to the corresponding practice, most of the same, just to pay attention to the timing of the triggering of the annotations.
At last
At present, many big guys on the internet have a SpringBoot
series of tutorials, if there is a similar, please forgive me. This article is the author in front of the computer word knocking, each step is his own practice and understanding. If there is something wrong in the text, also hope to put forward, thank you.
Cliché
- Personal QQ:
499452441
- Public Number:
lqdevOps
Personal blog: http://blog.lqdev.cn
Complete Example: github.com/xie19900123/spring-boot-learning/tree/master/chapter-24
Original Address:/HTTP