1. Compound operation of tangents

Supports compound operations by adding the following operators to pointcut definitions:

The operator instructions
&& With the operation.
! The operation.
\ | the \ | Or operation.

2. Naming of tangent points

In general, pointcuts are declared directly where the enhancement method is required. This method is called anonymous pointcuts. Anonymous pointcuts can only be used at the declaration. If you want to reuse this Pointcut elsewhere, you can name it with the @Pointcut annotation and the aspect class method.

Public class NamePointcut {/** * Pointcut is named method1, and this Pointcut can only be used in this class */ @pointcut ("within(net.deniro.spring4.aspectj.*)")
    private void method1() {} /** * Pointcut is named method2 and can be used in this class or in descendant classes */ @pointcut ()"within(net.deniro.spring4.aspectj.*)")
    protected void method2() {} /** * Pointcut is named method3, and this Pointcut can be used in any class * compound operations are used */ @pointcut ()"method1() && method2()")
    public void method3() {}}Copy the code

The structure of named pointcuts is as follows:

The pointcut accessibility modifier serves the same function as the class accessibility modifier, which determines which classes a defined pointcut can be used in.

Because named pointcuts use only the method name and access modifier information, we generally define the method return type as void and the method body as empty.

Once the pointcuts are defined, they can be referenced in the section class:

@Aspect
public class NamePointcutAspect {

    @After("NamePointcut.method2()")
    public void aspectMethod1() {} /** * this is a compound operation */ @after ()"NamePointcut.method2() && NamePointcut.method3()")
    public void aspectMethod2() {}}Copy the code

3 Weaving sequence

A join point can match multiple pointcuts at the same time, and the rules for reinforcing pointcuts into the order at the join point are as follows:

1. If enhancements are declared in the same facet class, they are woven in the order defined in the facet class; 2. If the increase in the cut surface of the different classes, and these aspects are achieved org. Springframework. Core. Ordered interface, is determined by the method of Ordered the serial number of (serial number small woven into first); 3. If the increase in different section of class, but the plane class does not implement org. Springframework. Core. Ordered interface, the order of the weave is uncertain.

Assume that there are two class A and B, both of which realize the Ordered interface. The order of A is 1 and that of B is 2, and both class A and B define 3 enhancements. Then, the weaving order matching these 6 enhancements is shown in the figure below:

4 Obtain connection point information

4.1 JoinPoint

Org. Aspectj. Lang. JoinPoint interface represents the target class connection object, which defines the main method.

methods instructions
Object[] getArgs() Gets the list of input arguments for the join point method run time.
Signature getSignature() Gets the method signature object for the join point.
Object getTarget() Gets the target object of the join point.
Object getThis() Gets the proxy object.

4.2 ProceedingJoinPoint

Org. Aspectj. Lang. ProceedingJoinPoint inherited the JoinPoint interface, it has added two methods (they are used to perform the join point method).

methods instructions
Object proceed() throws Throwable Execute the method at the join point of the target object by reflection.
Object proceed(Object[] var1) throws Throwable Execute the method at the join point of the target object via reflection, using the new input parameter (replacing the original one).

4.3 the sample

Cook interface:

Public interface Cook {/** ** / void make(); /** * @param name */ void make(String name); }Copy the code

CookA class:

public class CookA implements Cook {
    public void make() {
        System.out.println("Make food.");
    }

    public void make(String name) {
        System.out.println("Make"+ name); }}Copy the code

Access join point information in the aspect class:

@Aspect
public class JoinPointAspect {

