Overview and Setup of AOP in Spring

Keywords: JavaEE Spring Back-end

How do we develop without using AOP?

How do we develop without AOP (face-to-face thinking).
In the first version of the development, we wrote the methods we needed, and in later maintenance updates, when we want to do the methods again, we need to add the functions to the written code.
In the case of the first edition and subsequent additions, you need to change the code you wrote before.

Spring's profile:

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!--Note the addition of constraints-->


    <!--open Spring Annotation Scan Resolves It-->
    <!--write package Be aware of your package name, which can be scanned under the advanced sections-->
    <context:component-scan base-package="com.demo.spring"></context:component-scan>

</beans>
package com.demo.spring.dao;

import org.springframework.stereotype.Repository;

@Repository(value = "userDao")
public class UserDao {
//    At the beginning, a feature has been written and new features need to be added in subsequent maintenance updates, so we have to modify the code we wrote before
//    That would be cumbersome and not very scalable

//    First Edition Developed Code
    public void save() {
        System.out.println("Project Development");
        doTransaction();
        doLog();
    }

//    New Code (Enhancement Code)
    public void doTransaction(){
        System.out.println("Transaction Processing");
    }

    public void doLog(){
        System.out.println("Log Processing");
    }
}

Test code:

package com.demo.spring.test;

import com.demo.spring.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test2 {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");

        UserDao userDao = applicationContext.getBean("userDao", UserDao.class);
        userDao.save();
    }
}


In this case, adding new functionality later and then going back to the previous one, adding code to call this new functionality can be very cumbersome when adding more functionality, even if you extract a tool class to make the code lightweight the first time you write, encapsulate these methods, you still need to show the call to go. So we have the idea of AOP.

Overview of AOP

AOP is an abbreviation for Aspect Oriented Programming, translated as "Face-to-Face Programming", which is a technology that achieves unified maintenance of program functions only through precompiled methods and runtime==dynamic agents (I don't do it, someone else does it for me)==

AOP is the continuation of OOP (object-oriented programming), a hot spot in software development, and it is also an important content and core of Spring framework. AOP can isolate parts of business logic, which reduces the coupling between parts of business logic, improves the reusability of code, and especially greatly improves the efficiency of development.

Difference between AOP and OOP
AOP and OOP seem very similar literally, but they can even be said to be two completely unrelated design ideas.

  1. OOP is designed to abstractly encapsulate entities, attributes and behaviors of business processes to obtain clearer and more efficient representation and partitioning of logical units.

  2. AOP is for the extraction of facets in a business process. It faces a step or stage in the process to achieve the isolation effect of coupling between parts in the logical process. There is a fundamental difference between the two design ideas in the goal.

Face-oriented advantages:
Reduces code duplication and focuses more on business extensions.

Face-Oriented Programming Thought is just a supplement to Object-Oriented Thought, not the opposite

Core Principle: Use dynamic proxy to add related logical statements before and after execution or when exceptions occur.
You can add new functionality to your program without modifying the previous code.
The extracted code is also conditional: the extracted code has no direct relationship with our business code.

Use cases:
Transaction: Open transaction, close transaction, roll back transaction in case of exception
Privilege Judgment: Determine whether the current operation has privileges before executing the method
Log: Enter log processing before execution

Graphical understanding:

Basic concepts of AOP

Joinpoint: A method in a class that can be enhanced, called a join point.
pointcut: Many methods in a class can be enhanced, but only adds and updates can actually be enhanced. The add and update methods can then be referred to as entry points (actual implemented connections).

Advice: Notification is what a facet does at a specific connection point (enhanced functionality). Notifications are divided into pre-notification (pre-method execution notification), post-method execution notification (post-method execution notification), surround notification (method execution is notified once before and after each).

==> Aspect: ==The process of adding notifications to a point of entry is called a facet.

Target: The target object of the proxy (the class to be enhanced) is called the target.

Proxy: A proxy object created after notification is applied to the target object.

Implementation of Spring AOP

For this programming idea of AOP, many frameworks have been implemented, Spring is one of them, which can complete face-to-face programming.

However, AOP is also implemented in the AspectJ framework, which is also an AOP framework based on Java language. AspectJ provides powerful AOP functions, is simpler to implement, is easy to use and supports annotated development, so Spring introduces AspectJ's implementation of AOP into its own framework.

So when AOP is used in the Spring framework, AspectJ is generally used to implement it.

What is AspectJ?
AspectJ is an excellent aspect-oriented framework that extends the Java language and provides a very powerful aspect implementation. This framework is for AOP only.

There are five types of notifications commonly used in AspectJ:
Pre-notification
Postnotification
Circumference Notification
Exception Notification
* Final Notice

Setup of AOP

Join the jar package

        <!-- spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.2.RELEASE</version>
        </dependency>

Implementation of XML Configuration Based on AspectJ

Here I create a separate xml configuration, and then simply import the xml file I created separately from the xml configuration file in Spring.

    <!--Import aop Profile-->
    <import resource="aop.xml"></import>

That's what the corresponding aop.xml configuration file should look like

There is a pre-notification configured here

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--Give the class with enhancements to Spring To manage-->
    <bean id="aopdemo" class="com.demo.spring.aop.AOPDemo"></bean>

    <!--Braiding: braiding connection points with notifications,The methods you will need to join are written here-->
    <aop:config>
        <!--Configure entry points,Specifically for which method to enhance-->
        <aop:pointcut id="addsave" expression="execution(* com.demo.spring.dao.UserDao.save(..))"/>

        <!--Configure Faces-->
        <aop:aspect ref="aopdemo"><!--ref The one you are referring to is the facet-->
            <aop:before method="doLog" pointcut-ref="addsave"></aop:before>
        </aop:aspect>
    </aop:config>

</beans>

Pre-notifications are added here

Cutting Code:

package com.demo.spring.aop;

public class AOPDemo {

    //    Notification: What to do at the connection point (enhancements)
    //    New Code (Enhancement Code)

    public void doLog() {
        System.out.println("Log Processing");
    }
}

The class where the entry point is located

package com.demo.spring.dao;

import org.springframework.stereotype.Repository;

@Repository(value = "userDao")
public class UserDao {

//    First Edition Developed Code
    public void save() {
        System.out.println("Project Development");
    }

}

Code to run the test:

package com.demo.spring.test;

import com.demo.spring.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test2 {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");

        UserDao userDao = applicationContext.getBean("userDao", UserDao.class);
        userDao.save();
    }
}

