Dynamic agent AOP

Posted by elite_prodigy on Thu, 16 Dec 2021 18:22:38 +0100

1 what is AOP?

  • Aspect Oriented Programming is the abbreviation of Aspect Oriented Programming. Aspect specification is the method of dynamic agent. Its function is to enhance the method without changing the source code of the business layer method. The underlying layer uses dynamic agent technology. Aspect Oriented Programming can also be understood as dynamic agent oriented programming.

2 AOP related concepts

  • Target: the represented object is the target object
  • Proxy: the enhanced object is the proxy object
  • Joinpoint: refers to all intercepted methods in the target object
  • Pointcut: the enhanced method in the target object
  • Advice (notification): the method that is called before or after the execution of the target method is notification.
  • Aspect: the location where the notification method and the pointcut method are combined is called the aspect
  • Weaving: the process of combining notification method and pointcut method. The result of weaving is facet

To sum up:
Connection points are all intercepted methods, and pointcuts are all enhanced methods. Connection points are not necessarily pointcuts, but pointcuts must be connection points. What needs to be done before or after the execution of the target object method is called notification, which has enhanced business. Organizing entry points and notifications together is called weaving in, and the result of weaving in is facet.

3 AOP configuration implementation steps

<1> Step 1: import related dependencies: Spring context and aspectjweaver

<!--spring Core dependency-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.9.RELEASE</version>
</dependency>
<!--Pointcut expression dependency, function: find which methods need to be enhanced through expressions, that is, find pointcuts-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>

<2> Step 2: define the notification class and target object

  • AOP target interface:
public interface StudentService {
    //Query all
    public abstract List<Student> findAll() throws IOException;

    public void transfer(Integer outId, Integer inId, double money);
}

  • AOP target realization class:
@Service("studentService")
public class StudentServiceImpl implements StudentService {
    @Override
    public List<Student> findAll() throws IOException {
        System.out.println("Query all student information findAll...");
        return null;
    }
   @Override
    public void transfer(Integer outId,Integer inId,double money){
        //One three account - 1000 yuan
        System.out.println("call dao: Zhang San("+outId+")Your account"+(-money)+"element");
        //2 Li Si's account + 1000 yuan
        System.out.println("call dao: Li Si("+inId+")Your account"+money+"element");
    }
    //This method does not exist in the interface and will not be intercepted
    public void show(){
        System.out.println("----------------");
    }
}

Note: the proxy is an interface object. There are no methods in the interface. The methods of the implementation class will not be enhanced

  • Notification class:
import org.aspectj.lang.ProceedingJoinPoint;

//The notification class tells spring what to do before and after enhancement
public class Advice {
    public void before(){
        //Pre notification: start transaction
        System.out.println("Pre notification: start transaction");
    }
    public void afterReturn(){
        //Post notification: commit transaction
        System.out.println("Post notification: commit transaction");
    }
    public void afterThrowable(){
        //Exception notification: rollback transaction
        System.out.println("Exception notification: rollback transaction");
    }
    public void after(){
        //Final notice: release resources
        System.out.println("Final notice: release resources");
    }

    // Surround notification: Spring provides us with a way to manually call the target object method or other notification methods
    // When spring calls the surround notification method, it will pass an object that encapsulates the target method, called ProceedingJoinPoint
    public Object around(ProceedingJoinPoint pjp){
        Object result =null;
        try {
            //Before advice 
            before();
            //Execute the target method, which is equivalent to result = method in the dynamic agent invoke(...)
            result = pjp.proceed();
            //Post notification
            afterReturn();
        } catch (Throwable throwable) {
            //Exception notification
            afterThrowable();
            throwable.printStackTrace();
        } finally {
            //Final notice
            after();
        }
        return result;
    }
}

