aop - AspectJ 可以将第三方库代码中的 "new X"替换为 "new SubclassOfX"吗?

标签 aop aspectj

我正在查看 AspectJ,看看我们是否可以在我们的测试套件中使用它。

我们有一个相当大的第三方 Java 通信库,硬连线使用它自己的类(不实现任何接口(interface)),这反过来意味着我们需要一个物理后端并正确配置才能运行测试。

我正在研究我们取消此限制的选项。一种可能性是创建麻烦类的子类,然后在加载第三方库时要求 AspectJ 简单地将“new X”替换为“new OurSubclassOfX”,但我是 AspectJ 的新手,并且从我对文档的简短浏览来看不是典型的用例。

AspectJ 可以做到这一点吗?配置片段是什么?

最佳答案

是的,这是可能的。让我们假设您有一个硬连线的类,可能从数据库中获取一些东西,并希望通过一个方面来模拟它:

package de.scrum_master.aop.app;

public class HardWired {
    private int id;
    private String name;

    public HardWired(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public void doSomething() {
        System.out.println("Fetching values from database");
    }

    public int getSomething() {
        return 11;
    }

    @Override
    public String toString() {
        return "HardWired [id=" + id + ", name=" + name + "]";
    }
}

然后有一个小驱动应用程序使用那个类(不是接口(interface)):

package de.scrum_master.aop.app;

public class Application {
    public static void main(String[] args) {
        HardWired hw = new HardWired(999, "My object");
        System.out.println(hw);
        hw.doSomething();
        System.out.println(hw.getSomething());
    }
}

输出如下:

HardWired [id=999, name=My object]
Fetching values from database
11

现在你定义你的派生模拟类,它应该替换原来的用于测试目的:

package de.scrum_master.aop.mock;

import de.scrum_master.aop.app.HardWired;

public class HardWiredMock extends HardWired {
    public HardWiredMock(int id, String name) {
        super(id, name);
    }

    @Override
    public void doSomething() {
        System.out.println("Mocking database values");
    }

    @Override
    public int getSomething() {
        return 22;
    }

    @Override
    public String toString() {
        return "Mocked: " + super.toString();
    }
}

最后,您使用简单的切入点和建议定义了一个方面,以在每次构造函数调用期间替换原始值:

package de.scrum_master.aop.aspect;

import de.scrum_master.aop.app.HardWired;
import de.scrum_master.aop.mock.HardWiredMock;


public aspect MockInjector {
    HardWired around(int p1, String p2) : call(HardWired.new(int, String)) && args(p1, p2) {
        return new HardWiredMock(p1, p2);
    }
}

输出根据需要更改:

Mocked: HardWired [id=999, name=My object]
Mocking database values
22

您对每个类和构造函数执行一次,就可以了。为了概括该方法,您需要连接点属性,并且取决于您想要走多远,也许是反射,但这在这里非常简单。享受!

关于aop - AspectJ 可以将第三方库代码中的 "new X"替换为 "new SubclassOfX"吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16355771/

相关文章:

spring - 从 ProceedingJoinPoint 获取 java.lang.reflect.Method?

.net-core - .NET Core 默认依赖注入(inject)与 CaSTLe DynamicProxy

ruby-on-rails - 使用面向方面的编程进行Rails异常处理

java - 如何从现有动态代理获取 'proxied'对象

java - 在一个项目中使用Aspectj编译时编织和Java编译时注释处理

java - 通过AOP拦截重载方法

java - Grails 的 AOP

php - PHP的AOP实现

java - 如何让 Aspect 触发带注释的函数?

java - 如何从 ProceedingJoinPoint 获取类级别注释