【问题标题】:Spring AOP - get old field value before calling the setterSpring AOP - 在调用设置器之前获取旧字段值
【发布时间】:2015-07-19 15:51:34
【问题描述】:

亲爱的,我目前正在使用 Spring AOP (v4) 和 AspectJ 和 load-time-weaver。

我目前正在寻找一种将脏标志机制添加到我的 bean 中的方法。因此,我想在调用我的 bean 的 setter 之前使用 AOP 调用方法。我已经实现了这一点,但是如何在旧字段值被修改之前访问它?或者有没有办法获取字段名称,以便我可以在调用 setter 之前调用 getter?

谁能在这里给我举一些例子,切入点/建议必须如何让它作为参数传递?

@Aspect
public class MyAspect {

  @Before("execution(* foo.*.set*(..))") 
  public void beforeSetterCalled(JoinPoint joinPoint){
    System.out.println("beforeSetter");
  }
}

不幸的是,Spring AOP 似乎不支持“set()”字段切入点构造,这是正确的吗?或者以某种方式使用它?

感谢您的帮助。

【问题讨论】:

    标签: java spring aop aspectj pointcut


    【解决方案1】:

    我建议将完整的 AspectJ 与 set() 切入点结合使用,以获得有效的解决方案。但是,如果您不介意涉及反射的缓慢而丑陋的解决方案,您也可以执行以下操作:

    package de.scrum_master.app;
    
    public class Person {
        private int id;
        private String firstName;
        private String lastName;
    
        public Person(int id, String firstName, String lastName) {
            this.id = id;
            this.firstName = firstName;
            this.lastName = lastName;
        }
    
        public int getId() { return id; }
        public String getFirstName() { return firstName; }
        public String getLastName() { return lastName; }
    
        public void setId(int id) { this.id = id; }
        public void setFirstName(String firstName) { this.firstName = firstName; }
        public void setLastName(String lastName) { this.lastName = lastName; }
    
        @Override
        public String toString() { return "Person [" + id + ", " + firstName + " " + lastName + "]"; }
    
        public static void main(String[] args) {
            Person albert = new Person(1, "Albert", "Camus");
            Person audrey = new Person(2, "Audrey", "Hepburn");
            System.out.println(albert);
            System.out.println(audrey);
            System.out.println();
            albert.setId(8);
            albert.setLastName("Einstein");
            audrey.setId(9);
            audrey.setLastName("Tautou");
            System.out.println();
            System.out.println(albert);
            System.out.println(audrey);
        }
    }
    
    package de.scrum_master.aspect;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.SoftException;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    
    @Aspect
    public class SetterInterceptor {
        @Before("execution(* set*(*)) && target(instance) && args(newValue)")
        public void beforeSetterCalled(JoinPoint thisJoinPoint, Object instance, Object newValue) {
            String methodName = thisJoinPoint.getSignature().getName();
            try {
                System.out.println(
                    methodName.substring(3) + ": " +
                    instance
                        .getClass()
                        .getMethod(methodName.replaceFirst("set", "get"))
                        .invoke(instance) +
                    " -> " + newValue
                );
            } catch (Exception e) {
                throw new SoftException(e);
            }
        }
    }
    

    控制台日志:

    Person [1, Albert Camus]
    Person [2, Audrey Hepburn]
    
    Id: 1 -> 8
    LastName: Camus -> Einstein
    Id: 2 -> 9
    LastName: Hepburn -> Tautou
    
    Person [8, Albert Einstein]
    Person [9, Audrey Tautou]
    

    【讨论】:

      【解决方案2】:

      你对Spring not supporting field joinpoints的看法是正确的

      Spring AOP 目前只支持方法执行连接点 (建议在 Spring bean 上执行方法)。场地 拦截未实现,虽然支持字段 可以在不破坏核心 Spring AOP API 的情况下添加拦截。 如果您需要建议现场访问和更新连接点,请考虑 语言,例如 AspectJ。

      您将无法使用 Spring AOP 直接通过 AOP 通知获取字段值。

      方法与任何领域都不相关。访问器(和修改器)只是 Java 中的一种约定。如果您遵循该约定,则可以从方法名称推断字段名称并使用反射来检索它。

      【讨论】:

      • 谢谢,但有人知道“虽然可以在不破坏核心 Spring AOP API 的情况下添加对字段拦截的支持。”是什么意思。有人有这方面的经验吗?
      • @megloff 这只是意味着字段拦截不会干扰方法拦截,因此将来可能会添加向后兼容性问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-20
      • 1970-01-01
      相关资源
      最近更新 更多