2016-04-05 2 views
5

Я пробую весеннюю попытку, и у меня возникла странная проблема. Когда я использую аннотацию повтора для метода в контроллере останова, повторная попытка не работает. Но если я переведу этот метод в отдельный класс обслуживания, он работает. Следующий код не работает:Весенний повтор не работает в RestController

@RestController 
public class HelloController { 

    @RequestMapping(value = "/hello") 
    public String hello() { 
     return getInfo(); 
    } 

    @Retryable(RuntimeException.class) 
    public String getInfo() { 
     Random random = new Random(); 
     int r = random.nextInt(2); 
     if (r == 1) { 
      throw new RuntimeException(); 
     } else { 
      return "Success"; 
     } 
    } 
} 

Но следующее делает:

@RestController 
public class HelloController { 

    @Autowired 
    private SomeService service; 

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

@Service 
public class SomeService { 

    @Retryable(RuntimeException.class) 
    public String getInfo() { 
     Random random = new Random(); 
     int r = random.nextInt(2); 
     if (r == 1) { 
      throw new RuntimeException(); 
     } else { 
      return "Success"; 
     } 
    } 
} 

Мой вопрос, почему @Retryable не работает, когда используется в контроллере?

ответ

4

Проблема, которую вы видите, связана с тем, как вы вызываете свой метод getInfo().

В первом примере вы вызываете getInfo() из одного и того же весеннего управляемого компонента. Во втором примере вы вызываете getInfo() из другого управляемого фаном источника. Это различие является тонким, но очень важным, и очень вероятно, что вызывает проблемы.

Когда вы используете аннотацию @Retryable, Spring создает прокси-сервер вокруг вашего первоначального компонента, чтобы они могли выполнять специальную обработку в особых обстоятельствах. В этом конкретном случае Spring применяет Совет, который будет делегировать вызов вашему фактическому методу, поймав RuntimeException, который он может выбросить, и повторите вызов вашего метода в соответствии с конфигурацией аннотации @Retryable.

Причина, по которой этот прокси-сервер имеет значение в вашем случае, заключается в том, что только внешние абоненты видят совет прокси. Ваш компонент не знает, что он проксирован, и только знает, что его методы вызываются (по советам прокси). Когда ваш bean-метод вызывает метод сам по себе, никакого дополнительного проксирования не задействовано, поэтому повторная попытка на самом деле не возникает.