Невозможно ввести по классификатору - PullRequest
0 голосов
/ 12 июня 2018

У меня есть пользовательская аннотация с именем Retry со следующим постпроцессором бина:

@Component
public final class RetryBPP implements BeanPostProcessor {

    private final Map<String, ClassDefinition> map = new HashMap<>(40);

    @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(Retriable.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.baseCLass;
            return Proxy.newProxyInstance(beanClass.getClassLoader(), beanClass.getInterfaces(), (proxy, method, args) -> {
                if(definition.isMethodPresent(method)){
                    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 Retriable retriable = method.getAnnotation(Retriable.class);
        int attempts = retriable.attempts();
        while(true){
            try{
                return method.invoke(originalBean,argc);
            }catch (final Exception throwable){
                if(this.support(retriable.exceptions(),throwable.getClass()) && attempts != 0){
                    attempts--;
                    log.warn("Error on method {} wait to repeat",method.getName());
                    this.sleep(retriable.delay(),retriable.timeUnit());
                } else{
                    throw new RuntimeException(throwable);
                }
            }
        }
    }

    @SneakyThrows(InterruptedException.class)
    private void sleep(final long time, final TimeUnit timeUnit){
        timeUnit.sleep(time);
    }

    private boolean support(final Class<? extends Exception>[] exceptions,Class<? extends Exception> exception){
        boolean support = false;
        for (Class _class : exceptions) {
            if(_class.equals(exception)){
                support = true;
                break;
            }
        }
        return support;
    }

    @AllArgsConstructor
    private static final class ClassDefinition{
        final List<Method> methods;
        final Class baseCLass;

        boolean isMethodPresent(final Method method){
            return this.methods.stream()
                               .anyMatch(mthd->methodEquals(mthd,method));
        }

        Method originalMethod(final Method method){
            return this.methods.stream()
                               .filter(mthd->methodEquals(mthd,method))
                               .findFirst().orElseThrow(NullPointerException::new);

        }

    }

}

Интерфейс:

public interface Inter {

    String qqq(String url);

}

Абстрактный класс:

public abstract class Abs implements Inter {

    @Override
    @Retry
    public String qqq(final String url) {
        someLogic(url);
    }

  protected String someLogic(String str);

Пользовательская аннотация квалификатора:

@Retention(RetentionPolicy.RUNTIME)
@Qualifier
@Target({ElementType.CONSTRUCTOR, ElementType.TYPE, ElementType.PARAMETER, ElementType.FIELD})
public @interface Qualif {

    VV.v type();

}

И реализация:

@Service
@Qualif(type = First)
@Slf4j
public final class Impl extends Abs {

   @Override
   protected String someLogic(String str){...}
}

И когда я автоматически подключаюсь по классификатору, как это:

@Autowired
@Qualif(type = First)
Inter inter;

Исключение броска пружины No qualifying bean of type [com.devadmin.downloader.sites.VideoDownloader] found for dependency Inter:, но когдаЯ удаляю аннотацию @Retry из класса abctract, все работает круто.Как решить эту проблему.

Кстати, я проверил, что мой класс, который расширяет класс Abstract внутри ApplicationContext, но Spring не увидел мой пользовательский квалификатор

1 Ответ

0 голосов
/ 13 июня 2018

Наконец-то я нашел ответ.Для тех, кто не понимает проблему.

У меня есть интерфейс с методом foo() абстрактный класс, который реализует этот интерфейс и добавляет новый абстрактный метод, такой как

abstract class FooAbs impl Inter{
   @Override 
   void foo(){
      childMethod();
    }
   protected void childMethod();
}

И, наконец, у меня есть классс @Component, расширяющим абстрактный класс.

@Component 
class Trst extends FooAbs{

  @Override
  void childMethod(){}
}

Проблема была с динамическим прокси.

Этот код снизу

Proxy.newProxyInstance(beanClass.getClassLoader(), beanClass.getInterfaces(), (proxy, method, args) -> {}

Динамический прокси не видит getInterfaces поэтому я изменяю свою подпись класса следующим образом:

@Component 
    class Trst extends FooAbs implement Inter{

      @Override
      void childMethod(){}
    }

После этого шага

beanClass.getInterfaces()

см. Интерфейс.Я знаю, что это обходное решение, и я перепишу свой код, чтобы избежать такой структуры.Но это работает и, возможно, кому-то это будет полезно

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...