Result of the pre-notification:

after returning advise

Simply execute the post-notification after executing the method

Only the code in the configuration file was modified

<!--Give the class with enhancements to Spring To manage-->
    <bean id="aopdemo" class="com.demo.spring.aop.AOPDemo"></bean>

    <!--Braiding: braiding connection points with notifications,The methods you will need to join are written here-->
    <aop:config>
        <!--Configure entry points,Specifically for which method to enhance-->
        <aop:pointcut id="addsave" expression="execution(* com.demo.spring.dao.UserDao.save(..))"/>

        <!--Configure Faces-->
        <aop:aspect ref="aopdemo"><!--ref The one you are referring to is the facet-->
            <aop:after method="doLog" pointcut-ref="addsave"></aop:after>
        </aop:aspect>
    </aop:config>

Final Notification

If a method has a return value, the statement is executed after the return value is returned (after the return is executed).

<!--Give the class with enhancements to Spring To manage-->
    <bean id="aopdemo" class="com.demo.spring.aop.AOPDemo"></bean>

    <!--Braiding: braiding connection points with notifications,The methods you will need to join are written here-->
    <aop:config>
        <!--Configure entry points,Specifically for which method to enhance-->
        <aop:pointcut id="addsave" expression="execution(* com.demo.spring.dao.UserDao.save(..))"/>

        <!--Configure Faces-->
        <aop:aspect ref="aopdemo"><!--ref The one you are referring to is the facet-->
            <aop:after-returning method="doLog" pointcut-ref="addsave"></aop:after-returning>
        </aop:aspect>
    </aop:config>

Exception Notification

The class where the entry point is located

package com.demo.spring.dao;

import org.springframework.stereotype.Repository;

@Repository(value = "userDao")
public class UserDao {

//    First Edition Developed Code
    public void save() {
        System.out.println("Project Development");
        int a = 10/0;//Write an error here
    }
}

Cutting Code:

package com.demo.spring.aop;

public class AOPDemo {

    //    Notification: What to do at the connection point (enhancements)
    //    New code (also called hardening code)
    /*Exception Notification*/
     public void exceptionAdvice(Throwable e){
         System.out.println("Exception Notification"+e.getMessage());
     }
}
<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--Give the class with enhancements to Spring To manage-->
    <bean id="aopdemo" class="com.demo.spring.aop.AOPDemo"></bean>

    <!--Braiding: braiding connection points with notifications,The methods you will need to join are written here-->
    <aop:config>
        <!--Configure entry points,Specifically for which method to enhance-->
        <aop:pointcut id="addsave" expression="execution(* com.demo.spring.dao.UserDao.save(..))"/>

        <!--Configure Faces-->
        <aop:aspect ref="aopdemo"><!--ref The one you are referring to is the facet-->
        
            <aop:after-throwing method="exceptionAdvice" pointcut-ref="addsave" throwing="e"></aop:after-throwing>
             <!--throwing The parameters in the are as good as those in the heterogeneous notification-->
             
        </aop:aspect>
    </aop:config>

</beans>

Code to run the test:

package com.demo.spring.test;

import com.demo.spring.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test2 {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");

        UserDao userDao = applicationContext.getBean("userDao", UserDao.class);
        userDao.save();
    }
}

Around Advice

Surround notification is a complete replacement for pre-notification, post-notification, final notification, exception notification.

When a surround notification is executed, it goes directly into the notification and executes the statements inside the surround notification. The method to the entry point is then called until proceed() is executed.

The class where the entry point is located

package com.demo.spring.dao;

import org.springframework.stereotype.Repository;

@Repository(value = "userDao")
public class UserDao {

//    First Edition Developed Code
    public void save() {
        System.out.println("Project Development");
        int a = 10/0;//Write an error here
    }
}

