Spring-Retry: 创建类似于@Retryable 的自定义注解
Spring-Retry: Create custom annotation similar to @Retryable
我有很多微服务,如果与数据库的连接失败,它们需要重试机制。
当SQLException 和HibernateException 发生时,必须触发这种重试机制。
在 @Retryable 中传递一个合适的拦截器将起作用,但这必须被纳入所有微服务。
我们可以做一个类似于 @Retryable 的自定义注解,比如 @DatabaseRetryable ,它会在 SQLException 和 HibernateException.
上触发重试
这个注解的用法大致如下
@DatabaseRetryable
void executeQuery()
{
//some code
}
对此有几种方法:
- 使用 spring-retry 项目并将其集成到您的应用程序中。但正如你所说,这不是你想要的。这个框架提供的不仅仅是简单的异常重试,而且比乍看起来要广泛得多。
- 使用 AOP(面向方面编程)模型和库,如 AspectJ
- 创建自定义注释,在 运行 方法之前检查您的 classes 并查看它是否使用 @CustomRetryable 注释,然后 运行 重试方法。然而,这并不是很简单,需要与您的 classes 正确集成。哪个术语取决于您的应用程序的设计方式等。
- 如果您想使其尽可能简单:创建一个帮助程序 class 来为您执行重试。
我的建议是看看你的问题,除了这些重试之外,你是否需要解决方案?然后去图书馆。是否简单 one/two 用例场景然后使用实用程序 class/method 方法。
一个非常粗略的例子可能是 util class:
import java.util.logging.Level;
import java.util.logging.Logger;
public class RetryOperation {
public static void main(String args[]) {
retryOnException(() -> {throw new Exception();} , Exception.class, 4);
}
interface CustomSupplier<T> {
T get() throws Exception;
}
static <E extends Exception, T> T retryOnException(CustomSupplier<T> method, Class<E> exceptionClass, int retries) {
if (method == null) {
throw new IllegalArgumentException("Method may not be null");
}
if (exceptionClass == null) {
throw new IllegalArgumentException("Exception type needs to be provided");
}
int retryCount = 0;
T result = null;
while (retryCount < retries) {
try {
result = method.get();
} catch (Exception exception) {
if (exceptionClass.isAssignableFrom(exception.getClass()) && retryCount < retries) {
// log the exception here
retryCount++;
Logger.getLogger(RetryOperation.class.getName()).log(Level.INFO, String.format("Failed %d time to execute method retrying", retryCount));
} else {
throw exception;
}
}
}
return result;
}
}
请注意,这是一个粗略的示例,应该 仅 功能来解释我背后的想法。看看你到底需要什么,然后从那里设计。
您可以通过使用您想要的名称创建元注释来解决此问题:
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Retryable(
value = { SQLException.class, HibernateException.class }
)
public @interface DatabaseRetryable {
}
您可以使用此元注释作为 @Retryable
的直接替代。同样的约束适用——它只允许在一个地方配置一些常见的行为。您也可以使用它为所有相关服务使用相同的 backOff
。
我有很多微服务,如果与数据库的连接失败,它们需要重试机制。 当SQLException 和HibernateException 发生时,必须触发这种重试机制。 在 @Retryable 中传递一个合适的拦截器将起作用,但这必须被纳入所有微服务。 我们可以做一个类似于 @Retryable 的自定义注解,比如 @DatabaseRetryable ,它会在 SQLException 和 HibernateException.
上触发重试这个注解的用法大致如下
@DatabaseRetryable
void executeQuery()
{
//some code
}
对此有几种方法:
- 使用 spring-retry 项目并将其集成到您的应用程序中。但正如你所说,这不是你想要的。这个框架提供的不仅仅是简单的异常重试,而且比乍看起来要广泛得多。
- 使用 AOP(面向方面编程)模型和库,如 AspectJ
- 创建自定义注释,在 运行 方法之前检查您的 classes 并查看它是否使用 @CustomRetryable 注释,然后 运行 重试方法。然而,这并不是很简单,需要与您的 classes 正确集成。哪个术语取决于您的应用程序的设计方式等。
- 如果您想使其尽可能简单:创建一个帮助程序 class 来为您执行重试。
我的建议是看看你的问题,除了这些重试之外,你是否需要解决方案?然后去图书馆。是否简单 one/two 用例场景然后使用实用程序 class/method 方法。
一个非常粗略的例子可能是 util class:
import java.util.logging.Level;
import java.util.logging.Logger;
public class RetryOperation {
public static void main(String args[]) {
retryOnException(() -> {throw new Exception();} , Exception.class, 4);
}
interface CustomSupplier<T> {
T get() throws Exception;
}
static <E extends Exception, T> T retryOnException(CustomSupplier<T> method, Class<E> exceptionClass, int retries) {
if (method == null) {
throw new IllegalArgumentException("Method may not be null");
}
if (exceptionClass == null) {
throw new IllegalArgumentException("Exception type needs to be provided");
}
int retryCount = 0;
T result = null;
while (retryCount < retries) {
try {
result = method.get();
} catch (Exception exception) {
if (exceptionClass.isAssignableFrom(exception.getClass()) && retryCount < retries) {
// log the exception here
retryCount++;
Logger.getLogger(RetryOperation.class.getName()).log(Level.INFO, String.format("Failed %d time to execute method retrying", retryCount));
} else {
throw exception;
}
}
}
return result;
}
}
请注意,这是一个粗略的示例,应该 仅 功能来解释我背后的想法。看看你到底需要什么,然后从那里设计。
您可以通过使用您想要的名称创建元注释来解决此问题:
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Retryable(
value = { SQLException.class, HibernateException.class }
)
public @interface DatabaseRetryable {
}
您可以使用此元注释作为 @Retryable
的直接替代。同样的约束适用——它只允许在一个地方配置一些常见的行为。您也可以使用它为所有相关服务使用相同的 backOff
。