通过AOP定义一个缺失的方法?

问题描述 投票:0回答:2

我所处的情况是,我们正在使用的库的实现比我们的依赖项之一的实现更新。例如。依赖项使用 MyLibrary-1.0,我们使用 MyLibrary-2.0.

在较新的实现中,一个不推荐使用的方法已被删除,这会给我们带来运行时错误。

我正在尝试使用 AOP(具体来说是 Spring-AOP)来拦截对缺失方法的调用,并将它们代理到现有方法中……但我似乎无法获得正确的方面。

感觉 Java 在我的方面有机会拦截之前引发了“java.lang.NoSuchMethodError”异常。有没有我遗漏的技巧,或者这是不可行的(例如,该方法必须存在才能实现它)?

@Before("execution(* com.mylibrary.SomeClass.*(..))") 
     Fails with java.lang.NoSuchMethodError

@Around("target(com.mylibrary.SomeClass) && execution(* missingMethod(..))")
     Fails with java.lang.NoSuchMethodError
spring aop spring-aop
2个回答
2
投票

假设您正在谈论独立于 Spring 的第 3 方库,您不能将 Spring AOP 与其基于代理的“AOP lite”方法一起使用,该方法仅适用于 Spring 组件的公共非静态方法。请改用更强大的 AspectJ。 Spring 手册 解释了如何将带有加载时编织 (LTW) 的完整 AspectJ 集成到 Spring 应用程序中。如果你的应用程序到目前为止还没有基于 Spring,而你只是想使用 Spring AOP 的框架,你可以完全跳过整个 Spring 的东西,使用普通的 AspectJ。

您要使用的功能是类型间声明 (ITD),更具体地说是 AspectJ 为现有类声明方法的能力。这是一些示例代码:

第三方库:

package org.library;

public class Utility {
    public String toHex(int number) {
        return Integer.toHexString(number);
    }

    // Let us assume that this method was removed from the new library version
    /*
    @Deprecated
    public String toOct(int number) {
        return Integer.toOctalString(number);
    }
    */
}

假设我注释掉的方法只是从你自己的项目依赖的最新版本中删除,但你知道如何重新实现它。

项目依赖依赖于旧版本的 3rd 方库:

package com.dependency;

import org.library.Utility;

public class MyDependency {
    public void doSomethingWith(int number) {
        System.out.println(number + " in octal = " + new Utility().toOct(number));
    }
}

因为之前弃用的方法

Utility.toOct
在你自己的项目使用的版本中已经不存在了,你会在运行时调用
NoSuchMethodError
时得到
MyDependency.doSomethingWith

您自己的申请:

package de.scrum_master.app;

import org.library.Utility;

import com.dependency.MyDependency;

public class Application {
    public static void main(String[] args) {
        System.out.println("3333 in hexadecimal = " + new Utility().toHex(3333));
        new MyDependency().doSomethingWith(987);
    }
}

如您所见,该应用程序也使用相同的库,但当前版本中仍然存在不同的方法。不幸的是,它还使用依赖于已删除方法的存在的依赖项。那么我们应该如何修复呢?

使用 ITD 的方面:

AspectJ 来拯救!我们只是将缺少的方法添加到 3rd 方库中。

package de.scrum_master.aspect;

import org.library.Utility;

public aspect DeprecatedMethodProvider {
    public String Utility.toOct(int number) {
        return Integer.toOctalString(number);
    }
}

如果您使用 AspectJ 编译器 Ajc 编译这个项目,它就可以正常工作。在您的实际场景中,将方面编译成自己的方面库,将编织代理aspectjweaver.jar 放在 JVM 命令行上以激活 LTW 并享受它如何通过字节码检测将方法编织到库类中类加载。

日志输出:

3333 in hexadecimal = d05
987 in octal = 1733

瞧瞧!享受。

:-)


1
投票

当 JVM 加载一个类时,它会在“链接器”阶段解析所有依赖项:外部类、属性和方法。你不能在你的案例中通过这个阶段,因为缺少方法。

(Spring-)AOP有两种模式:代理和编织。

  1. 代理创建...一个类的代理:目标类必须存在并被加载
  2. 编织可以发生在一个类被加载之前:当一个类加载器加载一个类时,一个byte[]数组被传递给编织器,它可以在类真正具体化之前操作类字节码。这种类型的 aop can 适用于您的情况。然而,这不是一件容易的事。
© www.soinside.com 2019 - 2024. All rights reserved.