假设您的外部库类/接口位于某个包中,例如org.external.library 或其任何子包中,您可以在AspectJ 语法中将这些类/接口表示为org.external.library..*+。 .. 表示“包含子包”,* 表示“所有类”,+ 表示“包含子类”。现在追加.*(..),您将获得所有方法,无论这些类的名称和参数数量如何。
现在以切入点为例
execution(!static * org.external.library..*+.*(..))
拦截任何库子类中的所有非静态方法,无论返回类型如何。
坏消息是您不能将切入点限制为覆盖方法,因为@Override 注释具有保留类型“源”,即它不能用于方面匹配。但也许您只想将切入点缩小到公共方法,以便排除内部方法引发的错误。这取决于你的情况以及你想如何处理它。假设非覆盖方法也可以破坏基础组件,那么切入点很好。
这是一个自洽的示例:
库类/接口:
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 + "!";
}
}
类扩展/实现库类/接口:
如您所见,出于演示目的,这些类在大约 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