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

rggaifut  于 2023-03-16  发布在  Spring
关注(0)|答案(2)|浏览(121)

我遇到的情况是我们正在使用的库的实现比我们的依赖项之一的实现更新。例如,依赖项使用MyLibrary-1.0,而我们使用MyLibrary-2.0。
在较新的实现中,一个过时的方法被删除了,这会给我们带来运行时错误。
我尝试使用AOP(具体来说是Spring-AOP)来拦截对缺失方法的调用,并将它们代理到现有方法中......但我似乎无法正确地使用Aspect。
感觉好像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
nvbavucw

nvbavucw1#

假设您正在讨论一个独立于Spring的第三方库,那么您就不能使用SpringAOP及其基于代理的“AOP lite”方法,这种方法只适用于public,Spring组件的非静态方法。请使用更强大的AspectJ。Spring手册解释了如何将完整的AspectJ与加载时编织集成在一起如果您的应用程序到目前为止还没有基于Spring,并且您只是因为SpringAOP而想使用这个框架,那么您可以跳过整个Spring内容,使用普通的AspectJ。
您要使用的特性是类型间声明(inter-type declaration,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);
    }
    */
}

让我们假设我注解掉的方法刚刚从您自己的项目所依赖的最新版本中删除,但是您知道如何重新实现它。

项目依赖性取决于第三方库的旧版本:

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,所以在运行时调用MyDependency.doSomethingWith时将获得NoSuchMethodError

您自己的应用程序:

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来拯救我们!我们只是将缺少的方法添加到第三方库中。

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

好了!好好享受吧。:-)

8nuwlpux

8nuwlpux2#

当JVM加载一个类时,它会在“链接器”阶段解析所有依赖项:外部类、属性和方法。在您的情况下无法通过此阶段,因为缺少方法。
(Spring-)AOP有两种模式:代理和编织。
1.代理创建...一个类周围的代理:目标类必须存在并已加载
1.编织可以在类加载之前发生:当一个类加载器加载一个类时,一个byte[]数组被传递给weaver,weaver可以在类被真正具体化之前操作类的字节码。2这种类型的aop可以在你的情况下工作。3然而,这不是一件容易的事情。

相关问题