SpringBoot AOP Introduction

Speaking of spring, we know that two of its core function is to AOP (aspect-oriented) and IOC (Inversion of Control), here article to summarize SpringBoot how to integrate the use of AOP.

First, an example application scenario: all the web request to cut logs.

1, pom introduced SpringBoot web modules and related dependencies using AOP:
================================== ============

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1</version>
</dependency>
============================================================


Wherein:
CGLIB package is used for dynamic proxy, based proxies;
aspectjrt aspectjweaver and are associated with aspectj package for programming support section;
aspectjrt aspectj package is a runtime package;
aspectjweaver aspectj is woven into the package;

2, to achieve a simple (function realization name parameter passed, return "hello xxx" of) the inlet Web requests:


Note: At the conclusion of the introduction of AOP dependencies, in general, do not need additional configuration. Used Spring annotation configuration of people will ask whether you need to increase @EnableAspectJAutoProxy in the program to enable the master class, not actually need.

After the default configuration properties because of the AOP, spring.aop.auto property is enabled by default, which means that as long as the introduction of AOP dependency, default has increased @EnableAspectJAutoProxy.

3, the definition of the aspect class, implementing a web log slice layer

To put a cut into class categories, two steps,
① using @Component annotation on the aspect class category is added to the vessel IOC
② @Aspect annotation used in making the aspect class class

package com.example.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
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.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/**
* Created by lmb on 2018/9/5.
*/
@Aspect
@Component
public class WebLogAcpect {

private Logger logger = LoggerFactory.getLogger(WebLogAcpect.class);

/ **
* defined entry point in the entry point for all functions com.example.aop
* /
@Pointcut ( "Execution (public com.example.aop .. * *. * (..))")
public void Weblog () {}

/ **
* Pre-notification: notification is performed before the connection point
* @param Joinpoint
* @throws the Throwable
* /
@Before ( "Weblog ()")
public void doBefore (the JoinPoint Joinpoint) throws the Throwable {
// receiving the request, recorded requested content
ServletRequestAttributes Attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes ();
the HttpServletRequest attributes.getRequest request = ();

// 记录下请求内容
logger.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", the pointcut = "Weblog ()")
public void doAfterReturning (Object RET) throws the Throwable {
// End processing request, returns content
logger.info ( "the RESPONSE:" + RET);
}
}

above @Pointcut aspect classes defined by the starting point for all functions done at com.example.aop the entering packet, the entry point achieved by pre-notification @Before, @AfterReturning object returned by the request recording.

 

Second, notice AOP support
1, the pre-notification @Before: Advice to be executed before a join point, unless it throws an exception, otherwise the notice can not stop the flow of execution before the connection point.

/ **
* is called before the pre-notification method calls
* @param Joinpoint / null
* /
@Before (value = POINT_CUT)
public void before (the JoinPoint Joinpoint) {
logger.info ( "pre-notification");
// Get parameter information of the target method
Object [] joinPoint.getArgs obj = ();
// AOP proxy class information
joinPoint.getThis ();
// proxy target object
joinPoint.getTarget ();
notification with most // signature
signature = joinPoint.getSignature Signature ();
// agent which is a method
logger.info ( "agent which is a method of" + signature.getName ());
// the name of the proxy class AOP
logger.info ( "AOP agent class name "+ signature.getDeclaringTypeName ());
// AOP proxy class category (class) information
signature.getDeclaringType ();
// get RequestAttributes
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
//从获取RequestAttributes中获取HttpServletRequest的信息
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
//如果要获取Session信息的话,可以这样写:
//HttpSession session = (HttpSession) requestAttributes.resolveReference(RequestAttributes.REFERENCE_SESSION);
//获取请求参数
Enumeration<String> enumeration = request.getParameterNames();
Map<String,String> parameterMap = Maps.newHashMap();
while (enumeration.hasMoreElements()){
String parameter = enumeration.nextElement();
parameterMap.put(parameter,request.getParameter(parameter));
}
JSON.toJSONString STR = String (the parameterMap);
IF (obj.length> 0) {
logger.info ( "parameter information request is:" + STR);
}
}

5, around advice @Around: enclosing a connection point of the notification, and the like as a method call. This is the most powerful kind of advice. Around advice can perform custom behavior before and after the method call, it will choose whether to continue with the connection point or directly back to its own return value or throwing an exception execution.

Around advice most powerful and most troublesome, is surrounded by a method, the specific method to be passed to the section through a proxy, selectable cut or not to perform a method, a method performed several times. Around advice is to use a proxy ProceedingJoinPoint type of objects to manage the target audience, so the first parameter of this notice must be ProceedingJoinPoint type. () Method in the notice calling the body ProceedingJoinPoint proceed causes the connection point of the background of the method is executed. proceed () method may also be called passing in an Object [] is the value of the array will be used as the reference when the method is executed.

/ **
* around advice:
* around advice is very powerful and can determine whether the target method, when executed, whether the need to replace the execution method parameters, whether finished return value needs to be replaced.
* Surround first parameter must be notified org.aspectj.lang.ProceedingJoinPoint type
* /
@Around (value = POINT_CUT)
public Object doAroundAdvice (ProceedingJoinPoint ProceedingJoinPoint) {
logger.info ( "target surrounded notification method name:" + proceedingJoinPoint. getSignature () getName ());.
the try {
Object obj = proceedingJoinPoint.proceed ();
return obj;
} the catch (Throwable the Throwable) {
Throwable.printStackTrace ();
}
return null;
}

. 6, sometimes we define the time section , section requires the use of a parameter to the target object, how to make the cut parameters of the target object to get it? Args can be used to bind. If you type the name of the place should be used in a args expression using a parameter name, then when the parameter value when object Circular will be passed in.

@Before("execution(* findById*(..)) &&" + "args(id,..)")
public void twiceAsOld1(Long id){
System.err.println ("切面before执行了。。。。id==" + id);

}

Note: Any notification method can be defined as the first parameter type org.aspectj.lang.JoinPoint (notice needs to be defined around the first parameter type ProceedingJoinPoint, which is a subclass of JoinPoint). JoinPoint interface provides a number of useful methods, such as getArgs () (returns the method arguments), getThis () (return proxies), getTarget () (return target), getSignature () (return method being notified information) and toString () (print out useful information methods are being notified).

Third, pointcut expressions
defined entry point when the need to include a signature name and any parameters, as well as an entry point expression, such as the execution (public * com.example.aop ... (.. ))

Pointcut expression format: Execution ([visibility] Return Type [declared type] method name (parameter) [exception].)
Where [] is the optional, further supports the use of wildcards:
1) * : matches all characters
2) ..: Usually for matching a plurality of packets, a plurality of parameters
3) +: represents a class and its subclasses
4) operators are: &&, || ,!

