Spring AOP -- aspect oriented programming in spring

1, AOP -- another programming idea
1.1 what is AOP
AOP (aspect oriented programming), literally translated, is aspect oriented programming. AOP is a programming idea and a supplement to object-oriented programming (OOP). Object oriented programming abstracts the program into objects at all levels, while aspect oriented programming abstracts the program into all aspects.
Pick up a picture from the book Spring actual combat (4th Edition):

It can be seen vividly from the figure that the so-called section is equivalent to the cross cutting point between application objects, which can be abstracted into separate modules.

1.2 why AOP is needed
Imagine the following scenario. How do we usually deal with a piece of repeated code between multiple modules in development? Obviously, no one will rely on "copy and paste". In traditional process oriented programming, we will also abstract this code into a method, and then call this method where necessary. In this way, when this code needs to be modified, we only need to change this method. However, requirements always change. One day, when a new requirement is added and needs to be modified, we need to abstract another method and call this method separately where necessary, or we don't need this method, we still have to delete every place where the method is called. In fact, problems involving the same modifications in multiple places can be solved through AOP.

1.3 AOP implementation classification
The effect of AOP is to add some general functions to the business components in the system without modifying the source code. The essence of AOP is to modify the source code of multiple methods of business components by the AOP framework. In fact, we should understand that AOP is actually a typical application of the agent mode mentioned in the previous article.
According to the timing of modifying source code in AOP framework, it can be divided into two categories:

Static AOP implementation: the AOP framework modifies the program source code in the compilation stage and generates static AOP proxy classes (the generated *. class file has been changed and a specific compiler needs to be used), such as AspectJ.
For dynamic AOP implementation, the AOP framework dynamically generates proxy objects (JDK dynamic proxy in memory or CGlib dynamic generation of AOP proxy classes) at the run-time, such as spring AOP.
The following is a comparison of common AOP implementations

If you don't know about dynamic proxy, please refer to my previous article, which explains static proxy, JDK dynamic proxy and CGlib dynamic proxy.
Static agent and dynamic agent https://www.cnblogs.com/joy99/p/10865391.html

2, AOP terminology
Characteristic terms in AOP field:

Advice: enhanced processing in the AOP framework. The notification describes when and how the aspect is executed.
Join point: a join point refers to a point that can be inserted into the section during application execution. This point can be method call and exception throw. In Spring AOP, join points are always method calls.
PointCut: you can insert a connection point for enhancement processing.
Aspect: aspect is a combination of notification and pointcut.
Introduction: introduction allows us to add new methods or properties to existing classes.
Weaving: add enhancement processing to the target object and create an enhanced object. This process is weaving.
The concept always seems a little confused, and the above terms are translated differently in different reference books, so it needs to be understood slowly in application.

3, Preliminary understanding of Spring AOP
3.1 characteristics of spring AOP
There are many kinds of AOP frameworks. The implementation methods of AOP framework introduced in Section 1.3 may be different. AOP in spring is implemented through dynamic agents. Different AOP frameworks support different join points. For example, AspectJ and JBoss support not only method pointcuts, but also field and constructor join points. Spring AOP cannot intercept the modification of object fields, nor does it support constructor connection points. We cannot apply notifications when creating beans.

3.2 simple example of spring AOP
Let's start with the code. It's easier to say it to the code. Take the following example:
This example is created based on gradle. First, build Add dependency to gradle file:

dependencies {
    compile 'org.springframework:spring-context:5.0.6.RELEASE'
}

First create an interface Ibuy java

package com.sharpcj.aopdemo.test1;

public interface IBuy {
    String buy();
}

Boy and Gril classes implement this interface respectively:
Boy.java

package com.sharpcj.aopdemo.test1;

import org.springframework.stereotype.Component;

@Component
public class Boy implements IBuy {
    @Override
    public String buy() {
        System.out.println("The boy bought a game console");
        return "recreational machines";
    }
}

Girl.java

package com.sharpcj.aopdemo.test1;

import org.springframework.stereotype.Component;

@Component
public class Girl implements IBuy {
    @Override
    public String buy() {
        System.out.println("The girl bought a beautiful dress");
        return "clothes";
    }
}

Configuration file, AppConfig java

