SpringBoot利用@Async优雅实现异步任务以及注意事项(同一类中调用无效的解决)

2022-04-09 690点热度 0人点赞 0条评论

很早之前写异步任务,可能就是直接使用Thread类来操作,例如:

new Thread() {
    @Override
    public void run() {
        // 要执行的异步操作
    }
}.start();

// 或者这样:
new Thread(() -> {
// 要执行的异步操作
}).start();

后来慢慢改进成:java.util.concurrent.Executor

在SpringBoot下,可以更加优雅的实现这些操作

首先开启异步的配置,只要增加@EnableAsync注解就可以了

@EnableAsync
@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

调用示例,给需要异步的方法,加上@Async注解,返回值只能是void或者Future,可以带参数,如下:

@Component
public class AsyncDemo {
    private static final Logger log = LoggerFactory.getLogger(AsyncDemo.class);

    /**
     * 最简单的异步调用,返回值为void
     */
    @Async
    public void asyncInvokeSimplest() {
        log.info("asyncSimplest");
    }

    /**
     * 带参数的异步调用 异步方法可以传入参数
     * 
     * @param s
     */
    @Async
    public void asyncInvokeWithParameter(String s) {
        log.info("asyncInvokeWithParameter, parementer={}", s);
    }

    /**
     * 异常调用返回Future
     * 
     * @param i
     * @return
     */
    @Async
    public Future<String> asyncInvokeReturnFuture(int i) {
        log.info("asyncInvokeReturnFuture, parementer={}", i);
        Future<String> future;
        try {
            Thread.sleep(1000 * 1);
            future = new AsyncResult<String>("success:" + i);
        } catch (InterruptedException e) {
            future = new AsyncResult<String>("error");
        }
        return future;
    }

}

这样调用没问题:

asyncDemo.asyncInvokeSimplest();
asyncDemo.asyncInvokeWithException("test");
Future<String> future = asyncDemo.asyncInvokeReturnFuture(100);
System.out.println(future.get());

注意事项

在相同的类中调用本类中的异步的方法,异步效果会失效

@Component
public class AsyncDemo {
    private static final Logger log = LoggerFactory.getLogger(AsyncDemo.class);

    /**
     * 最简单的异步调用,返回值为void
     */
    @Async
    public void asyncInvokeSimplest() {
        log.info("asyncSimplest");
    }

    // 反例,在test中,直接调用本类中的asyncInvokeSimplest方法,其实不会异步调用的
    public void test() {
        this.asyncInvokeSimplest();
    }

}

如果一定在本方法中调用,解决办法如下:

利用ApplicationContext.getBean得到本类的Proxy,然后来调用

@Service
public class AsyncDemo {
    private static final Logger log = LoggerFactory.getLogger(AsyncDemo.class);

    @Autowired
    private ApplicationContext applicationContext;

    private AsyncDemo getSpringProxy() {
        return applicationContext.getBean(this.getClass());
    }

    /**
     * 最简单的异步调用,返回值为void
     */
    @Async
    public void asyncInvokeSimplest() {
        log.info("asyncSimplest");
    }

    // 本类中调用异步方法不生效的解决办法
    public void test() {
        getSpringProxy().asyncInvokeSimplest();
        // 不要这样调用: this.asyncInvokeSimplest();
    }

}

 

admin

这个人很懒,什么都没留下

文章评论

您需要 登录 之后才可以评论