Spring AOP - get old field value before calling the setter

前端 未结 2 375
暗喜
暗喜 2020-12-15 14:53

Dear all I am curently using Spring AOP (v4) and AspectJ with load-time-weaver.

I am looking currently for a way to add a dirty flag mechanism into my beans. Therefo

相关标签:
2条回答
  • 2020-12-15 15:19

    You are correct about Spring not supporting field joinpoints

    Spring AOP currently supports only method execution join points (advising the execution of methods on Spring beans). Field interception is not implemented, although support for field interception could be added without breaking the core Spring AOP APIs. If you need to advise field access and update join points, consider a language such as AspectJ.

    You won't be able to use Spring AOP to get the field value through the AOP advice directly.

    A method is not related to any field. Accessors (and mutators) are just a convention in Java. If you are following that convention, you can infer the field name from the method name and use reflection to retrieve it.

    0 讨论(0)
  • 2020-12-15 15:22

    I would recommend to use full AspectJ in combination with a set() pointcut in order to get an efficient solution. But if you do not mind having a slow, ugly solution involving reflection you can also do something like this:

    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);
            }
        }
    }
    

    Console log:

    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]
    
    0 讨论(0)
提交回复
热议问题