package com.sharpcj.aopdemo;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackageClasses = {com.sharpcj.aopdemo.test1.IBuy.class})
public class AppConfig {
}

Test class, apptest java

package com.sharpcj.aopdemo;

import com.sharpcj.aopdemo.test1.Boy;
import com.sharpcj.aopdemo.test1.Girl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AppTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        Boy boy = context.getBean("boy",Boy.class);
        Girl girl = (Girl) context.getBean("girl");
        boy.buy();
        girl.buy();
    }
}

Operation results:

Automatic deployment in spring IOC is used here. Now the demand has changed. We need to print out "boys and girls have bought what they like" before boys and girls' buy method. To implement this requirement with Spring AOP, you only need the following steps:
1. Since Spring AOP is used, first in build Related dependencies are introduced into the grade file:

dependencies {
    compile 'org.springframework:spring-context:5.0.6.RELEASE'
    compile 'org.springframework:spring-aspects:5.0.6.RELEASE'
}

2. Define an aspect class, buyaspectj java

package com.sharpcj.aopdemo.test1;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class BuyAspectJ {
    @Before("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..))")
    public void haha(){
        System.out.println("Boys and girls buy what they like");
    }
}

For this class, we use the annotation @ Component to indicate that it will be assembled as a Spring Bean, and use the annotation @ Aspect to indicate that it is an Aspect.
There is only one method haha in the class. We use the @ Before annotation to indicate that it will be executed Before the method is executed. This note will be explained later.
The parameter ("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(...))") declares the tangent point, indicating that the tangent point in the tangent plane is com sharpcj. aopdemo. test1. Ibuy is the buy method in this interface. As for why it is written like this, it will be explained below.
3. Enable AOP aspect function in configuration file

package com.sharpcj.aopdemo;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan(basePackageClasses = {com.sharpcj.aopdemo.test1.IBuy.class})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {
}

We added the @ EnableAspectJAutoProxy annotation to the configuration file class, enabled the AOP function, and set the value of the parameter proxyTargetClass to true. The default value is false. The difference between the two is explained below.
OK, just test the code below, and the running results are as follows:

We can see that the results are consistent with our requirements. We did not modify the Buy methods of Boy and Girl classes, nor the code of the test class, and almost realized the requirements without intrusion. This is the "magic" of AOP.

4, Configuring Spring AOP with annotations
4.1 declaration of pointcut indicator by annotation
AspectJ pointcut indicator supported by Spring AOP

An IllegalArgumentException exception will be thrown when trying to use AspectJ other indicators in spring.

When we look at the spring supported indicators shown above, note that only the execution indicator is the only execution match, while other indicators are used to limit the match. This shows that the execution indicator is the most important indicator we use when writing the pointcut definition. On this basis, we use other indicators to limit the matching pointcuts.

The tangent expression in the following figure indicates that the notification will be triggered when the play method of Instrument is executed.

We use the execution indicator to select the play method of Instrument. The method expression starts with an * sign to identify the return value type of the method we don't care about. Then we specify the fully qualified class name and method name. For the method parameter list, we use... To identify the tangent point and select any play method, no matter what the input parameters of the method are.
Among multiple matches, we can use the links &, ||! To represent the relationship between "and", "or" and "not". However, when using XML file configuration, these symbols have special meanings, so we use "and", "or" and "not".

give an example:
The only package that qualifies this pointcut to match is com sharpcj. aopdemo. Test1, you can use
execution(* com.sharpcj.aopdemo.test1.IBuy.buy(...)) && within(com.sharpcj.aopdemo.test1.)
Select the bean in the pointcut, and you can use
execution( com.sharpcj.aopdemo.test1.IBuy.buy(...)) && bean(girl)
Modify buyaspectj java

package com.sharpcj.aopdemo.test1;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class BuyAspectJ {
    @Before("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..)) && within(com.sharpcj.aopdemo.test1.*) && bean(girl)")
    public void hehe(){
        System.out.println("Boys and girls buy what they like");
    }
}

At this point, the slice will only be applied to girl The Java class takes effect, and the execution result is:

Careful, you may find that the method name in the section has been quietly changed from haha to hehe, which has no effect on the result. It shows that the method name has no effect. It is the same as the method name decorated with @ Bean annotation when assembling beans with java configuration files in Spring IOC, which has no impact.

