新年新征程
新年新气象
元旦节快乐
虎年大吉,家人们。
祝大家日入百万,心想事成。
为啥使用异步??
异步方法可以让业务接口快到飞起
异步方法适用于逻辑与逻辑之间可以相互分割互不影响的业务中, 如生成验证码和发送验证码组成的业务, 其实无需等到真正发送成功验证码才对客户端进行响应, 可以让短信发送这一耗时操作转为异步执行, 解耦耗时操作和核心业务
异步:
注解说明:
@EnableAsync // 使用异步方法时需要提前开启(在启动类上或配置类上)
@Async // 被async注解修饰的方法由SpringBoot默认线程池(SimpleAsyncTaskExecutor)执行
看代码结构:
异步配置
/**
* 异步的一个配置
*
* @author Songxianyang
* @date 2022-01-01 21:22
*/
@EnableAsync
@Configuration
public class SyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//设置核心线程数
executor.setCorePoolSize(8);
// 设置最大线程数
executor.setMaxPoolSize(20);
// 设置队列大小
executor.setQueueCapacity(Integer.MAX_VALUE);
// 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(60);
// 设置线程名前缀+分组名称
executor.setThreadNamePrefix("AsyncOperationThread-");
executor.setThreadGroupName("AsyncOperationGroup");
// 所有任务结束后关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
// 初始化
executor.initialize();
return executor;
}
//异步异常打印
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new CustomAsyncExceptionHandler();
}
}
异步异常打印
/**
* 异步异常打印
*
* @author Songxianyang
* @date 2022-01-01 21:28
*/
@Slf4j
public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
log.error("异常捕获------------");
log.error("Exception message 异常信息 {}", throwable.getMessage() );
log.error("Method name 方法名称: {}", method.getName());
for (Object param : objects) {
System.out.println("Parameter value - " + param);
}
}
}
发短信 业务层
/**
* 发短信 业务层
*
* @author Songxianyang
* @date 2022-01-01 21:09
*/
@Slf4j
@Service
public class MsgService {
//定义生成策略
public static final String CODE_id = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
/**
* 生成验证码
* @return 4位
*/
public String createCode() {
StringBuilder sb=new StringBuilder(4);
for(int i=0;i<4;i++)
{
char ch=CODE_id.charAt(new Random().nextInt(CODE_id.length()));
sb.append(ch);
}
return sb.toString();
}
/**
* 发生验证码
* @param code 4验证码
* @return code
*/
@Async
public void sendCode(String code) throws InterruptedException {
TimeUnit.SECONDS.sleep(10);
// throw new RuntimeException("故意异常");
log.info("发生给用户:");
log.info("【SteveCode】验证码:{},您正在使用SteveCode,需要进行验证,请勿向任何人提供您收到的短信验证码。", code);
}
}
测试异步方法调用
/**
* 测试异步方法调用
*
* @author Songxianyang
* @date 2022-01-01 21:48
*/
@RestController
@RequestMapping("sync")
public class TestSyncWeb {
@Resource
private MsgService msgService;
@SneakyThrows
@GetMapping("send")
public String userSendCode() {
String code = msgService.createCode();
msgService.sendCode(code);
return "短信已发送,请注意查收";
}
}
异步方法 带来的问题吧!
- 异步方法执行失败后对Controller前半部分的非异步操作无影响, 因此说异步方法在整个业务逻辑中不是100%可靠的,
- 对于强一致性的业务来说不适用 还是消息中间件更为强大, RabbitMQ, Kafka…
- 异步方法只能声明在Service方法中在Controller直接调用才会生效, 异步方法被同级Service方法调用不会生效
效果图
页面先打印信息:
10秒–后台才会把具体的信息发送给给用户。【为什么10s, TimeUnit.SECONDS.sleep(10)】