扩展异常方面以便实现特定于应用程序的实现



在我的春季启动应用程序中,我一直在使用一个外部公共库来处理异常。外部库有一个相同的方面定义如下:

@Aspect
@Order(0)
public class InternalExceptionAspect {
public InternalExceptionAspect() {
}
@Pointcut("@within(org.springframework.stereotype.Service)")
public void applicationServicePointcut() {
}
@AfterThrowing(
pointcut = "applicationServicePointcut()",
throwing = "e"
)
public void translate(JoinPoint joinPoint, Throwable e) {
String resourceId = this.getResourceId();
if (e instanceof BadInputException) {
BadInputException inputException = (BadInputException)e;
throw new BadRequestAlertException(inputException.getErrorCode().getDefaultMessage(), inputException.getMessage(), inputException.getErrorCode().getHttpStatusCode(), resourceId, inputException.getErrorCode().getCode());
} else if (!(e instanceof BadServerStateException) && !(e instanceof InternalException)) {
String message;
if (e instanceof JDBCException) {
...
throw new BadServerStateException(message, resourceId, "20");
} else {
...
throw new BadServerStateException(message, resourceId, "10");
}
} else {
InternalException serverStateException = (InternalException)e;
throw new BadServerStateException(serverStateException.getErrorCode().getDefaultMessage(), serverStateException.getMessage(), resourceId, serverStateException.getErrorCode().getHttpStatusCode(), serverStateException.getErrorCode().getCode(), serverStateException.getErrorCode().getErrorType().name());
}
}
String getResourceId() {
RequestHeaders requestHeaders = RequestResponseContext.getRequestHeaders();
return requestHeaders.getResourceId();
}
}

在这里,我想介绍另一个if块,以便为我的应用程序处理DuplicateKeyException

问题是,作为公共库的一部分,上述代码正被多个其他应用程序使用。但是,我只想在我的申请中进行更改。

我一直在考虑在我的应用程序中继承Aspect类,如下所示:

@Aspect
@Order(0)
public class MyInternalExceptionAspect extends InternalExceptionAspect {
public MyInternalExceptionAspect() {
}
@Pointcut("@within(org.springframework.stereotype.Service)")
public void applicationServicePointcut() {
}
@AfterThrowing(
pointcut = "applicationServicePointcut()",
throwing = "e"
)
public void translate(JoinPoint joinPoint, Throwable e) { 
if(e instanceof DuplicateKeyException) {
...
}
super.translate(joinpoint, e);
}
}

但是,我不确定这样做是否正确。请有人在这里帮忙,了解实现这一目标的最佳方法是什么?谢谢

不能使用class MyInternalExceptionAspect extends InternalExceptionAspect扩展具体方面。它将在Spring AOP中引发异常:

...AopConfigException:
[...MyInternalExceptionAspect] cannot extend concrete aspect
[...InternalExceptionAspect]

只有抽象的方面才能被扩展。

但是,您可以简单地创建一个没有继承的新方面,并确保它的优先级低于原始方面。