4.2 five types of notification are declared by annotation
There are five notification types in Spring AOP, as follows:

Modify the section class below:

package com.sharpcj.aopdemo.test1;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class BuyAspectJ {
    @Before("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..))")
    public void hehe() {
        System.out.println("before ...");
    }

    @After("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..))")
    public void haha() {
        System.out.println("After ...");
    }

    @AfterReturning("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..))")
    public void xixi() {
        System.out.println("AfterReturning ...");
    }

    @Around("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..))")
    public void xxx(ProceedingJoinPoint pj) {
        try {
            System.out.println("Around aaa ...");
            pj.proceed();
            System.out.println("Around bbb ...");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

}

In order to see the effect conveniently, in our test class, as long as the Boy class:

package com.sharpcj.aopdemo;

import com.sharpcj.aopdemo.test1.Boy;
import com.sharpcj.aopdemo.test1.Girl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AppTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        Boy boy = context.getBean("boy",Boy.class);
        Girl girl = (Girl) context.getBean("girl");
        boy.buy();
        // girl.buy();
    }
}

The results are as follows:

The results are obvious. Note that the surround notification type modified by @ Around encapsulates the whole target method. When using it, we pass in the parameter of ProceedingJoinPoint type. This object is required, and we need to call the processed () method of ProceedingJoinPoint. If the method is not called, the execution result is:

Around aaa ...
Around bbb ...
After ...
AfterReturning ...

It can be seen that if you do not call the processed () method of the object, it means that the original target method is blocked. Of course, it is also possible that your actual needs are like this.

4.3 declaration of pointcut expression by annotation
As you can see, multiple notifications we wrote above use the same Pointcut expression. For the same expression that occurs frequently like this, we can use the @ Pointcut annotation to declare the Pointcut expression, and then use the expression. The modification code is as follows:

BuyAspectJ.java

