将元数据添加到 java throwable 对象
add meta data to java throwable object
在我的应用程序中,我执行一些业务逻辑,例如我有业务逻辑方法:
@Override
@ByPassable(exceptions = {"InvalidIdentityException"})
public void validate(Model model) {
if (nonNull(model)) {
final boolean test = isOk(model.getIdentity());
if (test) {
throw new InvalidIdentityException("Invalid bla bla");
}
}
}
和自定义异常 Class:
public class InvalidIdentityException extends SomeException {
public InvalidIdentityException (final String message) {
super(message);
}
}
方法上的 @ByPassable
获取可以绕过的异常列表,因此在这种情况下 InvalidIdentityException
被抛出,并且在不久的将来重新执行此方法时它会变为 bypassable
。
我为我的 spring 引导应用程序启动一个 bean,它有一组可绕过的异常:
public class Config {
@Bean("bypassable-exceptions")
public Set<String> getBypassableExceptions() {
final Set<String> exceptions = new HashSet<>();
new Reflections(new MethodAnnotationsScanner())
.getMethodsAnnotatedWith(ByPassable.class).stream()
.filter(method -> method.getAnnotation(ByPassable.class).enabled())
.forEach(method -> {
final String[] exceptions = method.getAnnotation(ByPassable.class).exceptions();
exceptions.addAll(Arrays.asList(exceptions));
});
return exceptions;
}
}
每当方法中抛出 Bypassable
异常时,我的应用程序都会将 Throwable
对象作为数据库中的 Json 持久化,但是我需要一个额外的布尔值 属性 bypassable
在这个应该更新的可抛对象上 @BeforeThrowing
异常作为拦截。这可能吗?
public class ExceptionAspect {
@Pointcut("@annotation(com.services.aop.ByPassable)")
public void byPassableExceptionMethods() {
}
@BeforeThrowing(pointcut = "byPassableExceptionMethods()", throwing = "exception")
public void beforeThrowingAdviceForByPassableExceptionMethods(final JoinPoint jp,
final Throwable exception) {
// check against the set of bypassable exceptions and update a custom property on the exception
class so when Throwable is persisted it is persisted with this customer property e.g. bypassable
= true
}
来自 Spring 参考文档:AOP Concepts 没有建议类型 @BeforeThrowing
。
在 Spring AOP 中,可以建议方法执行(连接点)- 在方法开始之前、方法完成之后(有或没有异常)或周围(在方法开始之前和方法完成之后).这也意味着该方法中的逻辑在运行时无法更改,只能操作方法执行的输入或结果。
根据共享的代码逻辑,基于方法内的验证抛出异常,Spring AOP 在抛出异常之前不提供通知句柄。
话虽如此,以下是我能想到的实现相同目标的方法。
- A Bypassable 异常是根据条件引发的,字段
bypassable
可以在异常实例创建时间本身期间设置。这是最简单的方法。
以下是我想出的 Spring AOP 方法。
@AfterThrowing
可以如下设置绕过
@BeforeThrowing
可以模拟。
注意:无法使用 Spring AOP 拦截内部调用。参考文档中的相关信息可以在 section 下找到。
Due to the proxy-based nature of Spring’s AOP framework, calls within
the target object are, by definition, not intercepted.
因此,出于演示目的,示例代码自动装配了自己的参考。 throw exception的方法可以移到另一个bean中,同样拦截。
对示例进行了以下更改。
具有共同基础的可绕过异常 class
public class BaseBypassableException extends RuntimeException {
private boolean bypassable;
public BaseBypassableException(String message) {
super(message);
}
public boolean isBypassable() {
return bypassable;
}
public void setBypassable(boolean bypassable) {
this.bypassable = bypassable;
}
}
可绕过的异常从公共基础延伸class
public class InvalidIdentityException extends BaseBypassableException {
public InvalidIdentityException(String message) {
super(message);
}
}
方法修改如下。 (示例有 String
而不是 Model
)
@Component
public class BypassableServiceImpl implements BypassableService {
@Autowired
BypassableService service;
@Override
@ByPassable(exceptions = {"InvalidIdentityException"})
public void validate(String model) {
if (null != model) {
final boolean test = !("Ok".equals(model));
if (test) {
service.throwException(new InvalidIdentityException("Invalid bla bla"));
}
}
System.out.println("Validate called : "+model);
}
@Override
public void throwException(BaseBypassableException exception) {
throw exception;
}
}
建议这两种方法的方面。 throwing
基于异常类型进行过滤,因此对于示例,我没有包含检查 bypassableExceptionNames
的逻辑,逻辑安全地假定异常的类型为 BaseBypassableException
。如果需要,可以修改逻辑以包括检查。
@Component
@Aspect
public class ExceptionAspect {
@Autowired
@Qualifier("bypassable-exceptions")
Set<String> bypassableExceptionNames;
@Pointcut("@annotation(com.services.aop.ByPassable)")
public void byPassableExceptionMethods() {
}
@AfterThrowing(pointcut = "byPassableExceptionMethods()", throwing = "exception")
public void afterThrowingAdviceForByPassableExceptionMethods(final JoinPoint jp,
final BaseBypassableException exception) {
System.out.println(jp.getSignature());
System.out.println("Before " + exception.isBypassable());
exception.setBypassable(true);
System.out.println("After " + exception.isBypassable());
System.out.println(exception);
}
@Before("execution(* com.services..*.*(..)) && args(exception)")
public void beforeThrowingAdviceForByPassableExceptionMethods(final JoinPoint jp,
final BaseBypassableException exception) {
System.out.println(jp.getSignature());
System.out.println("Before " + exception.isBypassable());
exception.setBypassable(true);
System.out.println("After " + exception.isBypassable());
System.out.println(exception);
}
}
希望对您有所帮助
在我的应用程序中,我执行一些业务逻辑,例如我有业务逻辑方法:
@Override
@ByPassable(exceptions = {"InvalidIdentityException"})
public void validate(Model model) {
if (nonNull(model)) {
final boolean test = isOk(model.getIdentity());
if (test) {
throw new InvalidIdentityException("Invalid bla bla");
}
}
}
和自定义异常 Class:
public class InvalidIdentityException extends SomeException {
public InvalidIdentityException (final String message) {
super(message);
}
}
方法上的 @ByPassable
获取可以绕过的异常列表,因此在这种情况下 InvalidIdentityException
被抛出,并且在不久的将来重新执行此方法时它会变为 bypassable
。
我为我的 spring 引导应用程序启动一个 bean,它有一组可绕过的异常:
public class Config {
@Bean("bypassable-exceptions")
public Set<String> getBypassableExceptions() {
final Set<String> exceptions = new HashSet<>();
new Reflections(new MethodAnnotationsScanner())
.getMethodsAnnotatedWith(ByPassable.class).stream()
.filter(method -> method.getAnnotation(ByPassable.class).enabled())
.forEach(method -> {
final String[] exceptions = method.getAnnotation(ByPassable.class).exceptions();
exceptions.addAll(Arrays.asList(exceptions));
});
return exceptions;
}
}
每当方法中抛出 Bypassable
异常时,我的应用程序都会将 Throwable
对象作为数据库中的 Json 持久化,但是我需要一个额外的布尔值 属性 bypassable
在这个应该更新的可抛对象上 @BeforeThrowing
异常作为拦截。这可能吗?
public class ExceptionAspect {
@Pointcut("@annotation(com.services.aop.ByPassable)")
public void byPassableExceptionMethods() {
}
@BeforeThrowing(pointcut = "byPassableExceptionMethods()", throwing = "exception")
public void beforeThrowingAdviceForByPassableExceptionMethods(final JoinPoint jp,
final Throwable exception) {
// check against the set of bypassable exceptions and update a custom property on the exception
class so when Throwable is persisted it is persisted with this customer property e.g. bypassable
= true
}
来自 Spring 参考文档:AOP Concepts 没有建议类型 @BeforeThrowing
。
在 Spring AOP 中,可以建议方法执行(连接点)- 在方法开始之前、方法完成之后(有或没有异常)或周围(在方法开始之前和方法完成之后).这也意味着该方法中的逻辑在运行时无法更改,只能操作方法执行的输入或结果。
根据共享的代码逻辑,基于方法内的验证抛出异常,Spring AOP 在抛出异常之前不提供通知句柄。
话虽如此,以下是我能想到的实现相同目标的方法。
- A Bypassable 异常是根据条件引发的,字段
bypassable
可以在异常实例创建时间本身期间设置。这是最简单的方法。
以下是我想出的 Spring AOP 方法。
@AfterThrowing
可以如下设置绕过@BeforeThrowing
可以模拟。
注意:无法使用 Spring AOP 拦截内部调用。参考文档中的相关信息可以在 section 下找到。
Due to the proxy-based nature of Spring’s AOP framework, calls within the target object are, by definition, not intercepted.
因此,出于演示目的,示例代码自动装配了自己的参考。 throw exception的方法可以移到另一个bean中,同样拦截。
对示例进行了以下更改。
具有共同基础的可绕过异常 class
public class BaseBypassableException extends RuntimeException {
private boolean bypassable;
public BaseBypassableException(String message) {
super(message);
}
public boolean isBypassable() {
return bypassable;
}
public void setBypassable(boolean bypassable) {
this.bypassable = bypassable;
}
}
可绕过的异常从公共基础延伸class
public class InvalidIdentityException extends BaseBypassableException {
public InvalidIdentityException(String message) {
super(message);
}
}
方法修改如下。 (示例有 String
而不是 Model
)
@Component
public class BypassableServiceImpl implements BypassableService {
@Autowired
BypassableService service;
@Override
@ByPassable(exceptions = {"InvalidIdentityException"})
public void validate(String model) {
if (null != model) {
final boolean test = !("Ok".equals(model));
if (test) {
service.throwException(new InvalidIdentityException("Invalid bla bla"));
}
}
System.out.println("Validate called : "+model);
}
@Override
public void throwException(BaseBypassableException exception) {
throw exception;
}
}
建议这两种方法的方面。 throwing
基于异常类型进行过滤,因此对于示例,我没有包含检查 bypassableExceptionNames
的逻辑,逻辑安全地假定异常的类型为 BaseBypassableException
。如果需要,可以修改逻辑以包括检查。
@Component
@Aspect
public class ExceptionAspect {
@Autowired
@Qualifier("bypassable-exceptions")
Set<String> bypassableExceptionNames;
@Pointcut("@annotation(com.services.aop.ByPassable)")
public void byPassableExceptionMethods() {
}
@AfterThrowing(pointcut = "byPassableExceptionMethods()", throwing = "exception")
public void afterThrowingAdviceForByPassableExceptionMethods(final JoinPoint jp,
final BaseBypassableException exception) {
System.out.println(jp.getSignature());
System.out.println("Before " + exception.isBypassable());
exception.setBypassable(true);
System.out.println("After " + exception.isBypassable());
System.out.println(exception);
}
@Before("execution(* com.services..*.*(..)) && args(exception)")
public void beforeThrowingAdviceForByPassableExceptionMethods(final JoinPoint jp,
final BaseBypassableException exception) {
System.out.println(jp.getSignature());
System.out.println("Before " + exception.isBypassable());
exception.setBypassable(true);
System.out.println("After " + exception.isBypassable());
System.out.println(exception);
}
}
希望对您有所帮助