为什么优先级较低?

  • 根据@Orderjavadoc;较低的值具有较高的优先级">
  • 您希望您自己方面的@AfterReturning建议在之前启动,在您有机会处理之前,原始方面可能会将感兴趣的异常转换为其他内容。但根据Spring手册:"最高优先级的建议首先运行";在";(因此,给出两条之前的建议,优先级最高的先运行("在离开的路上;从一个连接点开始,优先级最高的建议运行在最后(因此,给定两条after建议,具有最高优先级的建议将运行在第二条(">
  • 因此,您自己的方面应该有@Order(1),使其优先级低于原始方面,但使@AfterThrowingadvide在原始方面之前运行。很抱歉出现了相反的逻辑,尽管这是有道理的。你只需要意识到这一点

这是一个MCVE,以简化的方式模拟您的情况:

package de.scrum_master.spring.q69862121;
import org.springframework.stereotype.Service;
@Service
public class MyService {
public void doSomething(Throwable throwable) throws Throwable {
if (throwable != null)
throw throwable;
}
}
package de.scrum_master.spring.q69862121;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
@SpringBootApplication
@Configuration
public class DemoApplication {
private static final Logger log = LoggerFactory.getLogger(DemoApplication.class.getName());
public static void main(String[] args) throws Throwable {
try (ConfigurableApplicationContext appContext = SpringApplication.run(DemoApplication.class, args)) {
doStuff(appContext);
}
}
private static void doStuff(ConfigurableApplicationContext appContext) {
MyService myService = appContext.getBean(MyService.class);
List<Throwable> throwables = Arrays.asList(
null,                                   // No exception -> no aspect should kick in
new Exception("oops"),                  // Not covered by any aspects -> no translation
new IllegalArgumentException("uh-oh"),  // Original aspect translates to RuntimeException
new NullPointerException("null"),       // Custom aspect translates to RuntimeException
new ArithmeticException("argh")         // Custom aspect translates to IllegalArgumentException,
// then original aspect translates to RuntimeException
);
for (Throwable originalThrowable : throwables) {
try {
myService.doSomething(originalThrowable);
}
catch (Throwable translatedThrowable) {
log.info(translatedThrowable.toString());
}
}
}
}

正如您所看到的,应用程序调用服务,第一次使用null,没有引起任何异常,然后使用几种类型的异常,这些方面将被忽略或转换。

package de.scrum_master.spring.q69862121;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Aspect
@Component
@Order(0)
public class InternalExceptionAspect {
private static final Logger log = LoggerFactory.getLogger(InternalExceptionAspect.class.getName());
@AfterThrowing(pointcut = "@within(org.springframework.stereotype.Service)", throwing = "e")
public void translate(JoinPoint joinPoint, Throwable e) {
log.info(joinPoint + "  -> " + e);
if (e instanceof IllegalArgumentException)
throw new RuntimeException("Transformed by InternalExceptionAspect", e);
}
}
package de.scrum_master.spring.q69862121;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Aspect
@Component
@Order(1)
public class MyInternalExceptionAspect {
private static final Logger log = LoggerFactory.getLogger(MyInternalExceptionAspect.class.getName());
@AfterThrowing(pointcut = "@within(org.springframework.stereotype.Service)", throwing = "e")
public void translate(JoinPoint joinPoint, Throwable e) {
log.info(joinPoint + "  -> " + e);
if (e instanceof NullPointerException)
throw new RuntimeException("Transformed by MyInternalExceptionAspect", e);
if (e instanceof ArithmeticException)
throw new IllegalArgumentException("Transformed by MyInternalExceptionAspect", e);
}
}

控制台日志证明一切都如预期一样工作,也与调用顺序有关:

d.s.s.q.MyInternalExceptionAspect        : execution(void de.scrum_master.spring.q69862121.MyService.doSomething(Throwable))  -> java.lang.Exception: oops
d.s.s.q69862121.InternalExceptionAspect  : execution(void de.scrum_master.spring.q69862121.MyService.doSomething(Throwable))  -> java.lang.Exception: oops
d.s.spring.q69862121.DemoApplication     : java.lang.Exception: oops
d.s.s.q.MyInternalExceptionAspect        : execution(void de.scrum_master.spring.q69862121.MyService.doSomething(Throwable))  -> java.lang.IllegalArgumentException: uh-oh
d.s.s.q69862121.InternalExceptionAspect  : execution(void de.scrum_master.spring.q69862121.MyService.doSomething(Throwable))  -> java.lang.IllegalArgumentException: uh-oh
d.s.spring.q69862121.DemoApplication     : java.lang.RuntimeException: Transformed by InternalExceptionAspect
d.s.s.q.MyInternalExceptionAspect        : execution(void de.scrum_master.spring.q69862121.MyService.doSomething(Throwable))  -> java.lang.NullPointerException: null
d.s.s.q69862121.InternalExceptionAspect  : execution(void de.scrum_master.spring.q69862121.MyService.doSomething(Throwable))  -> java.lang.RuntimeException: Transformed by MyInternalExceptionAspect
d.s.spring.q69862121.DemoApplication     : java.lang.RuntimeException: Transformed by MyInternalExceptionAspect
d.s.s.q.MyInternalExceptionAspect        : execution(void de.scrum_master.spring.q69862121.MyService.doSomething(Throwable))  -> java.lang.ArithmeticException: argh
d.s.s.q69862121.InternalExceptionAspect  : execution(void de.scrum_master.spring.q69862121.MyService.doSomething(Throwable))  -> java.lang.IllegalArgumentException: Transformed by MyInternalExceptionAspect
d.s.spring.q69862121.DemoApplication     : java.lang.RuntimeException: Transformed by InternalExceptionAspect

最新更新