Spring Retry: метод, помеченный @Recover, не вызывается

Я тестирую весеннюю повторную попытку, но похоже, что восстановление не вызывается. Пытался заставить его работать, но это кажется исчерпывающим. Я перешел к @Recover без аргументов, Throwable, Exception. Изменена версия зависимости повторных попыток, и, похоже, она включена в aop для весенней загрузки и удалена. Продолжение восстановления не вызывается со следующим сообщением об исключении.

Ошибка обработки запроса; вложенное исключение - org.springframework.retry.ExhaustedRetryException: не удается найти метод восстановления; вложенное исключение - java.lang.ArithmeticException: / по нулю] с основной причиной

Любая помощь приветствуется

Код, который у меня есть, выглядит как показано ниже.

Класс конфигурации

package hello;

import java.util.Arrays;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.retry.annotation.Retryable;

@SpringBootApplication
@EnableRetry
public class Application {
public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
}

@Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
    return args -> {

        System.out.println("Let's inspect the beans provided by `Spring Boot:");`

        String[] beanNames = ctx.getBeanDefinitionNames();
        Arrays.sort(beanNames);
        for (String beanName : beanNames) {
            System.out.println(beanName);
        }

    };
}

}

Класс Rest Controller;

package hello;

import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.retry.annotation.Backoff;
import org.springframework.web.bind.annotation.RequestMapping;

@RestController
public class HelloController {

@Autowired
private SomeService service;

@RequestMapping("/")
public String hello() {
    String result = service.getInfo();
    return result;
}

}

Класс обслуживания есть;

ackage hello;

import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

@Service
public class SomeService {

@Retryable(value = ArithmeticException.class, maxAttempts = 3, `backoff = @Backoff(delay = 3000))`
public String getInfo() {
    System.out.println("How many time will this be printed?");
    return "Hello" + 4/0;
}

@Recover
public void helpHere(ArithmeticException cause) {
        System.out.println(cause);
        System.out.println("Recovery place!");
}

Это мой список зависимостей

 <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- tag::actuator[] -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!-- end::actuator[] -->
    <!-- tag::tests[] -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <!-- end::tests[] -->
    <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
        </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
</dependencies>

С попыткой и множеством аргументов

 @Service
public class SomeService {

    @Retryable(value = {ArithmeticException.class}, maxAttempts = 3, `backoff = @Backoff(delay = 3000))`
public String getInfo() {
        try {
        System.out.println("How many time will this be printed?");
        return "Hello" + 4/0;
    } catch(ArithmeticException ex) {
            System.out.println("In the arthemetic Exception");
            throw new ArithmeticException();
    }   
}

@Recover
public void helpHere(ArithmeticException cause) {
        System.out.println(cause);
        System.out.println("Recovery place! ArithmeticException");
}
@Recover
public void helpHere(Exception cause ) {
        System.out.println(cause);
        System.out.println("Recovery place! Exception");
}

@Recover
public void helpHere(Throwable cause) {
        System.out.println(cause);
        System.out.println("Recovery place! Exception");
}

@Recover
public void helpHere() {
        System.out.println("Recovery place! Exception");
}
}

Снимок экрана консоли

введите описание изображения здесь


person Tadele Azanaw    schedule 14.05.2018    source источник
comment
зачем вам два @Recover в двух разных классах?   -  person John Joe    schedule 14.05.2018
comment
Я ошибся при копировании. Оба на самом деле принадлежат к одному классу. Редактирование ... один из них должен быть классом контроллера   -  person Tadele Azanaw    schedule 14.05.2018
comment
будет ли работать, если удалить ArithmeticException.class?   -  person John Joe    schedule 14.05.2018
comment
Нет. Я пытался с другими аргументами, но ни один не работал   -  person Tadele Azanaw    schedule 14.05.2018
comment
удалить System.out.println(cause); и посмотреть   -  person John Joe    schedule 14.05.2018
comment
также удалите {} между ArithmeticException.class.   -  person John Joe    schedule 14.05.2018
comment
Хорошо я попробую   -  person Tadele Azanaw    schedule 14.05.2018
comment
Совсем не помогло. Кажется, эта штука с @Recover не в руке   -  person Tadele Azanaw    schedule 14.05.2018


Ответы (2)


Вы должны использовать try-catch, чтобы справиться с этим. Вот пример

@Retryable(value = ArithmeticException.class, maxAttempts = 5, backoff = @Backoff(delay = 3000))
    public String getInfo() {
        try {
            System.out.println("How many time will this be printed?");
            return "Hello" + 4 / 0;
        } catch (ArithmeticException ex) {
            // will be retried
            throw ex;
        }
    }

throw ex; является обязательным, поскольку он сообщает Spring применить обработку повторных попыток. С @Recover мы определяем отдельный метод восстановления для ArithmeticException. Это позволяет нам запускать специальный код восстановления, когда повторный метод завершается неудачно с ArithmeticException.

Вы можете получить дополнительную информацию о Как обрабатывать повторные попытки с помощью Spring-Retry?

Изменить

На основе последнего исключения попробуйте предоставить версию для повторной попытки пружины

 <dependency>
       <groupId>org.springframework.retry</groupId>
       <artifactId>spring-retry</artifactId>
       <version>1.2.1.RELEASE</version>
 </dependency>
person John Joe    schedule 14.05.2018
comment
Это был бы лучший выбор, так как я не смог заставить работать восстановление. Единственное, что у меня есть, это то, что мне просто нужно получить некоторую логику, если возникнет исключение. Если повторная попытка повторяется 3 раза, она будет выполняться в улове столько же раз. Спасибо за вариант - person Tadele Azanaw; 14.05.2018
comment
Это то, что тебе надо ? - person John Joe; 14.05.2018
comment
Вроде, но когда возникает исключение и оно повторяется 3 раза, я просто хочу иметь один метод восстановления, когда я делаю что-то еще. в этом случае он проходит 3 раза, но все равно работает нормально. - person Tadele Azanaw; 14.05.2018
comment
Для экземпляра, если вызов базы данных завершился неудачно (после 3 повторных вызовов с @retrable), и я не смог получить ввод, мне нужно вернуть некоторые фиктивные данные, только один раз. Я думал, что восстановление будет лучше. - person Tadele Azanaw; 14.05.2018
comment
Вы можете иметь свою логику других в @Recovery. После трех попыток он вызовет метод восстановления. Метод восстановления будет вызван только один раз. - person John Joe; 14.05.2018
comment
Да, я на это надеялся. к сожалению, методы, помеченные @Recover, вообще не работают - person Tadele Azanaw; 14.05.2018
comment
Эти две строки System.out.println(cause); System.out.println("Recovery place!"); не печатаются, хотя вы попробовали мой ответ? - person John Joe; 14.05.2018
comment
Нет! это не так. Я поставил вот так How many time will this be printed? printed message form catch How many time will this be printed? printed message form catch How many time will this be printed? printed message form catch На самом деле я уменьшил повторную попытку в 3 раза - person Tadele Azanaw; 14.05.2018
comment
проверьте мой ответ еще раз - person John Joe; 14.05.2018
comment
Я поставил такой вопрос: "Сколько раз это будет напечатано?" форма печатного сообщения ... Не знаю, зачем вам повторять эти несколько строк. Можете ли вы опубликовать свой последний код? - person John Joe; 14.05.2018
comment
Ничего из этого не помогло, вызвать метод @Recover - person Tadele Azanaw; 14.05.2018
comment
Так почему этот ответ отмечен как правильный ?? @TadeleAzanaw - person Alberto; 24.04.2019
comment
Это не ответ, пожалуйста, снимите отметку, это вводит в заблуждение - person Sunil Rk; 22.10.2019

Наконец-то я получил ответ.

Для вызова метода, помеченного @Recover, он должен иметь тот же аргумент метода (плюс исключение) и тот же тип возвращаемого значения.

Я тестировал его с другим типом аргумента исключения, и методы вызываются, если у них есть более конкретный тип исключения. Если у меня есть такой метод, будет вызываться тот, у которого есть аргумент Exception. Однако, если у меня есть несколько методов восстановления, будет вызываться только один с более конкретным аргументом исключения.

@Recover
public String helpHere(ArithmeticException cause) {

Окончательный пример кода

package hello;

import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

@Service
public class SomeService {

@Retryable(maxAttempts = 3, backoff = @Backoff(delay = 3000))
public String getInfo() {
        try {
        System.out.println("How many time will this be printed?");
        return "Hello" + 4/0;
    } catch(Exception ex) {
            System.out.println("In the arthemetic Exception");
            throw new ArithmeticException();
    }   
}

@Recover
public String helpHere(ArithmeticException cause) {

        System.out.println("Recovery place! ArithmeticException");
        return "Hello";
}
@Recover
public String helpHere(Exception cause ) {

        System.out.println("Recovery place! Exception");
        return "Hello";
}

@Recover
public String helpHere() {
        System.out.println("Recovery place! Exception");
        return "Hello";
}

@Recover
public String helpHere(Throwable cause) {

        System.out.println("Recovery place! Throwable");
        return "Hello";
}

введите описание изображения здесь

person Tadele Azanaw    schedule 14.05.2018
comment
Это основная часть. Для вызова метода, аннотированного ------- с @Recover, он должен иметь тот же аргумент метода (плюс исключение) и тот же тип возвращаемого значения -----. - person Arjun T Raj; 17.03.2020
comment
Вам не нужны аргументы метода, просто исключение, поскольку у меня сработал параметр. И да, возвращаемый тип должен быть таким же, как кажется. - person Bhdr; 06.06.2021