Spring basic usage 7 - AOP support (2)

       Foreword: AOP, that is, aspect-oriented programming, as a supplement to aspect-oriented programming, has been relatively mature. If OOP considers program structure from a static perspective, then AOP considers program operation from a dynamic perspective. This article aims to introduce Spring's support for AOP and briefly describe its usage.

This article focuses on the following issues:

  • SpringAOP access parameter of target method
  • Execution order of enhancement processing

1. SpringAOP access parameters of the target method

         The easiest way to access the target method is to define the first parameter as JoinPoint type when defining the enhanced processing method. When the enhanced processing method is called, the JoinPoint parameter represents the join point where the enhanced processing is woven. JoinPoint contains the following commonly used methods:

  • Object[] getArgs : returns the parameters of the target method
  • Signature getSignature : Returns the signature of the target method
  • Object getTarget : Returns the target object processed by the woven enhancement
  • Object getThis : Returns the proxy object generated by the AOP framework for the target object
Hint: When using @Around processing, we need to define the first parameter as ProceedingJoinPoint type, which is a subclass of JoinPoint.

2. Output DEMO

          The test project directory is as follows:

2.1 Prepare the XML configuration file

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-4.3.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
    
    <!-- Specify automatic search for bean components and automatic search for aspect classes -->
    <context:component-scan base-package="com.wj.chapter6.aop2">
        <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
    </context:component-scan>
    
    <!-- Enable @AspectJ support -->
    <aop:aspectj-autoproxy/>
    
</beans>

       illustrate:

2.2 Writing aspect classes       

       The following aspect classes define the enhancement processing in Before, Around, AfterReturning and After 4, and access the target method woven into the enhanced processing, the parameters of the target method and the target object woven into the enhanced processing in the 4 enhanced processing respectively. Wait:

package com.wj.chapter6.aop2.aspect;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

/**
 * Define an aspect that tests access to the target method parameters
 */
@Aspect
public class FourAdviceTest {
    
    @Around("execution(* com.wj.chapter6.aop2.service.*.*(..))")
    public Object processTx(ProceedingJoinPoint jp) throws java.lang.Throwable {
        System.out.println("[Around enhancement] Before executing the target method, the simulation starts the transaction...");
        // access the parameters of the execution target method
        Object[] args = jp.getArgs();
        // When the parameters to execute the target method exist,
        // and the first parameter is a string parameter
        if (args != null && args.length > 0
            && args[0] instanceof String) {
            // Modify the first parameter of the target method call parameter
            args[0] = "[Added prefix]" + args[0];
        }
        //Execute the target method and save the return value after the target method is executed
        Object rvt = jp.proceed(args);
        System.out.println("[Around enhancement] After executing the target method, the simulation ends the transaction...");
        // If rvt is of type Integer, change rvt to its square
        if(rvt != null && rvt instanceof Integer)
            rvt = (Integer)rvt * (Integer)rvt;
        return rvt;
    }
    
    @Before("execution(* com.wj.chapter6.aop2.service.*.*(..))")
    public void authority(JoinPoint jp) {
        System.out.println("[Before Enhancement] Simulate Execute Permission Check");
        // Returns the target method that is woven into the enhancement process
        System.out.println("[Before enhancement] The target method to be woven into enhancement processing is: " + jp.getSignature().getName());
        // access the parameters of the execution target method
        System.out.println("[Before enhancement] The parameters of the target method are: " + Arrays.toString(jp.getArgs()));
        // access the enhanced target object
        System.out.println("[Before enhancement] The target object that is woven into the enhancement processing is: " + jp.getTarget());
    }
    
    @AfterReturning(pointcut="execution(* com.wj.chapter6.aop2.service.*.*(..))", returning="rvt")
    public void log(JoinPoint jp , Object rvt) {
        System.out.println("[AfterReturning enhancement] Get the return value of the target method: " + rvt);
        System.out.println("[AfterReturning enhancement] Simulate logging function...");
        // Returns the target method that is woven into the enhancement process
        System.out.println("[AfterReturning enhancement] The target method to be woven into enhancement processing is: " + jp.getSignature().getName());
        // access the parameters of the execution target method
        System.out.println("[AfterReturning enhancement] The parameters of the target method are: " + Arrays.toString(jp.getArgs()));
        // access the enhanced target object
        System.out.println("[AfterReturning enhancement] The target object to be woven into enhancement processing is: " + jp.getTarget());
    }

