首页 > 解决方案 > 从方法调用时@Retryable 不起作用

问题描述

下面是我的应用程序类。流程就像DEToken从这里开始的类,从DEToken我调用RestConnection我有@retryable方法的地方开始。

@SpringBootApplication
@EnableRetry
public class SpringBootTrfficApplication implements CommandLineRunner {

    Enter code here

    @Autowired
    DEToken deToken;

    @Autowired
    SyncService syncService;
    public static void main(String[] args) {
        SpringApplication.run(SpringBootTrfficApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        deToken.getToken();
    }
}

DEToken 类:从getToken我调用RestConnect我有@Retrable方法的地方:

@Service
public class DEToken {
    private Logger logger = LogManager.getLogger(getClass());

    @Autowired
    RestConnection restConnection;

    @Autowired
    private Environment env;

    public String accessToken;

    public void getToken() {
        System.out.println("hello from get token");
        //String getJsonPayload = "{\"Query\":{\"RegisterExtensionWithDE\":{\"pid\": \"\",\"providerInsName\":" +
        //env.getProperty("provider.ins") + "}}}";
        //String str = restConnection.restPost(
        //    env.getProperty("rest.de.url"), getJsonPayload);

        try {
            String getJsonPayload =
                "{\"Query\":{\"RegisterExtensionWithDE\":{\"pid\": \"\",\"providerInsName\":" +
                env.getProperty("provider.ins") + "}}}";
            StringBuffer tokenResult =
                restConnection.restPost(env.getProperty("rest.de.url"),
                                        getJsonPayload);
            System.out.println(tokenResult);
            JSONObject xmlJSONObj = XML.toJSONObject(tokenResult.toString());
            JSONObject registration = new JSONObject();
            if (xmlJSONObj.has("Registration")) {
                registration  = xmlJSONObj.getJSONObject("Registration");
                if (registration.has("accessToken")) {
                    accessToken = registration.get("accessToken").toString();
                }
                else
                    logger.info("no accessToken from DE");
            }
            else
                logger.info("no Registration object from DE");
        }
        catch (Exception e) {
            logger.error("Exception while fetching accesstoken from DE ");
            logger.error(e.getMessage());
        }
    }
}

我有retryable方法的 REST 连接类:

@Service
public class RestConnection {

    private Logger logger = LogManager.getLogger(getClass());

    @Autowired
    private Environment env;

    public void setBaseUrl(String value, String ip) {
        //baseUrl = value;
        HttpsURLConnection.setDefaultHostnameVerifier(
            (hostname, session) -> hostname.equals(ip));
    }


    /*
     * REST post call
     */
    @Retryable(value = {IOException.class, ConnectException.class},
               maxAttempts = 4,
               backoff = @Backoff(5000))
    public StringBuffer restPost(String restUrl, String payload) {
        StringBuffer sb = new StringBuffer();
        HttpURLConnection conn = null;
        try {
            URL url = new URL(restUrl);
            String protocol = url.getProtocol();
            if (protocol.toLowerCase().equals("http")) {
                conn = (HttpURLConnection)url.openConnection();
            }
            else if (protocol.toLowerCase().equals("https")) {
                //setTrustedCert();
                conn = (HttpsURLConnection)url.openConnection();
            }
            else {
                logger.info("Protocol is neither HTTP nor HTTPS");
            }
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("Accept", "application/json");
            conn.setRequestProperty("version", env.getProperty("de.version"));
            conn.setRequestProperty("accessToken", env.getProperty("access.token"));
            conn.setRequestProperty("requestHost", env.getProperty("server.de.host"));
            conn.setRequestProperty("requestPort", env.getProperty("server.port"));
            conn.setRequestProperty("requestProtocol",
                                    env.getProperty("server.de.protocol"));
            PrintWriter pout =
                new PrintWriter(
                    new OutputStreamWriter(
                        conn.getOutputStream(), "UTF-8"),
                    true);
            pout.print(payload);
            pout.flush();
            pout.close();

            InputStream isi = conn.getInputStream();
            InputStreamReader isr = new InputStreamReader(isi);
            int numCharsRead1;
            char[] charArray1 = new char[1024];

            while ((numCharsRead1 = isr.read(charArray1)) > 0) {
                sb.append(charArray1, 0, numCharsRead1);
            }
            isr.close();
            isi.close();
        }
        catch (MalformedURLException e) {
            logger.error("MalformedURLException in restAccessTokenPOST..." +
                         e.getMessage());
            //e.printStackTrace();
        }
        catch (IOException e) {
            logger.error("IOException in restAccessTokenPOST..." +
                         e.getMessage());
            e.printStackTrace();
        }
        catch (Exception e) {
            logger.error("Exception in restAccessTokenPOST..." +
                         e.getMessage());
            e.printStackTrace();
        }
        finally {
            if (null != conn)
                conn.disconnect();
        }
        return sb;
    }

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

    @Recover
    public String helpHere(IOException 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";
    }
}

标签: spring-bootaopspring-retry

解决方案


考虑到你看到你的函数restPost()实现,

@Retryable(value = {IOException.class, ConnectException.class},
           maxAttempts = 4,
           backoff = @Backoff(5000))
public StringBuffer restPost(String restUrl, String payload) {
    try {
        // Your code
    }
    catch(IOException ex){ // These catch block handles the exception
                           // and nothing to throw to retryable.
    }
    catch(MalformedURLException ex){ // More catch blocks that you
                                     // define to handle exception.
    }
}

在这里,您处理所有可能导致撤销retryandrecover方法的异常。

注意:可恢复方法仅在抛出异常时执行,不由任何try-catch块处理。

方法引发的任何异常restPost()都由方法try-catch块本身处理,并且没有由 catch 块重新引发的异常。

现在,Spring-Retry无法获得任何异常(因为它是由方法try-catch块处理的)。因此,不会执行任何恢复方法。

解决方案:您应该从要对其执行重试恢复的方法定义中删除那些 catch 块。

请做必要的事情,它会像魅力一样工作...... :)


推荐阅读