gpt4 book ai didi

java - AOP围绕外部库的重写方法?

转载 作者:塔克拉玛干 更新时间:2023-11-02 07:45:24 26 4
gpt4 key购买 nike

我正在为以下问题寻找实用的解决方案:

  • 外部库提供组件作为基类。
  • 自定义组件是通过扩展这些基类制作的。
  • 当实现抛出未处理的异常时,基类中断。
  • 基类源代码不可用。只有一个二进制 jar。

我正在寻找的是有一个通用的 AOP 错误处理建议。它将包装每个方法的代码,这些方法是外部库中方法的直接覆盖或实现。基本上执行 try/catch 以进行错误恢复。

我当然可以手动搜索它们。然而,我们的代码库是广泛的。覆盖外部库类方法的可能性也是如此。因此考虑 AOP 来帮助我。

加载时编织被排除在外,因为它涉及到一个网络应用程序。可能无法使用应用程序服务器添加 JVM 代理程序。所以一定是编译时编织。

有人知道如何用 AspectJ 做到这一点吗?

最佳答案

假设您的外部库类/接口(interface)位于某个包中,例如 org.external.library 或其任何子包中,您可以用 AspectJ 语法将这些类/接口(interface)表示为 org.external.library..*+. .. 表示“包含子包”,* 表示“所有类”,+ 表示“包含子类”。现在附加 .*(..),您将获得所有方法,而不管这些类的名称和参数数量。

现在以切入点为例

execution(!static * org.external.library..*+.*(..))

无论返回类型如何,拦截任何库子类中的所有非静态方法。

坏消息是您不能将切入点限制为覆盖方法,因为 @Override 注释具有保留类型“source”,即它不可用于方面匹配。但也许您只想将切入点缩小到公共(public)方法,以便排除内部方法抛出的错误。这取决于您的情况以及您想如何处理它。假设非重写方法也可以破坏基础组件,不过切入点很好。

这是一个自洽的样本:

库类/接口(interface):

package org.external.library;

public abstract class AbstractBase {
public abstract String getText();
public abstract int getNumber();
public abstract void doSomething();
}
package org.external.library;

public interface Service {
void start();
void stop();
boolean isRunning();
}

扩展任何库类的类:

如您所见,出于演示目的,此类在约 50% 的所有情况下随机抛出运行时异常。我们希望它们由我们的方面处理。

package de.scrum_master.app;

import java.util.Random;

public class MyOwnClass {
private static final Random RANDOM = new Random();

public String getGreeting(String recipient) {
if (RANDOM.nextBoolean())
throw new RuntimeException("cannot get greeting for '" + recipient + "'");
return "Hello " + recipient + "!";
}
}

扩展/实现库类/接口(interface)的类:

如您所见,出于演示目的,这些类在大约 50% 的情况下还会随机抛出运行时异常。我们希望它们由我们的方面处理。

main 方法通过多次调用每个方法来演示整个设置,不处理重写库类中的任何错误,而只处理我们自己的类中的错误。

package de.scrum_master.app;

import java.util.Random;

import org.external.library.Service;

public class FooService implements Service {
private static final Random RANDOM = new Random();
private boolean isRunning;

@Override
public void start() {
if (RANDOM.nextBoolean())
throw new RuntimeException("cannot start");
isRunning = true;
}

@Override
public void stop() {
if (RANDOM.nextBoolean())
throw new RuntimeException("cannot stop");
isRunning = false;
}

@Override
public boolean isRunning() {
return isRunning;
}

public void pause() {
if (RANDOM.nextBoolean())
throw new RuntimeException("cannot pause");
isRunning = false;
}

public void resume() {
if (RANDOM.nextBoolean())
throw new RuntimeException("cannot resume");
isRunning = true;
}
}
package de.scrum_master.app;

import java.util.Random;

import org.external.library.AbstractBase;