<3> Configure AOP with XML file

    1 Configuring target objects, adding to spring In container
	2 Configuring notification objects, adding to spring In container
	3 Configure the pointcut method and notification method weaving process, that is, configure the aspect
  • Pure XML 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.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--1.to configure service-->
    <bean id="studentService" class="com.itheima.service.impl.StudentServiceImpl"/>

    <!--2.Configure notification objects-->
    <bean id="myAdvice" class="com.itheima.aop.Advice"/>

    <!--3.to configure AOP-->
    <aop:config>
        <!--3.1 to configure AOP Pointcut expression[Can be placed anywhere]-->
        <!--*Space represents void Method name
            .*:.StudentServiceImpl
            .*:.Method name
            (..)Method parameters, ..Represents an arbitrary parameter
        -->
        <aop:pointcut id="pt" expression="execution(* com.itheima.service.impl.*.*(..))"/>
        <!--<aop:pointcut id="pt" expression="execution(* com.itheima.service.impl.StudentServiceImpl.*(..))"/>-->

        <!--3.2 Configure section-->
        <aop:aspect ref="myAdvice">
            <!--Before advice -->
            <aop:before method="before" pointcut-ref="pt"/>
            <!--Post notification-->
            <aop:after-returning method="afterReturn" pointcut-ref="pt"/>
            <!--Exception notification-->
            <aop:after-throwing method="afterThrowable" pointcut-ref="pt"/>
            <!--Final notice-->
            <aop:after method="after" pointcut-ref="pt"/>

            <!--Use surround notifications-->
            <!--<aop:around method="around" pointcut-ref="pt"/>-->
        </aop:aspect>
    </aop:config>
</beans>
  • Annotation configuration:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

//The notification class tells spring what to do before and after enhancement
@Component("advice")
@Aspect//The notification is a faceted class, and its annotations will be scanned during scanning / / instead: < AOP: aspect ref = "advice" >
public class Advice {

    @Pointcut("execution(* com.itheima.service.impl.*.*(..))")
    //id is the method name [initial lowercase]
    public void pt() {
    }

    //= note: use the annotation to configure AOP, post notification and exception notification will be called after the final notification.
// In 5.1.1 of spring context This is true in version 9. It may be solved in a later version,
// (solved in version 5.2.6 and above).
// However, we can use surround notification to solve this problem. It is recommended to use surround notification==**
  /*  @Before("pt()")
    public void before(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        //Pre notification: start transaction
        System.out.println("Pre notification: start transaction "+ args[0]);
    }*/
//Two methods to get passed parameters. If the target method has no passed parameters, it will not be executed
    @Before("execution(* com.itheima.service.impl.*.*(..))&&args(x)")
    public void before(int x) {
        //Pre notification: start transaction
        System.out.println("Pre notification: start transaction" + x);
    }

    @AfterReturning("pt()")
    public void afterReturn() {
        //Post notification: commit transaction
        System.out.println("Post notification: commit transaction");
    }

    @AfterThrowing("pt()")
    public void afterThrowable() {
        //Exception notification: rollback transaction
        System.out.println("Exception notification: rollback transaction");
    }

    @After("pt()")
    public void after() {
        //Final notice: release resources
        System.out.println("Final notice: release resources");
    }

    // Surround notification: Spring provides us with a way to manually call the target object method or other notification methods
    // When spring calls the surround notification method, it will pass an object that encapsulates the target method, called ProceedingJoinPoint
    //@Around("pt()")
    public Object around(ProceedingJoinPoint pjp) {
        Object result = null;
        try {
            //Before advice 
            //Object[] args = pjp.getArgs();
            //before();
            //Execute the target method, which is equivalent to result = method in the dynamic agent invoke(...)
            result = pjp.proceed();
            //Post notification
            afterReturn();
        } catch (Throwable throwable) {
            //Exception notification
            afterThrowable();
            throwable.printStackTrace();
        } finally {
            //Final notice
            after();
        }
        return result;
    }
}

Note:
Using the annotation configuration AOP, the post notification and exception notification will be called after the final notification.
In 5.1.1 of spring context This is true in version 9. It may be solved in a later version,
(solved in version 5.2.6 and above).
However, we can use surround notification to solve this problem. It is recommended to use surround notification

  • Core configuration class instead of XML
import org.springframework.context.annotation.*;

@Configuration//Represents the replacement of ApplicationContext XML identifier [can not be written]
@ComponentScan("com.itheima")//Enable Spring annotation scanning
@EnableAspectJAutoProxy//Enable AOP annotation support for Spring
public class SpringConfig {
}


Topics: Java Spring