在我的 Spring Boot 應用程式中,我一直在使用一個外部公共庫來處理例外。外部庫有一個方面為相同的東西定義,如下所示:
@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();
}
}
在這里,我想介紹另一個 else 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);
}
}
但是,我不確定這是否是執行此操作的正確方法。任何人都可以在這里提供幫助,了解實作這一目標的最佳方法是什么?謝謝。
uj5u.com熱心網友回復:
您不能使用 擴展具體方面class MyInternalExceptionAspect extends InternalExceptionAspect。它會在 Spring AOP 中引發例外:
...AopConfigException:
[...MyInternalExceptionAspect] cannot extend concrete aspect
[...InternalExceptionAspect]
只有抽象的方面是為了擴展。
但是您可以簡單地創建一個沒有繼承的新方面,并確保它的優先級低于原始方面。
為什么優先級低?
- 根據
@Orderjavadoc,“較低的值具有較高的優先級”。 - 在您有機會處理它之前,您希望您自己的方面的
@AfterReturning建議在原始方面可能將感興趣的例外轉化為其他東西之前就開始發揮作用。但是根據Spring 手冊:“最高優先級的建議首先在“進入”時運行(因此,給定兩條前通知,優先級最高的一條先運行)。從連接點“在退出時”,最高優先級的建議最后運行(因此,給定兩條后建議,具有最高優先級的建議將在其后運行)。” . - 因此,您自己的方面應該具有
@Order(1),給予它比原始方面更低的優先級,但使建議在原始方面@AfterThrowing之前運行。對不起,反向邏輯,即使它是有道理的。你只需要意識到這一點。
這是一個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
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/354133.html
標籤:弹簧靴 例外 奥普 spring-aop
