Spring AOP - 在调用setter之前获取旧字段值

时间:2015-07-19 15:51:35

标签: java spring aop aspectj pointcut

亲爱的所有我使用Spring AOP(v4)和AspectJ加载时间编织器。

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

任何人都可以在这里向我提供一些示例,说明切入点/建议如何将其作为参数传递?

@Aspect
public class MyAspect {

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

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

感谢您的帮助。

2 个答案:

答案 0 :(得分:3)

我建议将完整的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]

答案 1 :(得分:0)

你对Spring not supporting field joinpoints

是正确的
  

Spring AOP目前仅支持方法执行连接点   (建议在Spring bean上执行方法)。领域   拦截没有实施,虽然支持现场   可以在不破坏核心Spring AOP API的情况下添加拦截。   如果您需要建议现场访问和更新连接点,请考虑a   像AspectJ这样的语言。

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

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