@Around

图示

  • 环绕通知的切面参数就是目标方法本身
  • 环绕通知的返回值就是目标方法的返回值,如果目标方法有返回值的话,可以对该返回值进行修改
  • 不论目标方法的返回值是基本类型(8 + 1),还是引用类型,环绕通知对该返回值的修改都可以真正影响到目标方法的返回值

aop java 环绕通知 环绕通知获取返回值_spring

业务接口

package com.example.s03;

/**
 * 业务接口
 */
public interface SomeService {
    default String order(int orderNums){return null;}
}

业务实现类

package com.example.s03;

import org.springframework.stereotype.Service;

/**
 * 业务实现类
 */
@Service
public class SomeServiceImpl implements SomeService{
    @Override
    public String order(int orderNums) {
        System.out.println("预定图书: " + orderNums + "册");
        return "order success";
    }
}

切面类

package com.example.s03;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

/**
 * 切面类
 */
@Aspect
@Component
public class SomeServiceAspect {
    /**
     * a.环绕通知的方法规范
     *  1.方法权限:public
     *  2.方法返回值:目标方法的返回值,如果目标方法有返回值可以直接修改
     *  3.方法名称:自定义
     *  4.方法参数:目标方法本身
     *  5.需要使用注解:@Around来指定通知的切入时机
     *  value参数:用来指定切入点表达式
     *
     * b.环绕通知示例
     * public String order(int orderNums)
     */
    @Around(value = "execution(* com.example.s03.*.*(..))")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
        //前置通知
        System.out.println("环绕通知的前置通知: 检查现有图书的册数");

        //pjp即为目标方法本身,res为目标方法的返回值,根据反射获取外部调用的目标方法和目标方法需要的参数
        Object res = pjp.proceed(pjp.getArgs());

        //后置通知
        System.out.println("环绕通知的后置通知: 检查预定后的图书册数");
        return res.toString().toUpperCase();
    }
}

applicationContext.xml

<!-- 添加包扫描 -->
    <context:component-scan base-package="com.example.s03"/>
    <!-- 绑定业务功能和切面功能-->
    <aop:aspectj-autoproxy/>

测试

package com.example.test;

import com.example.s03.SomeService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAroundAspect {
    //测试环绕通知
    @Test
    public void testAroundAspect(){
        //获取Spring容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("s03/applicationContext.xml");
        //获取动态代理对象
        SomeService agent = (SomeService) ac.getBean("someServiceImpl");
        //调用业务功能
        String res= agent.order(1000);
        System.out.println("目标方法的返回值: " + res);
    }
}

测试输出

  • 由测试结果可知,环绕通知包裹了目标方法,依次执行前置通知,目标方法,后置通知,并且成功的对目标方法返回的基本类型的数据做了修改
环绕通知的前置通知: 检查现有图书的册数
预定图书: 1000册
环绕通知的后置通知: 检查预定后的图书册数
目标方法的返回值: ORDER SUCCESS

Process finished with exit code 0