public class Application extends AbstractBase {
private static final Random RANDOM = new Random();

@Override
public String getText() {
if (RANDOM.nextBoolean())
throw new RuntimeException("cannot get text");
return "Hello world!";
}

@Override
public int getNumber() {
if (RANDOM.nextBoolean())
throw new RuntimeException("cannot get number");
return RANDOM.nextInt(10);
}

@Override
public void doSomething() {
if (RANDOM.nextBoolean())
throw new RuntimeException("cannot do something");
}

public void doSomethingElse() {
if (RANDOM.nextBoolean())
throw new RuntimeException("cannot do something else");
}

public static void main(String[] args) {
Application application = new Application();
FooService fooService = new FooService();
MyOwnClass myOwnClass = new MyOwnClass();
for (int i = 0; i < 5; i++) {
application.getText();
application.getNumber();
application.doSomething();
application.doSomethingElse();
fooService.start();
fooService.pause();
fooService.isRunning();
fooService.resume();
fooService.isRunning();
fooService.stop();
try {
myOwnClass.getGreeting("world");
myOwnClass.getGreeting("guys");
}
catch (Exception e) {
System.out.println("Uncaught by aspect: " + e);
}
}
}
}

错误处理方面:

package de.scrum_master.aspect;

public aspect ErrorHandler {
Object around() : execution(!static * org.external.library..*+.*(..)) {
try {
return proceed();
}
catch (Exception e) {
System.out.println(thisJoinPoint + " -> " + e);
return null;
}
}
}

控制台输出:

由于代码中的随机化,每次运行应用程序时输出看起来都有些不同:

execution(int de.scrum_master.app.Application.getNumber()) -> java.lang.RuntimeException: cannot get number
execution(void de.scrum_master.app.Application.doSomething()) -> java.lang.RuntimeException: cannot do something
execution(void de.scrum_master.app.Application.doSomethingElse()) -> java.lang.RuntimeException: cannot do something else
execution(void de.scrum_master.app.FooService.start()) -> java.lang.RuntimeException: cannot start
execution(void de.scrum_master.app.FooService.pause()) -> java.lang.RuntimeException: cannot pause
execution(void de.scrum_master.app.FooService.resume()) -> java.lang.RuntimeException: cannot resume
execution(void de.scrum_master.app.FooService.stop()) -> java.lang.RuntimeException: cannot stop
Uncaught by aspect: java.lang.RuntimeException: cannot get greeting for 'world'
execution(String de.scrum_master.app.Application.getText()) -> java.lang.RuntimeException: cannot get text
execution(int de.scrum_master.app.Application.getNumber()) -> java.lang.RuntimeException: cannot get number
execution(void de.scrum_master.app.Application.doSomething()) -> java.lang.RuntimeException: cannot do something
execution(void de.scrum_master.app.FooService.start()) -> java.lang.RuntimeException: cannot start
execution(void de.scrum_master.app.FooService.pause()) -> java.lang.RuntimeException: cannot pause
execution(void de.scrum_master.app.FooService.stop()) -> java.lang.RuntimeException: cannot stop
Uncaught by aspect: java.lang.RuntimeException: cannot get greeting for 'guys'
execution(void de.scrum_master.app.Application.doSomething()) -> java.lang.RuntimeException: cannot do something
execution(void de.scrum_master.app.FooService.start()) -> java.lang.RuntimeException: cannot start
execution(void de.scrum_master.app.FooService.pause()) -> java.lang.RuntimeException: cannot pause
Uncaught by aspect: java.lang.RuntimeException: cannot get greeting for 'guys'
execution(void de.scrum_master.app.Application.doSomethingElse()) -> java.lang.RuntimeException: cannot do something else
execution(void de.scrum_master.app.FooService.resume()) -> java.lang.RuntimeException: cannot resume
execution(void de.scrum_master.app.FooService.stop()) -> java.lang.RuntimeException: cannot stop
Uncaught by aspect: java.lang.RuntimeException: cannot get greeting for 'world'
execution(String de.scrum_master.app.Application.getText()) -> java.lang.RuntimeException: cannot get text
execution(int de.scrum_master.app.Application.getNumber()) -> java.lang.RuntimeException: cannot get number
execution(void de.scrum_master.app.Application.doSomething()) -> java.lang.RuntimeException: cannot do something
execution(void de.scrum_master.app.Application.doSomethingElse()) -> java.lang.RuntimeException: cannot do something else
execution(void de.scrum_master.app.FooService.start()) -> java.lang.RuntimeException: cannot start
execution(void de.scrum_master.app.FooService.pause()) -> java.lang.RuntimeException: cannot pause
execution(void de.scrum_master.app.FooService.stop()) -> java.lang.RuntimeException: cannot stop

关于java - AOP围绕外部库的重写方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27943872/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com