package com.sharpcj.aopdemo.test1;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class BuyAspectJ {

    @Pointcut("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..))")
    public void point(){}

    @Before("point()")
    public void hehe() {
        System.out.println("before ...");
    }

    @After("point()")
    public void haha() {
        System.out.println("After ...");
    }

    @AfterReturning("point()")
    public void xixi() {
        System.out.println("AfterReturning ...");
    }

    @Around("point()")
    public void xxx(ProceedingJoinPoint pj) {
        try {
            System.out.println("Around aaa ...");
            pj.proceed();
            System.out.println("Around bbb ...");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
}

The program running results have not changed.
Here, we use

@Pointcut("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..))")
public void point(){}

A pointcut expression is declared. The content of the method point is not important, and the method name is not important. In fact, it is only used as an identifier for notification.

4.4 processing parameters in notification by annotation
In the above example, the target method for enhancement processing has no parameters. Let's talk about the case with parameters and use them in enhancement processing.
Next, we add a parameter to the interface to represent the money spent on purchase. Through AOP enhancement, if the girl buys clothes for more than 68 yuan, she can give a pair of socks as a gift.
The change code is as follows:
IBuy.java

package com.sharpcj.aopdemo.test1;

public interface IBuy {
    String buy(double price);
}

Girl.java

package com.sharpcj.aopdemo.test1;

import org.springframework.stereotype.Component;

@Component
public class Girl implements IBuy {
    @Override
    public String buy(double price) {
        System.out.println(String.format("The girl spent%s Yuan bought a beautiful dress", price));
        return "clothes";
    }
}

Boy.java

package com.sharpcj.aopdemo.test1;

import org.springframework.stereotype.Component;

@Component
public class Boy implements IBuy {
    @Override
    public String buy(double price) {
        System.out.println(String.format("The boy spent%s Yuan bought a game console", price));
        return "recreational machines";
    }
}

Take another look at the BuyAspectJ class. We will comment out all the previous notifications. This function is realized by a surround notification:

package com.sharpcj.aopdemo.test1;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class BuyAspectJ {

    /*
    @Pointcut("execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..))")
    public void point(){}

    @Before("point()")
    public void hehe() {
        System.out.println("before ...");
    }

    @After("point()")
    public void haha() {
        System.out.println("After ...");
    }

    @AfterReturning("point()")
    public void xixi() {
        System.out.println("AfterReturning ...");
    }

    @Around("point()")
    public void xxx(ProceedingJoinPoint pj) {
        try {
            System.out.println("Around aaa ...");
            pj.proceed();
            System.out.println("Around bbb ...");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
    */


    @Pointcut("execution(String com.sharpcj.aopdemo.test1.IBuy.buy(double)) && args(price) && bean(girl)")
    public void gif(double price) {
    }

    @Around("gif(price)")
    public String hehe(ProceedingJoinPoint pj, double price){
        try {
            pj.proceed();
            if (price > 68) {
                System.out.println("The girl bought clothes for more than 68 yuan and gave a pair of socks as a gift");
                return "Clothes and socks";
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return "clothes";
    }
}

As mentioned earlier, when we don't care about the return value of the method, we use * when writing the pointcut indicator, and when we don't care about the method parameters, we use. Now, if we need to pass in parameters and have a return value, we need to use the corresponding type. When writing the notification, we also need to declare the corresponding return value type and parameter type.

Test class: apptest java

package com.sharpcj.aopdemo;

import com.sharpcj.aopdemo.test1.Boy;
import com.sharpcj.aopdemo.test1.Girl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AppTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        Boy boy = context.getBean("boy",Boy.class);
        Girl girl = (Girl) context.getBean("girl");
        String boyBought = boy.buy(35);
        String girlBought = girl.buy(99.8);

        System.out.println("The boy bought:" + boyBought);
        System.out.println("The girl bought:" + girlBought);
    }
}

Test results:

As you can see, we successfully realized the requirements through AOP and printed the results.

4.5 configuring the weaving method through annotation
There is another remaining problem. In the configuration file, when we use the annotation @ EnableAspectJAutoProxy() to enable Spring AOP, we assign the parameter proxyTargetClass to true. If we don't write the parameter, it defaults to false. Run the program at this time, and the program throws an exception

This is a cast exception. Why throw this exception? It may have been thought that this is related to the mechanism of Spring AOP dynamic proxy. This proxyTargetClass parameter determines the proxy mechanism. When this parameter is false,
It is woven through the interface based method of jdk. At this time, the agent generates an interface object. If the interface object is forcibly converted into a class that implements the interface, the above type conversion exception will be thrown naturally.
On the contrary, if proxyTargetClass is true, the dynamic proxy mode of cglib will be used. The disadvantage of this method is that when the method of the extended class is modified by final, it cannot be woven in.
To test, we set the proxyTargetClass parameter to true and set girl The Buy method of Java is decorated with final:
AppConfig.java

package com.sharpcj.aopdemo;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan(basePackageClasses = {com.sharpcj.aopdemo.test1.IBuy.class})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {
}

Girl.java

package com.sharpcj.aopdemo.test1;

import org.springframework.stereotype.Component;

@Component
public class Girl implements IBuy {
    @Override
    public final String buy(double price) {
        System.out.println(String.format("The girl spent%s Yuan bought a beautiful dress", price));
        return "clothes";
    }
}

At this time, the running result:

It can be seen that our section does not take effect.

5, Declare facets through XML configuration files
In the previous example, we have shown how to declare aspects through annotation configuration. Let's see how to declare aspects in XML files. The following is a list of common elements that declare AOP in XML:

We can still use the AOP: AspectJ AutoProxy element, which can automatically proxy the notification class annotated by AspectJ.

5.1 pointcut indicator in XML configuration file
In the XML configuration file, the expression of pointcut indicator is basically the same as that configured through annotation. The difference mentioned earlier is that "and", "or" and "or" and "not" need to be used in the XML file to represent the relationship of "and", "or" and "not".

5.2 XML file configuration AOP instance
Let's transform the above example without any annotation:
BuyAspectJ.java

package com.sharpcj.aopdemo.test2;

import org.aspectj.lang.ProceedingJoinPoint;

public class BuyAspectJ {

    public void hehe() {
        System.out.println("before ...");
    }

    public void haha() {
        System.out.println("After ...");
    }

    public void xixi() {
        System.out.println("AfterReturning ...");
    }

    public void xxx(ProceedingJoinPoint pj) {
        try {
            System.out.println("Around aaa ...");
            pj.proceed();
            System.out.println("Around bbb ...");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
}

Create a new configuration file aopdemo. In the Resource directory xml :

<?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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="boy" class="com.sharpcj.aopdemo.test2.Boy"></bean>
    <bean id="girl" class="com.sharpcj.aopdemo.test2.Girl"></bean>
    <bean id="buyAspectJ" class="com.sharpcj.aopdemo.test2.BuyAspectJ"></bean>

    <aop:config proxy-target-class="true">
        <aop:aspect id="qiemian" ref="buyAspectJ">
            <aop:before pointcut="execution(* com.sharpcj.aopdemo.test2.IBuy.buy(..))" method="hehe"/>
            <aop:after pointcut="execution(* com.sharpcj.aopdemo.test2.IBuy.buy(..))" method="haha"/>
            <aop:after-returning pointcut="execution(* com.sharpcj.aopdemo.test2.IBuy.buy(..))" method="xixi"/>
            <aop:around pointcut="execution(* com.sharpcj.aopdemo.test2.IBuy.buy(..))" method="xxx"/>
        </aop:aspect>
    </aop:config>
</beans>

Here, a section is defined respectively, which contains four types of notifications.
Test file, in use

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("aopdemo.xml");

To get the ApplicationContext, and other codes remain unchanged.

5.3 XML file configuration declaration pointcut
For frequently used pointcut expressions, we can also declare them as pointcuts.
The configuration file is as follows: aopdemo xml

<?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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="boy" class="com.sharpcj.aopdemo.test2.Boy"></bean>
    <bean id="girl" class="com.sharpcj.aopdemo.test2.Girl"></bean>
    <bean id="buyAspectJ" class="com.sharpcj.aopdemo.test2.BuyAspectJ"></bean>

    <aop:config proxy-target-class="true">
        <aop:pointcut id="apoint" expression="execution(* com.sharpcj.aopdemo.test2.IBuy.buy(..))"/>
        <aop:aspect id="qiemian" ref="buyAspectJ">
            <aop:before pointcut-ref="apoint" method="hehe"/>
            <aop:after pointcut-ref="apoint" method="haha"/>
            <aop:after-returning pointcut-ref="apoint" method="xixi"/>
            <aop:around pointcut-ref="apoint" method="xxx"/>
        </aop:aspect>
    </aop:config>
</beans>

5.4 XML files are configured as notification delivery parameters
BuyAspectJ.java

package com.sharpcj.aopdemo.test2;

import org.aspectj.lang.ProceedingJoinPoint;

public class BuyAspectJ {
public String hehe(ProceedingJoinPoint pj, double price){
        try {
            pj.proceed();
            if (price > 68) {
                System.out.println("The girl bought clothes for more than 68 yuan and gave a pair of socks as a gift");
                return "Clothes and socks";
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return "clothes";
    }
}

aopdemo.xml

<?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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="boy" class="com.sharpcj.aopdemo.test2.Boy"></bean>
    <bean id="girl" class="com.sharpcj.aopdemo.test2.Girl"></bean>
    <bean id="buyAspectJ" class="com.sharpcj.aopdemo.test2.BuyAspectJ"></bean>

    <aop:config proxy-target-class="true">
        <aop:pointcut id="apoint" expression="execution(String com.sharpcj.aopdemo.test2.IBuy.buy(double)) and args(price) and bean(girl)"/>
        <aop:aspect id="qiemian" ref="buyAspectJ">
            <aop:around pointcut-ref="apoint" method="hehe"/>
        </aop:aspect>
    </aop:config>
</beans>

5.5 Xml file configuration weaving method
Similar to annotation configuration,
CGlib proxy method:

<aop:config proxy-target-class="true"> </aop:config>

JDK proxy method:

<aop:config proxy-target-class="false"> </aop:config>

6, Summary
This paper briefly records the programming idea of AOP, then introduces the related concepts of AOP in Spring, and uses Spring AOP to program through annotation and XML configuration file. Compared with AspectJ's aspect oriented programming, Spring AOP also has some limitations, but it can solve most problems in development. If we do encounter scenes that Spring AOP can't solve, we can still use AspectJ in Spring.

Author: SharpCJ

source: https://www.cnblogs.com/joy99/p/10941543.html

This site uses the creative sharing agreement of "signature 4.0 international". Please indicate the author and source in the obvious position of the article.

Posted by Chicken Little on Thu, 05 May 2022 05:32:26 +0300