想要将短信推送和微信消息推送的功能变为异步执行。对于这种场景, 可以使用Java的 CompletableFuture 或 Spring的 @Async 注解来实现。

以下是使用 CompletableFuture 的方式:

java

CompletableFuture.runAsync(() -> {
    // 短信发送代码
}).exceptionally(ex -> {
    ex.printStackTrace();
    logger.info("短信发送失败:{}", ex.getMessage());
    return null;
});
CompletableFuture.runAsync(() -> {
    // 微信模板消息推送代码
}).exceptionally(ex -> {
    ex.printStackTrace();
    return null;
});

这里的 CompletableFuture.runAsync() 方法将会在新的线程中执行传入的lambda表达式,而 exceptionally 方法用于处理执行中出现的异常。

另一个选项是 Spring 的 @Async 注解,它可以使得方法异步地执行。以下是如何使用这个注解:

  1. 首先在Spring Boot的主类或配置类中开启异步执行:

java

@Configuration
@EnableAsync
public class AsyncConfiguration {
}

2.然后在需要异步执行的方法上添加 @Async 注解:

java

@Service
public class YourService {
    @Async
    public void sendSms() {
        // 短信发送代码
    }

    @Async
    public void sendWeChatTemplateMsg() {
        // 微信模板消息推送代码
    }
}

其中,@Async标注的方法将会在另一个线程中执行。

无论是使用 CompletableFuture 还是 @Async 注解,都可以将耗时的IO操作如发送短信和推送微信消息变为异步执行,从而提高程序的响应速度

例如:通过CompletableFuture 自定义线程池,重构现有代码。

CompletableFuture中使用自定义线程池,需要先创建一个ExecutorService对象,然后将它作为参数传递给CompletableFuture.runAsync()方法。

下面是如何定义一个固定大小的线程池以及如何在CompletableFuture使用这个线程池:

java

@Autowired
private SmsSendService smsSendService;

@Autowired
private WeChatSendService weChatSendService;

// 定义一个具有10个线程的线程池
private ExecutorService executorService = Executors.newFixedThreadPool(10);

@PostMapping("/registerViolation")
@Transactional
public AjaxResult registerViolation(@Valid @RequestBody TblViolationRecords tblViolationRecords, BindingResult bindingResult)
{    
    // ...之前的代码保持不变

    CompletableFuture<Void> smsFuture = CompletableFuture.runAsync(() -> {
        try {
            String smsResult = smsSendService.sendSms(mobiles, content);
            // ...记录及处理短信发送结果的代码
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("短信发送失败:{}", e.getMessage());
        }
    }, executorService);

    CompletableFuture<Void> weChatFuture = CompletableFuture.runAsync(() -> {
        try {
            // 获取 wxAccessToken
            String wxAccessToken = weChatSendService.getWXAccessToken();
            // ...推送微信模板消息的代码
        } catch (Exception e) {
            e.printStackTrace();
        }
    }, executorService);

    CompletableFuture.allOf(smsFuture, weChatFuture).join();

    return AjaxResult.success();
}

在这里,我们在类的字段中定义了一个ExecutorService的实例executorService,它由Executors.newFixedThreadPool(10)生成,表示最多有10个线程被同时执行。然后我们将executorService作为第二个参数传递给CompletableFuture.runAsync()的方法,这样,CompletableFuture就会在我们的线程池中执行任务了。

将自定义线程池作为参数传递给CompletableFuture.runAsync()方法,可以更好地控制线程的执行。你可以根据应用程序的需求,调整线程池的大小。

注意:你需要在应用程序关闭或不再需要使用线程池时,调用ExecutorService.shutdown()方法来关闭线程池,释放资源。你可以通过Spring的@PreDestroy注解,在Bean销毁时关闭线程池:

java

@PreDestroy
public void destroy() {
    if (executorService != null) {
        executorService.shutdown();
    }
}