chapter24_解析@Around

对@Around环绕通知的解析比较特别,本章单独用来讲述

一、实现

新增一个ProceedingJoinPoint接口

  • 封装了目标方法的信息
public interface ProceedingJoinPoint {

    /**
     * 调用目标方法
     */
    Object proceed() throws Throwable;

    /**
     * 获取方法参数
     */
    Object[] getArgs();

    /**
     * 获取方法签名
     */
    Method getSignature();

    /**
     * 获取目标对象
     */
    Object getTarget();
}

提供一个pjp实现类

public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint {

    private final MethodInvocation methodInvocation;

    public MethodInvocationProceedingJoinPoint(MethodInvocation methodInvocation) {
        this.methodInvocation = methodInvocation;
    }

    @Override
    public Object proceed() throws Throwable {
        return methodInvocation.proceed();
    }

    @Override
    public Object[] getArgs() {
        return methodInvocation.getArguments();
    }

    @Override
    public Method getSignature() {
        return methodInvocation.getMethod();
    }

    @Override
    public Object getTarget() {
        return methodInvocation.getThis();
    }
}

新增一个环绕通知接口

@FunctionalInterface
public interface AroundAdvice {
    /**
     * 环绕通知的逻辑实现
     *
     * @param joinPoint 封装了目标方法的信息
     * @return 目标方法的返回值
     * @throws Throwable 如果目标方法或环绕逻辑抛出异常
     */
    Object around(ProceedingJoinPoint joinPoint) throws Throwable;
}

新增环绕通知拦截器

  • 里面封装环绕通知
public class AroundAdviceInterceptor implements MethodInterceptor {

    private AroundAdvice aroundAdvice; // @Around 注解的逻辑实现

    public AroundAdviceInterceptor() {
    }

    public AroundAdviceInterceptor(AroundAdvice aroundAdvice) {
        this.aroundAdvice = aroundAdvice;
    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        // 创建 ProceedingJoinPoint 对象
        ProceedingJoinPoint joinPoint = new MethodInvocationProceedingJoinPoint(invocation);

        // 调用 @Around 注解的方法
        return aroundAdvice.around(joinPoint);
    }
}

修改ReflectiveMethodInvocation ,增加对环绕通知拦截器的处理

// 将 Advice 包装成 MethodInterceptor
protected MethodInterceptor getInterceptor(Advisor advisor) {
    if (advisor.getAdvice() instanceof MethodInterceptor) {
        return (MethodInterceptor) advisor.getAdvice();
    }
    // 如果是 MethodBeforeAdvice,使用适配器包装
    if (advisor.getAdvice() instanceof MethodBeforeAdvice) {
        return new MethodBeforeAdviceInterceptor((MethodBeforeAdvice) advisor.getAdvice());
    }
    // 如果是 @Around 注解的方法,使用 AroundAdviceInterceptor 包装
    if (advisor.getAdvice() instanceof AroundAdvice) {
        return new AroundAdviceInterceptor((AroundAdvice) advisor.getAdvice());
    }
    throw new UnsupportedOperationException("Advice type not supported: " + advisor.getAdvice().getClass());
}

修改createAdvisorForAspect 方法

  • 对@Before和@After做简化
  • 增加对@Around注解的解析