Cutting Code:

package com.demo.spring.aop;

public class AOPDemo {

    //    Notification: What to do at the connection point (enhancements)
    //    New code (also called hardening code)
  /*Around Advice*/
    public void aroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
        //Put the entry point into ProceedingJoinPoint in a radiation-like way
        System.out.println("Before advice");
        try {
            proceedingJoinPoint.proceed();//Call the method of the entry point here
        } catch (Throwable throwable) {
            System.out.println("Exception Notification");
            throwable.printStackTrace();
        }
        System.out.println("after returning advise");
    }
}

In the configuration file

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--Give the class with enhancements to Spring To manage-->
    <bean id="aopdemo" class="com.demo.spring.aop.AOPDemo"></bean>

    <!--Braiding: braiding connection points with notifications,The methods you will need to join are written here-->
    <aop:config>
        <!--Configure entry points,Specifically for which method to enhance-->
        <aop:pointcut id="addsave" expression="execution(* com.demo.spring.dao.UserDao.save(..))"/>

        <!--Configure Faces-->
        <aop:aspect ref="aopdemo"><!--ref The one you are referring to is the facet-->
        
            <!--Around Advice-->
            <aop:around method="aroundAdvice" pointcut-ref="addsave"></aop:around>

        </aop:aspect>
    </aop:config>

</beans>

Code to run the test:

package com.demo.spring.test;

import com.demo.spring.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test2 {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");

        UserDao userDao = applicationContext.getBean("userDao", UserDao.class);
        userDao.save();
    }
}

Annotation-based implementation of AOP

Start AspectJ support: <aop:aspectj-autoproxy />

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!--Note the addition of constraints-->


    <!--open Spring Annotation Scan Resolves It-->
    <!--write package Be aware of your package name, which can be scanned under the advanced sections-->
    <context:component-scan base-package="com.demo.spring"></context:component-scan>

    <!--Turn on automatic proxy,Scanning annotation labels is turned on-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

The class in which the facet is located (the class containing the notification):
@Component//Create objects through spring
@Aspect//Declare that this class is faceted (class with notifications)

Pre-notification is on

package com.demo.spring.aop;

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

@Component//Creating objects through spring
@Aspect//Declare that this class is a facet (class with notifications)
public class AOPDemo {


    //Pre-notification, the code behind the label is identical to the code inside the xml
    @Before("execution(* com.demo.spring.dao.UserDao.save(..))")
    public void doLog() {
        System.out.println("Log Processing");
    }
}

Business Code:

package com.demo.spring.dao;

import org.springframework.stereotype.Repository;

@Repository(value = "userDao")
public class UserDao {

    //    First Edition Developed Code
    public void save() {
        System.out.println("Project Development");
//        int a = 10/0;
    }
}

Start test execution business code:

package com.demo.spring.test;

import com.demo.spring.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test2 {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");

        UserDao userDao = applicationContext.getBean("userDao", UserDao.class);
        userDao.save();
    }
}

Turn on Post Notification

package com.demo.spring.aop;

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

@Component//Creating objects through spring
@Aspect//Declare that this class is a facet (class with notifications)
public class AOPDemo {


    //Post Notification, the code behind the label is identical to the code inside the xml
    @After("execution(* com.demo.spring.dao.UserDao.save(..))")
    public void doLog() {
        System.out.println("Log Processing");
    }
}

Exception Notification

package com.demo.spring.aop;

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

@Component//Creating objects through spring
@Aspect//Declare that this class is a facet (class with notifications)
public class AOPDemo {

    /*Exception Notification*/
    @AfterThrowing(value = "execution(* com.demo.spring.dao.UserDao.save(..))",throwing = "e")
    public void exceptionAdvice(Throwable e){
        System.out.println("Exception Notification"+e.getMessage());
    }
}

The business code writes an exception:

package com.demo.spring.dao;

import org.springframework.stereotype.Repository;

@Repository(value = "userDao")
public class UserDao {

    //    First Edition Developed Code
    public void save() {
        System.out.println("Project Development");
        int a = 10/0;
    }
}


Print Output Successful

Around Advice

package com.demo.spring.aop;

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

@Component//Creating objects through spring
@Aspect//Declare that this class is a facet (class with notifications)
public class AOPDemo {

//Around Advice
    @Around("execution(* com.demo.spring.dao.UserDao.save(..))")
    public void aroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
        //Put the entry point into ProceedingJoinPoint in a radiation-like way
        System.out.println("Before advice");
        try {
            proceedingJoinPoint.proceed();//Call the method of the entry point here
        } catch (Throwable throwable) {
            System.out.println("Exception Notification");
            throwable.printStackTrace();
        }
        System.out.println("after returning advise");
    }
}

Still execute this exceptional business code:

package com.demo.spring.dao;

import org.springframework.stereotype.Repository;

@Repository(value = "userDao")
public class UserDao {

    //    First Edition Developed Code
    public void save() {
        System.out.println("Project Development");
        int a = 10/0;
    }
}

Result:

Posted by jandrox_ox on Thu, 25 Nov 2021 09:45:40 -0800