有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

JavaSpringAOP:代表类型声明其他方法或字段

Spring AOP规范中提到:

Introduction: declaring additional methods or fields on behalf of a type. Spring AOP allows you to introduce new interfaces (and a corresponding implementation) to any advised object. For example, you could use an introduction to make a bean implement an IsModified interface, to simplify caching. (An introduction is known as an inter-type declaration in the AspectJ community.)

我不知道如何为一个建议类添加一个新字段,如果你有经验的话,你能举个例子吗


共 (1) 个答案

  1. # 1 楼答案

    演示SpringAOP引入的代码得到了一个很长的答案。希望这有帮助

    考虑以下界面

    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引入的方法和字段