    // Define After enhancement processing
    @After("execution(* com.wj.chapter6.aop2.service.*.*(..))")
    public void release(JoinPoint jp) {
        System.out.println("[After Enhancement] Release resources after the simulation method ends...");
        // Returns the target method that is woven into the enhancement process
        System.out.println("[After Enhancement] The target method to be woven into enhancement processing is: " + jp.getSignature().getName());
        // access the parameters of the execution target method
        System.out.println("[After Enhancement] The parameters of the target method are: " + Arrays.toString(jp.getArgs()));
        // access the enhanced target object
        System.out.println("[After enhancement] The target object to be woven into enhancement processing is: " + jp.getTarget());
    }
}

         As can be seen from the above code, in the four enhancement processes of Before, Around, AfterReturning and After, the enhanced object, target method and method parameters can be accessed through the same code. But only Around enhancement processing can change the method's parameters and return value.

2.3 Write business code

       Interface + implementation, the business-related interface will not be on the code, you can view it through the attachment, the following is the business implementation class:

package com.wj.chapter6.aop2.service;

import org.springframework.stereotype.Component;

@Component("addService")
public class AddService implements IAddService {
    
    @Override
    public boolean addUser(String name , String pass){
        System.out.println("[AddService.addUser] Add user: " + name);
        return true;
    }
    
    @Override
    public void addProduct(String name) {
        System.out.println("【AddService.addProduct】添加商品:" + name);
    }

    @Override
    public void addException() {
        throw new NullPointerException();
    }
}

 2.4 编写测试代码、查看运行结果

package com.wj.chapter6.aop2;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.wj.chapter6.aop2.service.IAddService;

public class BeanTest {
    // 1.指明xml配置文件位置,便于Spring读取,从而知道Bean的相关信息
    private static final String PATH_XML = "com/wj/chapter6/aop2/applicationContext.xml";
    
    @SuppressWarnings("resource")
    public static void main(String[] args) {
        // 2.根据xml配置文件,创建Spring IOC容器的上下文
        ApplicationContext ctx = new ClassPathXmlApplicationContext(PATH_XML);
        
        IAddService addService = ctx.getBean("addService" , IAddService.class);
        addService.addUser("熊燕子", "123456");
    }
}

         测试结果为:

3. 访问目标方法参数的简单方式

        我们可以在程序中使用args来绑定目标方法的参数。如果在一个 args表达式中指定了一个或多个参数,该切入点将只匹配具有对应形参的方法,且目标方法的参数值将被传入增强处理方法。下面辅以例子说明:

package com.wj.chapter6.aop3.aspect;

import java.util.Date;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class AccessArgAspect {
    // 下面的args(arg0,arg1)会限制目标方法必须有2个形参
    @AfterReturning(returning="rvt" , pointcut="execution(* com.wj.chapter6.aop3.service.*.*(..)) && args(date,name,pass)")
    // 此处指定date为Date类型,name、pass为String类型
    // 则args(date,name,pass)还要求目标方法的第一个参数为Date类型,后两个形参都是String类型
    public void access(Object rvt, Date date, String name , String pass) {
        System.out.println("调用目标方法第1个参数为:" + date);
        System.out.println("调用目标方法第2个参数为:" + name);
        System.out.println("调用目标方法第3个参数为:" + pass);
        System.out.println("获取目标方法返回值:" + rvt);
        System.out.println("模拟记录日志功能...");
    }
}

       上面的程序中,定义pointcut时,表达式中增加了args(date,name,pass)部分,意味着可以在增强处理方法(access方法)中定义date,name,pass三个属性——这三个形参的类型可以随意指定,但一旦指定了这三个参数的类型,则这三个形参类型将用于限制该切入点只匹配第一个参数类型为Date,第二、三个参数类型为String的方法(方法参数个数和类型若有不同均不匹配)。

       args表达式有如下两个作用:

  • 提供了一种简单的方式来访问目标方法的参数

  • 可用于对切入点表达式作额外的限制

      测试结果为:

        测试代码见附件。

4. 织入增强处理的顺序

        Spring AOP和AspectJ一样,采用有限顺序来织入增强处理:

  • 在“进入”连接点时,最高优先级的增强处理将先被织入(所以给定的两个Before增强处理 中,优先级高的那个会先执行);
  • 在“退出”连接点时,最高优先级的增强处理会最后被织入(所以给定的两个After增强处理中,优先级高的那个会后执行);
  • 当不同的切面中的多个增强处理需要在同一个连接点被织入时,Spring AOP将以随机的顺序来织入这些增强处理。
       如果应用需要指定不同切面类里的增强处理的优先级,Spring提供了如下两种解决方案:
  • 让切面类实现org.springframework.core.Ordered接口:实现该接口只需要实现一个int getOrder()方法,该方法返回值越小,优先级越高;
  • 直接使用@Order注解来修饰一个切面类:使用这个注解时可以配置一个int类型的value属性,该属性值越小,优先级越高;(个人感觉更方便)

代码链接:http://pan.baidu.com/s/1hsafhPi 密码:d5z1

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326245186&siteId=291194637