1概要

Spring Retryは失敗した操作を自動的に再起動する機能を提供します。これは、エラーが一時的なものである可能性がある場合に役立ちます(瞬間的なネットワーク障害など)。 Spring Retryはプロセスの宣言的制御とポリシーベースの振る舞いを提供し、それは拡張とカスタマイズが容易です。

この記事では、https://github.com/spring-projects/spring-retry[Spring Retry]を使用してSpringアプリケーションに再試行ロジックを実装する方法を説明します。追加のコールバックを受信するようにリスナーも設定します。

** 2 Mavenの依存関係

**

まず、

pom.xml

に依存関係を追加します。

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>1.1.5.RELEASE</version>
</dependency>


https://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22org.springframework.retry%22%20AND%20a%3A%22spring-で


spring-retry

の最新バージョンを確認できます%22を再試行してください[Maven Central]。


3春の再試行を有効にする

アプリケーションでSpring Retryを有効にするには、

@ Enable

Retry

アノテーションを

@ Configuration__クラスに追加する必要があります。

@Configuration
@EnableRetry
public class AppConfig { ... }


4注釈を付けて再試行

アノテーションを使用して失敗したときに再試行するメソッド呼び出しを作成できます。


4.1.

@再試行可能


メソッドに再試行機能を追加するには、

@ Retryable

を使用できます。

@Service
public interface MyService {
    @Retryable(
      value = { SQLException.class },
      maxAttempts = 2,
      backoff = @Backoff(delay = 5000))
    void retryService(String sql) throws SQLException;
    ...
}

ここでは、__ @ Retryableの属性を使用して再試行動作がカスタマイズされています。


@ Retryable

が属性なしで使用された場合、メソッドが例外で失敗した場合、再試行は最大3回、1秒の遅延で試行されます。


4.2.

@回復する



@ Recoverable

メソッドが指定された例外で失敗した場合、

@ Recover

アノテーションを使用して個別のリカバリ方法を定義します。

@Service
public interface MyService {
    ...
    @Recover
    void recover(SQLException e, String sql);
}


5

RetryTemplate



5.1

再試行操作


Spring Retryは、

execute()

メソッドのセットを提供する

RetryOperations

インターフェースを提供します。

public interface RetryOperations {
    <T> T execute(RetryCallback<T> retryCallback) throws Exception;

    ...
}


execute()

のパラメータである

RetryCallback

は、失敗時に再試行する必要があるビジネスロジックの挿入を可能にするインタフェースです。

public interface RetryCallback<T> {
    T doWithRetry(RetryContext context) throws Throwable;
}


5.2.

RetryTemplate

設定


RetryTemplate

は、

RetryOperations

の実装です。

@ Configuration

クラスに

RetryTemplate

Beanを設定しましょう。

@Configuration
public class AppConfig {
   //...
    @Bean
    public RetryTemplate retryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();

        FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
        fixedBackOffPolicy.setBackOffPeriod(2000l);
        retryTemplate.setBackOffPolicy(fixedBackOffPolicy);

        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
        retryPolicy.setMaxAttempts(2);
        retryTemplate.setRetryPolicy(retryPolicy);

        return retryTemplate;
    }
}


__は、操作をいつ再試行するかを決定します。

__は、一定の回数だけ再試行するために使用されます。


__は再試行の間の制御をオフにするために使用されます。

__は継続する前に一定期間休止します。


5.3.

RetryTemplate


を使用する

再試行処理を使用してコードを実行するには、r:


を呼び出します。

retryTemplate.execute(new RetryCallback<Void, RuntimeException>() {
    @Override
    public Void doWithRetry(RetryContext arg0) {
        myService.templateRetryService();
        ...
    }
});

匿名クラスの代わりにラムダ式を使用しても同じことが実現できます。

+

retryTemplate.execute(arg0 -> {
    myService.templateRetryService();
    return null;
});


6. XML設定

Spring AOP名前空間を使用して、Spring RetryをXMLで構成できます。


6.1. XMLファイルを追加する

クラスパスに

retryadvice.xml

を追加しましょう。

