Spring Rerys est une fonction énergétique indépendante du lot de ressort, qui met principalement en œuvre et fusionne. Il existe des restrictions de scénarios pour la réessayer, et tous les scénarios ne conviennent pas à la réessayer, tels que la vérification illégale des paramètres, les opérations d'écriture, etc. (vous devez vous demander si l'écriture est idempotente) ne conviennent pas à la réessayer. Le délai d'appel à distance ou l'interruption du réseau peut être réessayé. Dans le cadre de gouvernance des microservices, il a généralement sa propre configuration de réessayer et de délai d'attente. Par exemple, Dubbo peut définir Retries = 1, Timeout = 500 Call échoue et réessayer une seule fois, et l'appel échoue s'il ne revient pas après plus de 500 ms. Dans Spring Rerying, vous pouvez spécifier le type d'exception qui doit être réessayé et définir l'intervalle pour chaque réessayer et si la nouvelle tentative échoue, s'il faut continuer à réessayer ou à fusionner (arrêtez-vous réessayer).
Conception et mise en œuvre
RetryOperations définissent l'API RETRY. RetryTemplate est l'implémentation en mode modèle de l'API, qui implémente la réessayer et la rupture de circuit. L'API fournie est la suivante:
Interface publique Retryoperations {<t, e étend Throwable> T EXECUTE (RetryCallback <T, E> RetryCallback) lance e; } // D'autres API ont été omises RetryCallback définit l'opération qui doit être effectuée. Après avoir défini l'opération, c'est la question de savoir comment réessayer. RetryTemplate exécute la logique de la façon de réessayer en formulant différentes stratégies de réessayer. La stratégie de réessayer par défaut est SimpleRetryPlicy , ce qui signifie qu'elle sera réessayée 3 fois. Si la nouvelle tentative réussit, vous ne continuerez pas à réessayer. Et si la nouvelle tentative de 3 pieds échouait? Le processus se termine ou renvoie le résultat ascendant. Pour retourner le résultat ascendant, vous devez configurer RecoveyCallBack . À partir du nom, vous pouvez voir qu'il s'agit d'une interface de rappel ascendante, qui est la logique de l'exécution après l'échec de la réessayer. En plus de SimpleRetryPolicy , il existe d'autres stratégies de réessayer. Jetons un coup d'œil à l'interface RetryPolicy :
L'interface publique RetryPolicy étend Serializable {boolean canretry (contexte de retRyContext); RetryContext Open (Parent RetryContext); void close (contexte de retRyContext); void RegisterThrowable (contexte de retRyContext, jetable jetable);} canRetry s'appelle chaque fois que vous réessayez. La condition de jugement de savoir si vous pouvez continuer à réessayer
Appelé avant le démarrage de l' open Retry, un contexte de réchauffement sera créé sur RetryContext , et la pile de retry sera enregistrée.
registerThrowable est appelé chaque fois que l'exception est réessayée (il y a une exception et elle continuera de réessayer)
Prenez SimpleRetryPolicy comme exemple. Lorsque le nombre de Rerys atteint 3 (par défaut 3 fois), arrêtez la réessayer et que le nombre de réessayer est enregistré dans le contexte de réessayer.
Fournir la mise en œuvre de la stratégie de réessayer suivante:
RETRING La stratégie de secours fait référence à la réessayer de réessayer immédiatement ou d'attendre un certain temps avant de réessayer. Par défaut, vous devez spécifier la stratégie Backoff BackoffRetryPolicy si vous devez configurer une période d'attente, puis réessayer. BackOffretryPolicy a la mise en œuvre suivante:
État de réessayer ou de réessayer sans état
Le soi-disant retrait apatride fait référence à la réessayer terminée dans un contexte de fil. Sinon, si la réessayer n'est pas terminée dans un contexte de thread est de tentative avec état. La SimpleRetryPolicy était une réessayer sans état car la réessayer a été achevée dans une boucle. Alors, que se passe-t-il après cela ou doit être réessayé dans un état? Il y a généralement deux situations: le retour en arrière et le disjoncteur de transaction.
DataAccessException est exceptionnel. Réessayer ne peut pas être effectué, mais si d'autres exceptions sont lancées, vous pouvez réessayer.
Fuse signifie ne pas gérer la réessayer dans la boucle actuelle, mais en mode de réessayer global (pas le contexte de thread). Le disjoncteur de circuit sautera de la boucle et les informations de pile du contexte du thread seront inévitablement perdues. Ensuite, il est certainement nécessaire de sauvegarder ces informations dans un "mode global". L'implémentation actuelle est placée dans un cache (implémentation de la carte). Vous pouvez continuer à réessayer après l'avoir obtenu du cache la prochaine fois.
Démarrage rapide
Utilisez @EnableRetry sur la classe qui doit effectuer une réessayer, si proxyTargetClass=true est défini, cela utilise le proxy dynamique CGLIB:
@ Configuration @ capableRet (proxytargetClass = true) @componentpublic class reryexamples {} Réessayer en fonction du nombre maximum de stratégie de tentatives, si la réessayer est répétée 3 fois et que l'exception est toujours lancée, la réessayer est arrêtée et le rappel ascendant est exécuté. Par conséquent, le résultat de sortie final est Integer.MAX_VALUE :
private void RetryExample3 () lève une exception {reryTemplate reryTemplate = new RetryTemplate (); SimpleretryPolicy SimpletryPolicy = new SimpletryPolicy (); SimpleretryPolicy.SetMaxAtTempts (3); RetryTemplate.setRetryPolicy (SimpletryPolicy); Integer Result = RetryTemplate.Execute (new RetryCallback <Integer, exception> () {int i = 0; // RetRey the Operation @Override public Integer Dowithretry (retRyContext ReryContex RecoveryCallback <Integer> () {// Callure de base @Override public Integer Recover (retRyContext RetryContext) lance une exception {log.info ("après la nouvelle: {}, la méthode de récupération appelée!", RetRyContex log.info ("résultat final: {}", résultat); } private int len (int i) lève une exception {if (i <10) lancer une nouvelle exception (i + "le 10"); retour i; }Ce qui suit décrit comment utiliser le mode de politique de réessayer du disjoncteur de circuit (CircuitBreakerRetyPolicy). Les trois paramètres suivants doivent être définis:
Circuit Breaker Opening and Close Judgment:
Le code de test est le suivant:
RetryTemplate Template = new RetryTemplate (); CircuitBreakerretryPolicy RetryPolicy = New CircuitBreakerRetyPolicy (New SimpleretryPolicy (3)); RetryPolicy.SetOpentimeout (5000); RetryPolicy.SetRereTtimeout (20000); template.setRetryPolicy (RetryPolicy); pour (int i = 0; i <10; i ++) {//thread.sleep(100); essayez {objet key = "circuit"; booléen isforcerefresh = false; RetryState State = new DefaultretryState (Key, isForCereFresh); String result = template.execute (new RetryCallback <String, runtimeException> () {@Override public String Dowithretry (ReryContext Context) lève RuntimeException {log.info ("Retry Count: {}", context.getRetryCount (); New RecoveryClack <) ()}}}, new RecoveryBrack <) {) {) {) {);); @Override public String Recover (RetryContext Context) lance l'exception {return "Default"; log.info ("result: {}", résultat); } catch (exception e) {System.out.println (e); }} Étant donné que isForceRefresh = false est défini, la valeur de key = "circuit" (c'est-à-dire RetryContext) sera obtenue à partir du cache. RetryContext conséquent, lorsque la nouvelle tentative échoue et this.time < this.openWindow .
Développement d'annotation
Si l'écriture d'un RetryTemplate à chaque fois que vous avez une exigence de réessayer est trop gonflée, l'utilisation d'annotations peut considérablement simplifier le développement et réduire le code en double. Voici une réessayer de la stratégie de réessayer maximale mise en œuvre à l'aide d'annotations:
@Retryable (value = sqlDataException.class, backoff = @backoff (value = 0l)) public String Service3 () lève sqlDataException {log.info ("Service3 Open"); lancer un nouveau sqldataException (); } @Recover public String Recover (sqlDataException ne) {return "SqlDataException Recover"; }Les annotations incluent:
@Enabletry
@Retryable
@Récupérer
@Backoff
@Circuitbreaker
@EnableRetry: Pouvez-vous réessayer? Lorsque la propriété proxytargetClass est vraie (par défaut false), utilisez le proxy CGLIB
@Retryable: la méthode que l'annotation doit être réessayée
@Backoff: réessayez la stratégie de secours (essayez maintenant ou attendez un moment avant de réessayer)
@Recover: pour une utilisation avec des méthodes. Utilisé comme méthode "garantie" lorsque @Retryable échoue. La méthode d'annotation @recover doit être cohérente avec la méthode "signature" de l'annotation @Retryable. Le premier paramètre d'entrée est l'exception à réessayer. D'autres paramètres sont cohérents avec @Retryable. La valeur de retour doit être la même, sinon elle ne peut pas être exécutée!
@CircuitBreaker: utilisé pour la méthode, implémenter le mode de rupture de circuit.
Pour plus d'exemples, bienvenue dans mon github (https://github.com/happyxiaofan/springboot-learning-example) Star. Merci
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.