    @Around("within(net.deniro.spring4.aspectj.CookA)")
    public void test(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("--------- get join point object [Start] ---------");
        System.out.println("Parameter:" + pjp.getArgs()[0]);
        System.out.println("Signature Object:"+ pjp.getTarget().getClass()); Proceed (); // Execute the target object method pjp.proceed(); System.out.println("--------- get join point object [End] ---------"); }}Copy the code

Spring Bean configuration:

<? xml version="1.0" encoding="UTF-8"? > <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <! Aspectj driver --> < AOP: Aspectj-autoproxy /> <bean id="cookA" class="net.deniro.spring4.aspectj.CookA"/>
    <bean class="net.deniro.spring4.aspectj.JoinPointAspect"/>
</beans>
Copy the code

Output result:

— — — — — — — — — to get connection object [to] — — — — — — — — — parameters: sushi signature objects: class net. Deniro. Spring4. Aspectj. CookA make sushi — — — — — — — — — to get connection object 【 over 】 — — — — — — — — —

5 Bind the method entry parameter of the join point

Pointcut functions such as args(), this(), target(), @args(), @Within (), @target(), and @annotation() can specify parameter names in addition to class names to bind method inputs at target object join points to enhanced methods. Where args() is used to bind join point method inputs, @annotation() is used to bind join point method annotation objects, and @args() is used to bind join point method inputs.

CookC class:

public class CookC implements Cook {
    public void make() {
        System.out.println("Make food.");
    }

    public void make(String name) {
        System.out.println("Make" + name);
    }

    public void make(String name, int num) {
        System.out.println("Make" + name + "" + num + "A"); }}Copy the code

Cut class:

@Aspect
public class ParamsAspect {

    @Before("target(net.deniro.spring4.aspectj.CookC) && args(name,num,..) ")
    public void test(String name,int num) {
        System.out.println("---------- binding join point entry parameter [Start] ----------");
        System.out.println("name:" + name);
        System.out.println("num:" + num);
        System.out.println("---------- binding join point entry parameter [End] ----------"); }}Copy the code
  • The join point expression hereargs(name,num,..)The types of name and num are first found to generate the real expressionargs(String,int,..).
  • An enhanced method can get join point method inputs by name and num.

The process for pointcut matching and parameter binding looks like this:

  1. args()The input parameter with the same name is found in the enhanced method based on the parameter name and the type of the corresponding parameter is obtained, thus obtaining the input parameter type matching the join point method.
  2. The join point method entry type is located by the parameter nameargs()The position declared in the function is determined.

The matching process in the above example is as follows:

The Spring configuration:

<! -- aspectJ driver --> < AOP :aspectj-autoproxy proxy-target-class="true"/>

<bean id="cookC" class="net.deniro.spring4.aspectj.CookC"/>
<bean class="net.deniro.spring4.aspectj.ParamsAspect"/>
Copy the code

Note: < AOP :aspectj-autoproxy proxy-target-class=”true” /> This is because CookC’s public void Make (String Name, int num) is a method unique to that class (a method not defined by the interface), so you must use CGLib’s proxy method for subclassing.

Unit tests:

ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
CookC cookC = (CookC) context.getBean("cookC");
cookC.make("Sushi", 100);
Copy the code

Output result:

— — — — — — — — — — the binding points into the reference [to] — — — — — — — — — — name: sushi num: 100 — — — — — — — — — — the binding points into the reference 【 over 】 — — — — — — — — — — make sushi, 100

6 Bind proxy objects

Use this() or target() to bind an instance of the proxied object. When an object is bound by a class instance name, it still has the same function as the original join point match, but the class name is indirectly determined by the same input parameter type in the enhanced method.

@Aspect
public class ProxyAspect {

    @Before("this(cook)")
    public void bind(Cook cook) {
        System.out.println("-------- Bind proxy object [Start] --------");
        System.out.println(cook.getClass().getName());
        System.out.println("-------- Bind proxy object [End] --------"); }}Copy the code

First through public void bind (Cook Cook) to find a Cook of the type, then convert the tangent point expression to this (net. Deniro. Spring4. Aspectj. Cook). This means that the pointcut matches all methods in the Cook class for all proxy objects.

Output result:

— — — — — — — — the binding proxy objects [to] — — — — — — — — net. Deniro. Spring4. Aspectj. CookC? EnhancerBySpringCGLIB? 217 fb793 — — — — — — — — the binding proxy objects 【 over 】 — — — — — — — —

The target() binding is similar to this().

Bind class annotation objects

Both the @Within () and @target() functions bind the annotation object of the target class to the enhanced method.

Define a logging annotation class:

@ Retention (RetentionPolicy RUNTIME) / / Retention @ Target ({ElementType METHOD, ElementType. TYPE}) / / Target TYPE public @ interface Log { boolean value() defaulttrue; // Declare member variables}Copy the code

Apply this annotation class to CookD:

@Log
public class CookD implements Cook {
    public void make() {
        System.out.println("Making cakes");
    }

    public void make(String name) {

    }
}
Copy the code

Binding class annotation object:

@Aspect
public class ClassAnnotationObjectAspect {

    @Before("@within(log)")
    public void bind(Log log){
        System.out.println("---------- Binding class annotation object [Start] ----------");
        System.out.println(log.getClass().getName());
        System.out.println("---------- binding class annotation object [End] ----------"); }}Copy the code

The Spring configuration:

<! -- aspectJ driver --> < AOP :aspectj-autoproxy proxy-target-class="true"/>


<bean id="cookD" class="net.deniro.spring4.aspectj.CookD"/>
<bean class="net.deniro.spring4.aspectj.ClassAnnotationObjectAspect"/>
Copy the code

Unit tests:

ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
CookD cook = (CookD) context.getBean("cookD");
cook.make();
Copy the code

Output result:

— — — — — — — — — — the binding class annotation object [to] — — — — — — — — — — the sun. The proxy. $Proxy8 — — — — — — — — — — the binding class annotation object 【 over 】 — — — — — — — — — —

Com.sun.proxy.$Proxy8 shows that the CookD annotated Log object is also proxied

Bind the return value

In post-enhancement, return values of join point methods can be bound by RETURNING.

Section:

@Aspect
public class ReturnValueAspect {

    @AfterReturning(value = "target(net.deniro.spring4.aspectj.CookA)", returning = "value")
    public void bind(boolean value) {
        System.out.println("Binding return value [Start]");
        System.out.println("value:" + value);
        System.out.println("Bind return value [End]"); }}Copy the code

** Note: The value of ** RETURNING must be the same as the method parameter name.

CookA New Smell method:

public boolean smell(String name) {
	System.out.println(name + "Does it smell good?);
	return true;
}
Copy the code

Unit tests:

ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
CookA cook = (CookA) context.getBean("cookA");
cook.smell("Duck");
Copy the code

Output result:

Is the roast duck delicious? Binding return value [Start] value: true Binding return value

9 Binding Exception

You can use the Throwing member variable of the AfterThrowing annotation to bind exceptions thrown by join points.

Cut class:

@Aspect
public class ExceptionAspect {

    @AfterThrowing(value = "target(net.deniro.spring4.aspectj.CookA)",throwing = "e")
    public void bind(CookException e){
        System.out.println("Binding exception [start]");
        System.out.println("e:" + e.getMessage());
        System.out.println("Binding exception [End]"); }}Copy the code

** Note: the value of **throwing must be the same as the method parameter name.

Unit tests:

ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
CookA cook = (CookA) context.getBean("cookA");
cook.make("");
Copy the code

Output result:

E: What are you cooking? Abnormal binding [End]

`