【问题标题】:Spring AOP : Declaring additional methods or fields on behalf of a typeSpring AOP:代表类型声明其他方法或字段
【发布时间】:2020-05-01 11:21:50
【问题描述】:

在 Spring AOP 的规范中提到:

简介:代表一个类型声明额外的方法或字段。 Spring AOP 允许您向任何建议的对象引入新接口(和相应的实现)。例如,您可以使用介绍使 bean 实现 IsModified 接口,以简化缓存。 (介绍在 AspectJ 社区中称为类型间声明。)

我不知道如何为建议课程添加新字段,如果您有经验,能否举个例子?

【问题讨论】:

    标签: java spring spring-aop


    【解决方案1】:

    演示 Spring AOP 介绍的代码得到了一个很长的答案。希望这会有所帮助

    考虑如下界面

    package rg.test.aop;
    
    public interface UserService {
        void sayHello();
    }
    

    还有两种实现方式

    UserServiceOneImpl

    package rg.test.aop.one;
    
    import org.springframework.stereotype.Service;
    
    import rg.test.aop.UserService;
    
    @Service
    public class UserServiceOneImpl implements UserService {
    
        @Override
        public void sayHello() {
            System.out.println("One");
        }
    
    }
    

    和 UserServiceTwoImpl

    package rg.test.aop.two;
    
    import org.springframework.stereotype.Service;
    
    import rg.test.aop.UserService;
    
    @Service
    public class UserServiceTwoImpl implements UserService {
    
        @Override
        public void sayHello() {
            System.out.println("Two");
        }
    
    }
    

    还有一个接口和它的实现将被 AOP 引入

    package rg.test.aop.intro;
    
    public interface LoginTracker {
        String FIELD = "Field";
    
        Integer incrementLoginCount();
    
    }
    

    实施

    package rg.test.aop.intro;
    
    public class DefaultLoginTracker implements LoginTracker {
    
        Integer count = 5;
    
        @Override
        public Integer incrementLoginCount() {
            return ++count;
        }
    
    }
    

    Spring AOP 建议在 rg.test.aop.two 包下的所有类中引入相同的建议

    package rg.test.aop.aspect;
    
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.DeclareParents;
    import org.springframework.stereotype.Component;
    
    import rg.test.aop.intro.DefaultLoginTracker;
    import rg.test.aop.intro.LoginTracker;
    
    @Aspect
    @Component
    public class IntroTestAspect {
    
        @DeclareParents(value="rg.test.aop.two.*+", defaultImpl=DefaultLoginTracker.class)
        LoginTracker tracker;
    }
    

    要实现的接口由注解字段的类型决定。(这里LoginTracker

    任何匹配类型的 bean 都实现 LoginTracker 接口。

    现在当你运行下面的测试类时

    //package and imports
    
    public class IntroductionTest {
    
        public static void main(String[] args) throws Exception {
            AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(IntroductionConfig.class);
    
            LoginTracker tracker = ctx.getBean(LoginTracker.class);
            System.out.println(tracker);
            System.out.println("------------------------");
            UserService userOne = (UserService) ctx.getBean("userServiceOneImpl");
            UserService userTwo = (UserService) ctx.getBean("userServiceTwoImpl");
    
            printDetails(userOne);
            System.out.println("------------------------");
            printDetails(userTwo);
    
            ctx.registerShutdownHook();
    
        }
    
        private static void printDetails(Object obj) throws Exception {
            System.out.println("Is LoginTracker type :"+LoginTracker.class.isAssignableFrom(obj.getClass()));
            System.out.println("Is UserService type :"+UserService.class.isAssignableFrom(obj.getClass()));
    
            System.out.println("Implemented Interfaces : ");
            for (Class clazz : obj.getClass().getInterfaces()) {
                System.out.println(clazz);
            }
    
            System.out.println("Methods : ");
            for (Method method : obj.getClass().getMethods()) {
                System.out.println(method);
            }
    
            System.out.println("Fields : ");
            for (Field field : obj.getClass().getFields()) {
                System.out.println(field);
            }
    
            // If Advised
            if (Advised.class.isAssignableFrom(obj.getClass())) {
                LoginTracker us = (LoginTracker) obj;
                System.out.println(us.incrementLoginCount());
    
            }
        }
    
    }
    

    打印以下日志(注意:此处仅复制日志的相关部分以方便参考。)

    rg.test.aop.two.UserServiceTwoImpl@c15d8b
    ------------------------
    Is LoginTracker type :false
    Is UserService type :true
    Implemented Interfaces : 
    interface rg.test.aop.UserService
    Methods : 
    public void rg.test.aop.one.UserServiceOneImpl.sayHello()
    Fields : 
    ------------------------
    Is LoginTracker type :true
    Is UserService type :true
    Implemented Interfaces : 
    interface rg.test.aop.UserService
    interface rg.test.aop.intro.LoginTracker
    interface org.springframework.aop.SpringProxy
    interface org.springframework.aop.framework.Advised
    interface org.springframework.core.DecoratingProxy
    Methods : 
    public final java.lang.Integer com.sun.proxy.$Proxy19.incrementLoginCount()
    public final void com.sun.proxy.$Proxy19.sayHello()
    Fields : 
    public static final java.lang.String rg.test.aop.intro.LoginTracker.FIELD
    Count :6
    

    日志显示了为 UserServiceTwoImpl bean 引入的方法和字段。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-12
      • 2014-05-08
      • 2023-03-24
      • 2018-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多