java - Spring AOP : Declaring additional methods or fields on behalf of a type

标签 java spring spring-aop

在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.)

我不知道如何为建议类添加新字段,如果您有经验,可以举个例子吗?

最佳答案

演示 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引入的接口(interface)及其实现

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

要实现的接口(interface)由注释字段的类型决定。(这里是LoginTracker)

任何匹配类型的 bean 都会实现 LoginTracker 接口(interface)。

现在,当您运行以下测试类时

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

关于java - Spring AOP : Declaring additional methods or fields on behalf of a type,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61541503/

相关文章:

java - Java 中的 k 叉树

java - 数据结构推荐

java - 使用 ANT 生成元模型时出现错误

java - 无法将 MySQL 数据库连接到我的 spring 项目(尽管我已阅读所有帖子)

spring - 如何在 Spring AOP 中获取 HttpServletRequest 和 HttpServletResponse 对象

java - 迁移到 AndroidX -“程序类型已存在 : android. support.v4.media.MediaBrowserCompat

java - NetBeans:将 Spring IOC 添加到基于 maven 的 Swing 应用程序框架项目

java - Spring Boot Swagger 2 配置错误创建名称为 'documentationPluginsBootstrapper' 的 bean

java - SonarQube 无法分析文件 : bridge method not marked as synthetic

java - 为什么 Spring AOP 不在运行时编织外部 jar?