代码之家  ›  专栏  ›  技术社区  ›  Almas Abdrazak

用于重试批注的bean后处理程序

  •  0
  • Almas Abdrazak  · 技术社区  · 6 年前

    我有一个Spring3.0版本的遗留项目(我不能使用Spring包中的可检索注释)。 我想实现可重试的注释来注释我的方法,在失败时应该重试执行。

    这是我的课:

    @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)在retry方法中,我希望保留最后一个异常,并在 repeateCount = 0 为此,我需要将空指针声明为 exc 但我希望我所有的领域都是最终的。有没有可能重写我的代码?

    2)在类定义中,我比较 Method 因为原版 equals 方法 Method class 按类比较,我不能这样做,因为原始类被代理替换,是否可以比较两个类 Method's 以不同的方式?

    1 回复  |  直到 6 年前
        1
  •  0
  •   BeUndead    6 年前

    第一部分:一个选项是使用 List Throwables .然后扔给他们,比如:

    final RuntimeException theError = new RuntimeException(list.get(list.size() - 1));
    for (int i = 0; i < list.size() - 1; i++) {
        theError.addSuppressed(list.get(i));
    }
    throw theError;
    

    失败。

    既然您已经在使用Spring,您可以尝试以下组合: AopUtils.getTargetClass AopUtils.getMostSpecificMethod

    一些简单的东西可以提供更多的(注意,不是绝对正确的)测试来测试你已经在运行的东西,但是:

    return methods.stream().anyMatch(mthd -> {
        if (!method.getName().equals(mthd.getName())) {
            return false;
        }
        if (!method.getReturnType().isAssignableFrom(mthd.getReturnType())) {
            return false;
        }
        final Class<?>[] parameterTypes = method.getParameterTypes();
        if (mthd.getParameterTypes().length != parameterTypes.length) {
            return false;
        }
        for (int i = 0; i < parameterTypes.length; i++) {
            if (!parameterTypes[i].equals(mthd.getParameterTypes()[i])) {
                return false;
            }
        }
        return true;
    });
    

    Method.getExceptionTypes() 确认他们 Method.getDeclaringClass() 从那里爬上树; Method.getModifiers() 但这取决于你需要多安全。