private void createAdvisorForAspect(Class<?> aspectClass) {
    ......
        for (Method method : methods) {
            // 检查是否带有 @Before 注解
            if (method.isAnnotationPresent(Before.class)) {
                Before beforeAnnotation = method.getAnnotation(Before.class);
                String expression = beforeAnnotation.value();  // 获取切点表达式

                // 创建 MethodBeforeAdviceInterceptor(通知拦截器)
                MethodBeforeAdviceInterceptor adviceInterceptor = new MethodBeforeAdviceInterceptor((method1, args, target) -> {
                    method.invoke(aspectInstance, args);  // 手动调用 @Before 方法
                });

                // 注册 MethodBeforeAdviceInterceptor 到容器
                registry.registerBeanDefinition(aspectClass.getSimpleName() + "BeforeAdviceInterceptor",
                        new BeanDefinition(adviceInterceptor.getClass()));

                // 创建 advisorDefinition
                BeanDefinition advisorDefinition = new BeanDefinition(AspectJExpressionPointcutAdvisor.class);
                advisorDefinition.getPropertyValues().addPropertyValue(new PropertyValue("expression", expression));
                advisorDefinition.getPropertyValues().addPropertyValue(new PropertyValue("advice", adviceInterceptor));

                // 注册 advisorDefinition
                registry.registerBeanDefinition(aspectClass.getSimpleName() + "BeforeAdvisor", advisorDefinition);
            }

            // 检查是否带有 @After 注解
            if (method.isAnnotationPresent(After.class)) {
                After afterAnnotation = method.getAnnotation(After.class);
                String expression = afterAnnotation.value();  // 获取切点表达式

                // 创建 AfterReturningAdviceInterceptor(通知拦截器)
                AfterReturningAdviceInterceptor adviceInterceptor = new AfterReturningAdviceInterceptor((returnValue, method1, args, target) -> {
                    method.invoke(aspectInstance, args);  // 手动调用 @After 方法
                });

                // 创建 advisorDefinition
                BeanDefinition advisorDefinition = new BeanDefinition(AspectJExpressionPointcutAdvisor.class);
                advisorDefinition.getPropertyValues().addPropertyValue(new PropertyValue("expression", expression));
                advisorDefinition.getPropertyValues().addPropertyValue(new PropertyValue("advice", adviceInterceptor));

                // 注册 advisorDefinition
                registry.registerBeanDefinition(aspectClass.getSimpleName() + "AfterAdvisor", advisorDefinition);
            }
            // 检查是否带有 @Around 注解
            if (method.isAnnotationPresent(Around.class)) {
                Around aroundAnnotation = method.getAnnotation(Around.class);
                String expression = aroundAnnotation.value();  // 获取切点表达式

                // 创建 AroundAdvice
                AroundAdvice aroundAdvice = joinPoint -> {
                    // 调用带有 @Around 注解的方法
                    return method.invoke(aspectInstance, joinPoint);
                };

                // 创建 AroundAdviceInterceptor
                AroundAdviceInterceptor adviceInterceptor = new AroundAdviceInterceptor(aroundAdvice);

                // 创建 advisorDefinition
                BeanDefinition advisorDefinition = new BeanDefinition(AspectJExpressionPointcutAdvisor.class);
                advisorDefinition.getPropertyValues().addPropertyValue(new PropertyValue("expression", expression));
                advisorDefinition.getPropertyValues().addPropertyValue(new PropertyValue("advice", adviceInterceptor));

                // 注册 advisorDefinition
                registry.registerBeanDefinition(aspectClass.getSimpleName() + "AroundAdvisor", advisorDefinition);
            }

        }
    }
}

二、测试

修改切面类

@Aspect
@Component
public class HouseworkAspect {

    // 前置通知
    @Before("execution(* cn.shopifymall.springframework.test.bean.Housework.doHousework(..))")
    public void beforeHousework() {
        System.out.println("Before doing housework.");
    }

    // 后置通知
    @After("execution(* cn.shopifymall.springframework.test.bean.Housework.doHousework(..))")
    public void afterReturningHousework() {
        System.out.println("After doing housework.");
    }

    // 环绕通知
    @Around("execution(* cn.shopifymall.springframework.test.bean.Housework.doHousework(..))")
    @SuppressWarnings("all")
    public Object aroundHousework(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("Before housework - Around");
        Object result = pjp.proceed();  // 执行目标方法
        System.out.println("After housework - Around");
        return result;
    }
}

spring.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <!-- 启用 AspectJ 自动代理,等价于@EnableAspectJAutoProxy -->
    <aspectj-autoproxy />

    <component-scan base-package="cn.shopifymall.springframework.test.bean"/>
</beans>

测试类

@Test
    public void test_duplicate_before_advice() {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");

        // 获取 Husband 对象
        Husband husband = (Husband) applicationContext.getBean("husband");

        // 调用 doHousework 方法,验证拦截器是否生效
        husband.doHousework();

    }

效果

Before doing housework.
Before housework - Around
老公正在做家务
After doing housework.
After housework - Around
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值