从调用者类停止异步Spring方法 [英] Stop an async Spring method from caller class

查看:38
本文介绍了从调用者类停止异步Spring方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类,该类调用Rest Web服务以从服务器接收文件.传输字节时,我创建了一个异步任务,它检查与服务器的连接是否正常,如果出现错误,则允许停止连接.这个异步任务有一个循环,我必须停止:

I've a class that call a Rest web service to receive a file from server. While bytes are transferred, I've created an Async task, it checks if connection with server is fine to allow the stop connection if an error appears. This async task has a loop that I have to stop:

@Component
public class ConnectionTest {

    @Async
    //Check connection with the server, if for three attemp it failes, throw exception
    public void checkServerConnection(String serverIp) throws Exception{
        int count=0;
        for(;;Thread.sleep(7000)){
            try{
                System.out.println("TEST");
                URL url = new URL(serverIp);
            HttpURLConnection con = (HttpURLConnection) url
                    .openConnection();
            con.connect();
            if (con.getResponseCode() == 200){
                System.out.println("Connection established!!");
            }
                if (count>0) count=0;
            }catch(Exception e){
                count++;
                if (count==3)   
                    throw new Exception("Connection error");
            }
        }
    }
}

但是如何从调用者处停止此方法?

but how can I stop this method from the caller?

@Autowired 
    private ConnectionTest connectionTest;

    @Override
    public Response getFile(String username, String password, String serverIp, String toStorePath, String filePath){


        ResponseEntity<byte[]> responseEntity = null;
        try{
            //it is used to check if connection of the client with the server goes down
            connectionTest.checkServerConnection();
            RestClient restClient = new RestClient(username, password);     

            //          SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
            //          requestFactory.setBufferRequestBody(false);     
            //          restClient.setRequestFactory(requestFactory);
            //          RestTemplate restClient = new RestTemplate();
            responseEntity  = restClient.getForEntity(serverIp + "client/file/?filePath={filePath}", byte[].class, filePath);   

            //TODO kill async task and return false

UPDATE :由于@Thomas建议我在ConnectionTest中使用了布尔变量,因此我用 while(!stop),然后在调用Web服务后,设置 ConnectionTest.setStop(true).请注意,以在循环之前(而不是作为实例字段)设置stop = false,否则只有第一个请求具有此值并且进入while内.

UPDATE: as @Thomas has suggested I've used a boolean variable in ConnectionTest, I changed for cycle with while (!stop) and after the web service call I set ConnectionTest.setStop(true). Pay attention to set stop=false before loop (and not as instance field) otherwise only the first request has this value and goes inside the while.

更新2 这是我的最后一个代码,似乎可以正常工作,也许我应该在使用wait-notify循环时进行更改:

UPDATE 2 This is the my last code, it seems to work, maybe I should change while loop with wait-notify:

public Response getFile(String username, String password, String serverIp, String toStorePath, String filePath){
        try{
            //it is used to check if connection of the client with the server goes down
            Future<Boolean> isConnect = connectionTest.checkServerConnection(serverIp);
            Future<ResponseEntity<byte[]>> downloadResult = downloadAsync.makeRequest(username, password, serverIp, filePath);

            while(!isConnect.isDone() && !downloadResult.isDone()){
            }
            if (isConnect.isDone()){
                downloadResult.cancel(true);
                return new Response(false, false, "Error with server connection!", null);
            }else{
                connectionTest.setStop(true);
                ResponseEntity<byte[]> responseEntity = downloadResult.get();

                if (MediaType.TEXT_PLAIN.toString().equals(responseEntity.getHeaders().getContentType().toString())){
                    ErrorResponse errorResponse= ErrorResponseBuilder.buildErrorResponse(new FileException("Error with file transfert!"));
                    return new Response(false, false, new String(Base64.decodeBase64(responseEntity.getBody()),Charset.forName("UTF-8")), errorResponse);
                }else{
                    Path p = Paths.get(filePath);
                    String fileName = p.getFileName().toString();
                    FileOutputStream fos = new FileOutputStream(toStorePath+"\\"+ fileName);
                    fos.write(responseEntity.getBody());
                    fos.close();
                    return new Response(true, true, "Your file has been downloaded!", null);
                }
            }
        }catch(Exception e){
            ErrorResponse errorResponse= ErrorResponseBuilder.buildErrorResponse(e);
            return new Response(false, false, "Error on the client side!" , errorResponse);
        }
    }

连接检查异步:

@Component
public class ConnectionTest {

    private boolean stop;

    @Async
    //Check connection with the server, if for three attemp it failes, throw exception
    /**
     * 
     * @param serverIp
     * @throws IOException
     */
    public Future<Boolean> checkServerConnection(String serverIp)  throws IOException {
        int count=0;
        stop = false;
        while (!stop){
            try{
                Thread.sleep(7000);
                System.out.println("TEST");
                //java.net.InetAddress.getByName(SERVER_ADDRESSS);
                URL url = new URL(serverIp);
                HttpURLConnection con = (HttpURLConnection) url
                        .openConnection();
                con.connect();
                if (count>0) count=0;
            }catch(Exception e){
                count++;
                System.out.println(count);
                if (count==3)   
                    return new AsyncResult<Boolean>(stop);
            }
        }
        return new AsyncResult<Boolean>(stop);
    }

    /**
     * @return the stop
     */
    public boolean isStop() {
        return stop;
    }

    /**
     * @param stop the stop to set
     */
    public void setStop(boolean stop) {
        this.stop = stop;
    }
}

下载异步:

@Component
public class DownloadAsync {

    @Async
    public Future<ResponseEntity<byte[]>> makeRequest(String username, String password, String serverIp, String filePath){
        RestClient restClient = new RestClient(username, password);
        ResponseEntity<byte[]> response= restClient.getForEntity(serverIp + "client/file/?filePath={filePath}", byte[].class, filePath);    
        return new AsyncResult<ResponseEntity<byte[]>>(response);
    }
}

推荐答案

在处理 @Async 方法时,一个好的做法是从以下方法返回 Future 对象这是因为您需要客户端和任务代码之间的连接点.

让我们让您的任务方法返回 Future :

When you deal with an @Async method, a good practice is to return a Future object from it because you need a connection point between the client and task code.

Let's make your task method return a Future:

public Future<Integer> checkServerConnection(String serverIp) {
    // other code here
    return new AsyncResult<>(count);
}

您需要添加几个导入:

import java.util.concurrent.Future;
import org.springframework.scheduling.annotation.AsyncResult;

最后,在客户端代码中,让我们获取 Future :

Finally, in the client code let's get the Future:

Future<Integer> checkTask = connectionTest.checkServerConnection();

现在,您可以使用 checkTask 做一些有用的事情.例如:

Now, you can do some useful things with the checkTask. For example:

// Check if the task was completed including by an exception being thrown.
checkTask.isDone();

// Get the task result.
Integer count = checkTask.get(); // Note: this is a blocking method.

// If the task was finished by throwing an exception,
// get() method will also throw an exception.
// You can get the cause exception like this:
if (checkTask.isDone()) {
    try {
        checkTask.get();
    } catch(Exception e) {
        Exception cause = e.getCause(); // this will be your new Exception("Connection error")
    }
}

// Not recommended, but you can also cancel the task:
checkTask.cancel(mayInterruptIfRunning);

这篇关于从调用者类停止异步Spring方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