Previous related articles:

AOP core concepts and aspects of SpringAOP

10 minutes introduction to SpringAOP

The introduction

What is the PCD

PCD(pointcut designators) is SpringAOP’s pointcut expressions. SpringAOP’s PCD is fully aspectj-compatible, and there are 10 of them.

PCD general map

Use guide

SpringAOP is based on dynamic proxy implementation, where proxied beans are represented as target objects, and proxy objects represent beans built by AOP. The target method represents the proxied method.

execution

Execution is the most commonly used PCD. Its matching template is shown below:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)
          throws-pattern?) Execution? Return type match class name match? Method name matching (parameter matching) exception matching?Copy the code

Code block with? The matching of symbols is optional, with only three essential to execution:

  1. Return value Matches the value
  2. Method name matching formula
  3. Parameter matching formula

Execution (public * ServiceDemo.*(..)) ServiceDemo = public; ServiceDemo = public; ServiceDemo = public; ServiceDemo = public; Is the parameter matching formula, matching any number, any type of parameter method.

Here are some other examples:

  • execution(* com.xyz.service.. *. * (..) ): matches any method under com.xyz.service and its subpackages.

  • Execution (* Joke (Object+)) : Matches any method named Joke whose dynamic entry is of type Object or a subclass of that class.

  • execution(* joke(String,..) ): matches any method named Joke, which has an input parameter of String(not subclass) and can be followed by any input parameter of any type

  • execution(* com.. *.*Dao.find*(..) ): matches methods that start with find under the specified package

  • execution(* com.baobaotao.Waiter+.*(..) ) : matches all methods of Waiter and its subclasses under the com.baobaotao package.

within

Filter all classes in a package with *.

  • Class within(com.xyz.service.*)com.xyz.service package, excluding subpackages

  • within(com.xyz.service.. *) classes under com.xyz.service and its subpackages

this

This is often used to name binding patterns. Filter by type of proxy object.

If the target class is implemented based on an interface, this() can be filled with the full path name of the interface; otherwise, because the target class is implemented based on CGLIB, this can be filled with the full path name of the target class.

This (com) xyz) service. AccountService) : the proxy class is com. Xyz service. AccountService or its subclasses.

CGLIB can be enforced using @enableAspectJAutoProxy (proxyTargetClass = true). Otherwise, the JDK dynamic proxy will be used first by default, and CGLIB will be used only if the JDK proxy cannot be used.

target

This applies to the proxy object and target to the target object.

Target (com) xyz) service. AccountService) : is the proxy class (target) is com. Xyz. Service. AccountService or its subclasses

args

Often used to match the parameters of a target method. Generally not used alone, but in conjunction with other PCDS to use. Args can use named binding mode, as shown in the following example:

@Aspect // Section declaration
@Component / / into the IOC
@Slf4j
class AspectDemo {
    @Around("within(per.aop.*) && args(str)") // Under the per.aop package, the propped method takes only one argument, of type String or a subclass of it
    @SneakyThrows
    public Object logAspect(ProceedingJoinPoint pjp, String str) { 
        String signature = pjp.getSignature().toString();
        log.info("{} start,param={}", signature, pjp.getArgs());
        Object res = pjp.proceed();
        log.info("{} end", signature);
        returnres; }}Copy the code
  1. If arGS isParameter names, along with the use of the advice method to determine the type of method parameter to match.
  2. If args is a type, for example@ Around (" within (per. Aop. *) && args (String) "), you don’t need to use the section method to determine the type, but you can’t use parameter binding at this point eitherSee below.

Although ARgs () supports the + symbol, the provincial ARgs () supports subclass wildcards.

And strip parameters matchexecutionThe difference between

For example: args(com.xgj.waiter) is equivalent to execution(* *(com.xgj.waiter +)). And execution does not support advice with parameters.

@target

Scenario Example: If a Service has multiple subclasses and some subclasses need to log and some subclasses do not need to log, you can perform the following operations (combined with Java polymorphism):

