【问题标题】:Modify value from class with @AfterReturning in Spring AOP在 Spring AOP 中使用 @AfterReturning 修改类中的值
【发布时间】:2020-05-13 20:03:37
【问题描述】:

如何使用@AfterReturning 建议修改值,它适用于除 String 之外的任何对象。我知道字符串是不变性的。以及如何在不更改 AccountDAO 类中 saveEverything() 函数的返回类型的情况下修改字符串? 这是代码sn-p:

@Component
public class AccountDAO {
    public String saveEverything(){
        String save = "save";
        return save;
    }
}

和方面:

@Aspect
@Component
public class AfterAdviceAspect {
    @AfterReturning(pointcut = "execution(* *.save*())", returning = "save")
    public void afterReturn(JoinPoint joinPoint, Object save){
        save = "0";
        System.out.println("Done");
    }
}

和主应用程序:

public class Application {
public static void main(String[] args) {
    AnnotationConfigApplicationContext context =
            new AnnotationConfigApplicationContext(JavaConfiguration.class);

    AccountDAO accountDAO = context.getBean("accountDAO", AccountDAO.class);

    System.out.println(">"+accountDAO.saveEverything());;

    context.close();
  }
}

【问题讨论】:

  • 为什么要实现这样的目标?您可以直接返回“0”对。如果仍然需要,Joinpoint 包含基于您可以执行某些操作的返回值。
  • 我想修改字符串,然后通过方面将其传递给方法
  • 你可以参考这篇文章,你可以使用 around aspect 并改变它看起来的返回值,stackoverflow.com/questions/14017860/…。希望这会有所帮助。

标签: java spring spring-aop


【解决方案1】:

来自文档:After Returning Advice

请注意,无法返回完全不同的 返回建议后使用时参考。

正如 anavaras lamurep 在 cmets 中正确指出的那样,@Around 建议可用于满足您的要求。一个示例方面如下

@Aspect
@Component
public class ExampleAspect {
    @Around("execution(* com.package..*.save*()) && within(com.package..*)")
    public String around(ProceedingJoinPoint pjp) throws Throwable {
        String rtnValue = null;
        try {
            // get the return value;
            rtnValue = (String) pjp.proceed();
        } catch(Exception e) {
            // log or re-throw the exception 
        }
        // modify the return value
        rtnValue = "0";
        return rtnValue;
    }
}

请注意,问题中给出的切入点表达式是 global 。此表达式将匹配对任何以save 开头并返回Object 的spring bean 方法的调用。这可能会产生不希望的结果。建议将类的范围限制为建议。

--- 更新---

正如@kriegaex 所指出的,为了更好的可读性和可维护性,切入点表达式可以重写为

execution(* com.package..*.save*())

execution(* save*()) && within(com.package..*)

【讨论】:

  • 对这个正确答案进行小幅改进的一种方法是通过 execution(* com.package..*.save*())execution(* save*()) && within(com.package..*) 删除多余的包名称说明符。 :-)
  • 这是我想问的。在阅读this 之后,我开始以这种方式编写切入点表达式:一个写得好的切入点应该至少包括前两种类型(种类和范围)。请让我知道我是否需要将其转换为 SO 问题以使其他人受益?
  • 这是一个一般性建议,因此当然是有道理的。作为程序员,我不喜欢冗余。如果你重构你的包结构,在这种情况下你将不得不在两个地方更新切入点——很容易忘记一个。此外,我发现较长的切入点更难阅读。如果你看我的第一个例子,它既是类型的,也是范围的。第二个示例也是如此,但都没有多余的包名称。当然,这可能是个人喜好问题,但我更喜欢我建议的变体而不是你的变体。正如我之前所说,你的也是正确的。我会赞成它。 :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-06
  • 2014-09-20
  • 2019-03-22
相关资源
最近更新 更多