对@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