Filter out that the proxied object with the given annotation is an object, not a class, and @target is dynamic. Define a custom annotation LogAble as follows:

// Fully qualified name: annotation.logable
@Target({ElementType.TYPE,ElementType.PARAMETER}) // Support annotation on method parameters and classes
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAble {
}
Copy the code

If you need to log all public methods of the class annotated with this annotation, the logging logic needs to be customized. You can write PCD as follows, and of course the corresponding method bean needs to be injected into the SpringIOC container:

@Around("@target(annotation.LogAble) && execution(public * *.*(..) )"
// Customize log logic
Copy the code

@args

Annotation @args specifies the runtime type of the target method parameter. The type of the method parameter is annotated, not the method parameter.

Usage scenario: If the parameter type has more than one subclass, only one subclass can match the PCD.

  • @ the args (com. Ms. Aop. Jargs. Not. Anno1) : match a parameter, and the first parameter runtime requires Anno1 annotation

  • @args(com.ms.aop.jargs.demo1.Anno1,..) Matches one or more arguments, the first of which should be annotated Anno1 at run time.

  • @ the args (com. Ms. Aop. Jargs. Not. Anno1, com. Ms. Aop) jargs. Not the Anno2) : a matching Anno1, two matching Annno2 refs.

@within

@target of a non-runtime type. @target looks at the object being called, @within looks at the class of the method being called.

Differences between @target and @within:

@target(annotation A) : Determines whether annotation A is declared in the target object being called. If so, annotation A will be intercepted

@within: Determines whether annotation A is declared in the class to which the method is being called. If so, annotation A will be intercepted

@annotation

Matches methods with specified annotations (annotations apply to methods)

bean

Match by beanNam. * wildcard characters are supported.

bean(*Service) // Matches all services at the end of Service
Copy the code

other

Use a combination of

Support between PCD, && | |! Three operators. The && operator is used in the example above. | | said (not short circuit or). ! Say not.

Named binding mode

The @around (“within(per.aop.*) &&args (STR)”) example above uses the named binding pattern, writing the variable name in PCD and qualifying the type of the variable name in the method.

@Around("within(per.aop.*) && args(str)")
public Object logAspect(ProceedingJoinPoint pjp, String str) { ...}
Copy the code

For example, if STR is a String or a subclass of it, and a method can have only one input parameter.

name binding only allowed in target, this, and args pcds

The named binding mode supports only target, this, and ARgs PCDS.

argNames

Looking at the source code, you can see that all Advice annotations have an argNames field, such as @around:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Around {
    String value(a);
    String argNames(a) default "";
}
Copy the code

When this attribute is used, here is an example:

@Around(value = "execution(* TestBean.paramArgs(..) ) && args(decimal,str,..) && target(bean)", argNames = "pjp,str,decimal,bean")
@SneakyThrows // proceed will throw a test exception
Object aroundArgs(ProceedingJoinPoint pjp,/* Use named binding mode */ String str, BigDecimal decimal, Object bean) {
    // Do something before the method executes
	return  pjp.proceed();
}
Copy the code

Argnames must be used with the args, target, and this tags. Although this parameter is optional in practice, it is recommended that all parameters be configured for the following reasons:

So if the ‘argerNames’ attribute is not specified, Spring AOP will look at the class’s debugging information and try to determine the parameter name from the local variation table. This information appears whenever the class is compiled using debugging information (at least ‘-g: Vars’). The result of compiling with this flag is:

(1) Your code will be more easily reverse-engineered)

(2) The class file size will be very large (usually insignificant)

(3) Optimizations that remove unused local variables will not be applied by the compiler.

In addition, if the compiled code does not have the necessary debugging information, Spring AOP will attempt to infer the pairing of binding variables and parameters. If the variable bindings under the available information is not clear, so a AmbiguousBindingException will be thrown. If all of the above strategies fail, an IllegalArgumentException is thrown.

It is recommended that all advice annotations include argNames as IDEA will remind you anyway.

Refer to the article

  1. Spring document
  2. SpringAOP Point expression