Keywords used in Example pointcut expressions:
. 1) Execution: a matching sub-expressions.
// com.cjm.model matching packet and its subpackages all methods in all classes, return type, any, any method parameter
@Pointcut ( "execution (* com.cjm.model ... (..))")
public void before () {}

2) within: a matching connection point where the Java class or package.
// All methods matching Person class
@Pointcut ( "WITHIN (com.cjm.model.Person)")
public void before () {}
// All methods com.cjm matching packets and sub-packets of all classes
@Pointcut ( "WITHIN (com.cjm .. *)")
public void before () {}

3) this: for incoming proxy object to the notification method reference.
@Before ( "before () && the this (Proxy)")
public void beforeAdvide (the JoinPoint Point, Object Proxy) {
// processing logic
}

4) target: the target object for incoming notification method reference.
@Before ( "before () && target (target)
public void beforeAdvide (the JoinPoint Point, Object Proxy) {
// processing logic
}

5) args: parameters for incoming notification process.
@Before ( "before () && args (Age, username)")
public void beforeAdvide (the JoinPoint Point, int Age, String username) {
// processing logic
}

6) @within: for one match class parameters are used to determine the type of annotation, all the methods which will be matched.
@Pointcut ( "WITHIN @ (com.cjm.annotation.AdviceAnnotation)")
- all classes are denoted @AdviceAnnotation matching
public void before () {}

7) @target: @within and is similar in function, but must specify retention policy annotation interface is RUNTIME.
@Pointcut ( "target @ (com.cjm.annotation.AdviceAnnotation)")
public void before () {}

8) @args: incoming connection point corresponding to the object to be marked @args Java class specified Annotation annotation.
@Before ( "@ args (com.cjm.annotation.AdviceAnnotation)")
public void beforeAdvide (the JoinPoint Point) {
// processing logic
}

9) @annotation: annotated method specified by its parameters Annotation connection point matching. That is, all methods are annotated notes specified will match.
@Pointcut ( "Annotation @ (com.cjm.annotation.AdviceAnnotation)")
public void before () {}

10) bean: Bean defined by the connection point where the name of the receiving tube Bean. The key word is Spring2.5 added.
@Pointcut ( "the bean (Person)")
public void before () {}

 

Guess you like

Origin www.cnblogs.com/runnerjack/p/10988165.html