У меня есть устаревший проект с версией Spring 3.0 (я не могу использовать аннотацию Retriable из пакета Spring).Я хочу внедрить аннотацию Retryable, чтобы аннотировать мои методы, выполнение которых следует повторить при неудаче.
Это мой класс:
@Component
public final class RetryBpp implements BeanPostProcessor {
private final ConcurrentMap<String, ClassDefinition> map = new ConcurrentHashMap<>();
@Override
public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
final Class<?> asClass = bean.getClass();
final Method[] methods = asClass.getMethods();
final List<Method> collect = Stream.of(methods)
.filter(method -> method.isAnnotationPresent(Repitable.class))
.collect(Collectors.toList());
if(!collect.isEmpty()){
this.map.put(beanName,new ClassDefinition(collect,asClass));
}
return bean;
}
@Override
public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
final ClassDefinition definition = this.map.get(beanName);
if(definition != null){
final Class beanClass = definition.asClass;
return Proxy.newProxyInstance(beanClass.getClassLoader(), beanClass.getInterfaces(), (proxy, method, args) -> {
if(definition.isMethodPresent(method)){
System.out.println("Present");
return this.retry(definition.originalMethod(method),bean,args);
} else{
return method.invoke(bean,args);
}
});
} else{
return bean;
}
}
private Object retry(final Method method,final Object originalBean,Object[] argc){
final Repitable repitable = method.getAnnotation(Repitable.class);
int attempts = repitable.attempts();
Throwable exc = null;
while(attempts!=0){
try{
return method.invoke(originalBean,argc);
}catch (final Throwable throwable){
exc = throwable;
attempts--;
this.sleep(repitable.delay(),repitable.timeUnit());
}
}
throw new RuntimeException(exc);
}
@SneakyThrows(InterruptedException.class)
private void sleep(final int time, final TimeUnit timeUnit){
timeUnit.sleep(time);
}
@AllArgsConstructor
private static final class ClassDefinition{
private final List<Method> methods;
private final Class asClass;
boolean isMethodPresent(final Method method){
return this.methods.stream().anyMatch(mthd->mthd.getName().equals(method.getName()));
}
Method originalMethod(final Method method){
return this.methods.stream().filter(mthd->mthd.getName().equals(method.getName())).findFirst().orElseThrow(NullPointerException::new);
}
}
}
И это работает, но я хочу изменить две вещи
1) В методе повтора я хочу сохранить последнее исключение и выдать, когда repeateCount = 0
, для этого мне нужно объявить null ptr в exc
, но я хочу, чтобы все мои поля были окончательными.Можно ли как-то переписать мой код?
2) В ClassDefinition я сравниваю Method
по имени, потому что оригинальный equals
метод Method class
сравнивает по классу, я не могу сделать это, потому что оригинальный классзаменены на прокси, можно ли сравнить два Method's
по-разному?