...
<beans>
    <aop:config>
        <aop:pointcut id="transactional"
          expression="execution(** MyService.xmlRetryService(..))"/>
        <aop:advisor pointcut-ref="transactional"
          advice-ref="taskRetryAdvice" order="-1"/>
    </aop:config>

    <bean id="taskRetryAdvice"
      class="org.springframework.retry.interceptor.
        RetryOperationsInterceptor">
        <property name="RetryOperations" ref="taskRetryTemplate"/>
    </bean>

    <bean id="taskRetryTemplate"
      class="org.springframework.retry.support.RetryTemplate">
        <property name="retryPolicy" ref="taskRetryPolicy"/>
        <property name="backOffPolicy" ref="exponentialBackOffPolicy"/>
    </bean>

    <bean id="taskRetryPolicy"
        class="org.springframework.retry.policy.SimpleRetryPolicy">
        <constructor-arg index="0" value="5"/>
        <constructor-arg index="1">
            <map>
                <entry key="java.lang.RuntimeException" value="true"/>
            </map>
        </constructor-arg>
    </bean>

    <bean id="exponentialBackOffPolicy"
      class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
        <property name="initialInterval" value="300">
        </property>
        <property name="maxInterval" value="30000">
        </property>
        <property name="multiplier" value="2.0">
        </property>
    </bean>
</beans>
...

この例では、

xmlRetryService

メソッドのインターセプター内でカスタム

RetryTemplate

を使用しています。


6.2. XML設定を使用する


classpath

から

retryadvice.xml

をインポートし、

@ AspectJ

サポートを有効にします。

@Configuration
@EnableRetry
@EnableAspectJAutoProxy
@ImportResource("classpath:/retryadvice.xml")
public class AppConfig { ... }


7. リスナー

リスナーは再試行時に追加のコールバックを提供します。さまざまな再試行にまたがるさまざまな分野横断的な懸念に使用できます。


7.1. コールバックを追加する

コールバックは

RetryListener

インタフェースで提供されています。

public class DefaultListenerSupport extends RetryListenerSupport {
    @Override
    public <T, E extends Throwable> void close(RetryContext context,
      RetryCallback<T, E> callback, Throwable throwable) {
        logger.info("onClose);
        ...
        super.close(context, callback, throwable);
    }

    @Override
    public <T, E extends Throwable> void onError(RetryContext context,
      RetryCallback<T, E> callback, Throwable throwable) {
        logger.info("onError");
        ...
        super.onError(context, callback, throwable);
    }

    @Override
    public <T, E extends Throwable> boolean open(RetryContext context,
      RetryCallback<T, E> callback) {
        logger.info("onOpen);
        ...
        return super.open(context, callback);
    }
}


open

および

close

コールバックは、全体の再試行の前後に行われ、

onError

は個々の

RetryCallback

コールに適用されます。


7.2. リスナーの登録

次に、リスナー(

DefaultListenerSupport)を

RetryTemplate__ Beanに登録します。

@Configuration
public class AppConfig {
    ...

    @Bean
    public RetryTemplate retryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();
        ...
        retryTemplate.registerListener(new DefaultListenerSupport());
        return retryTemplate;
    }
}


8結果をテストする

結果を確認しましょう。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  classes = AppConfig.class,
  loader = AnnotationConfigContextLoader.class)
public class SpringRetryTest {

    @Autowired
    private MyService myService;

    @Autowired
    private RetryTemplate retryTemplate;

    @Test(expected = RuntimeException.class)
    public void givenTemplateRetryService__whenCallWithException__thenRetry() {
        retryTemplate.execute(arg0 -> {
            myService.templateRetryService();
            return null;
        });
    }
}

テストケースを実行すると、以下のログテキストは

RetryTemplate

とListenerを正常に設定したことを意味します。

2017-01-09 20:04:10[main]INFO  o.b.s.DefaultListenerSupport - onOpen
2017-01-09 20:04:10[main]INFO  o.baeldung.springretry.MyServiceImpl
- throw RuntimeException in method templateRetryService()
2017-01-09 20:04:10[main]INFO  o.b.s.DefaultListenerSupport - onError
2017-01-09 20:04:12[main]INFO  o.baeldung.springretry.MyServiceImpl
- throw RuntimeException in method templateRetryService()
2017-01-09 20:04:12[main]INFO  o.b.s.DefaultListenerSupport - onError
2017-01-09 20:04:12[main]INFO  o.b.s.DefaultListenerSupport - onClose


9.


結論

この記事では、Spring Retryを紹介しました。アノテーションと

RetryTemplate

を使った再試行の例を見ました。それからリスナーを使って追加のコールバックを設定しました。

あなたはこの記事のソースコードを見つけることができますhttps://github.com/eugenp/tutorials/tree/master/spring-all[GitHubについて]。