(十八)SpringBoot2.0使用@Async实现异步调用

本文详细介绍如何在SpringBoot项目中使用@EnableAsync和@Async注解实现异步任务,包括配置依赖、启动类注解、异步方法示例及演示效果。

一. 项目示例

1.1 pom依赖

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

其实该异步实现类spring已经有了,直接调用即可。
在这里插入图片描述

1.2 启动类加上@EnableAsync

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

1.3 需要执行异步方法上加@Async

我在更新用户的方法上加上@Async注解,模拟更新用户会员信息及投资金额,这时就不用等待updateIndexBb方法执行完,就可以直接返回结果,页面无需等待。
我在updateUserInfo方法上加了@Async,表示该方法会另外开启一个线程去执行,同时我也异步去更新VIP用户信息和用户投资金额,所以我在其他两个方法上也加上了@Async,这个一般看情况而定。

    @Async
    @Override
    public void updateVipInfo(String userId) {
        log.info("【查询VIP用户信息开始】,参数:[userId:{}]", userId);
        try {
            Thread.sleep(5 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("【查询VIP用户信息结束】,参数:[userId:{}]", userId);
    }

    @Async
    @Override
    public void updateUserMoney(String userId) {
        log.info("【查询用户投资金额开始】,参数:[userId:{}]", userId);
        try {
            Thread.sleep(10 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("【查询用户投资金额开始】,参数:[userId:{}]", userId);
    }

    @Async
    @Override
    public void updateUserInfo(String userId) {
        log.info("【更新用户信息开始】,参数:[userId:{}]", userId);
        try {
            updateVipInfo(userId);
            updateUserMoney(userId);
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("【更新用户信息结束】,参数:[userId:{}]", userId);
    }

1.4 演示

在浏览器中输入地址:http://localhost:8080/index/updateUserInfo?userId=hejinrong
即可看到返回的结果:在这里插入图片描述
日志打印如下:
在这里插入图片描述

二. 源码下载

https://gitee.com/hejr.cn.com/SpringBoot2.0_2019/tree/master/springboot2_10

下一篇:(十九)SpringBoot2.0整合拦截器

<think>好的,我现在需要帮助用户在SpringBoot和Vue2.0项目中实现Redis存储订单号以避免重复支付和错误支付。用户之前已经提供了他们的思路和一些代码示例,还引用了几个相关的资料,比如阻塞队列生成订单、Vue和SpringBoot的管理系统模板、Avue组件的事件绑定等。我需要结合这些信息,给出一个具体的实现方案。 首先,用户的核心需求是防止重复支付和错误支付,这涉及到订单号的唯一性和支付状态的正确性。参考之前的回答,用户提到使用Redis的原子操作和分布式锁来保证幂等性。现在需要将这些概念应用到SpringBoot后端和Vue前端的具体实现中。 接下来,我需要考虑如何在SpringBoot中生成订单号并存入Redis。用户之前的示例使用了Python,现在需要转成Java的SpringBoot代码。可能用到的Redis命令括SETNX、EXPIRE等,确保订单号在创建时被唯一保存,并设置过期时间。同时,处理支付时需要检查订单是否存在,金额是否匹配等。 另外,用户提到了使用阻塞队列来保存订单信息,这可能涉及到订单生成的异步处理。需要确保订单生成和保存到Redis的过程是原子性的,避免并发问题。在SpringBoot中,可能需要使用@Transactional注解来保证数据库和Redis操作的事务性,或者使用分布式事务解决方案,但考虑到复杂性,可能优先依赖Redis的原子操作。 在Vue前端部分,用户可能需要在创建订单后,前端轮询或接收WebSocket通知来获取订单状态,避免重复提交。引用中提到了Avue组件的事件绑定和分页参数,可能需要在前端处理支付请求时,禁用按钮或显示加载状态,防止用户多次点击。 还需要考虑分布式锁的应用,比如在支付处理时,使用Redis的Redisson客户端来实现锁,防止多个请求同时处理同一个订单。同时,订单状态需要持久化到数据库,Redis作为缓存层,数据库作为最终一致性的保障。 此外,用户引用的资料中有关于系统设计和模板的内容,可能需要参考现有的权限管理、日志模块等,确保订单系统的安全性和可维护性。例如,用户管理模块可以用来验证用户身份,日志模块记录支付操作,方便后续排查问题。 在整合这些信息时,需要注意代码的正确性和最佳实践。例如,Redis的键命名规范、TTL设置、异常处理等。同时,前端和后端的接口设计要明确,比如创建订单的API、支付确认的API,以及如何传递订单号、金额等信息。 最后,需要验证整个流程,确保在并发情况下不会出现重复支付,金额错误时能正确拦截,并且系统在Redis故障时有降级方案,比如直接查询数据库。此外,监控和日志记录也是关键,及时发现和处理异常情况。</think>#### 基于SpringBoot+Vue2.0的支付防重方案设计(整合引用内容) --- ### 一、架构设计要点(结合引用[1][2][4]) 1. **双端协作模式** - 前端(Vue2.0+Avue):使用`@on-load`事件初始化支付页[^3],通过`:page`绑定分页参数[^3] - 后端(SpringBoot):基于通用管理系统模板扩展支付模块[^2],复用用户认证、日志等基础能力 2. **数据流向** ```mermaid graph TD A[用户支付请求] --> B{前端防重检查} B -->|首次请求| C[生成临时订单号] C --> D[禁用支付按钮] D --> E[调用SpringBoot API] E --> F{Redis原子校验} F -->|通过| G[创建正式订单] G --> H[写入阻塞队列[^1]] ``` --- ### 二、SpringBoot核心实现(扩展引用[1]代码) #### 1. 订单服务层(Redis集成) ```java @Service public class OrderService { @Autowired private RedisTemplate<String, String> redisTemplate; // 生成带防重标记的订单(原子操作) public String createOrder(OrderDTO orderDTO) { String orderKey = "order:" + orderDTO.getOrderId(); // 使用SETNX+EXPIRE原子命令 Boolean result = redisTemplate.execute((RedisCallback<Boolean>) connection -> { connection.multi(); connection.setEx(orderKey.getBytes(), 300, "CREATED".getBytes()); return connection.exec().size() > 0; }); if (!result) { throw new BusinessException("订单已存在"); } // 写入数据库(参考引用[1]阻塞队列模式) orderQueue.add(buildVoucherOrder(orderDTO)); // 阻塞队列实现[^1] return orderDTO.getOrderId(); } } ``` #### 2. 支付校验拦截器(分布式锁实现) ```java public class PaymentInterceptor implements HandlerInterceptor { // 基于Redisson的分布式锁(防并发支付) public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String orderId = request.getParameter("orderId"); RLock lock = redissonClient.getLock("pay_lock:" + orderId); try { if (lock.tryLock(2, 5, TimeUnit.SECONDS)) { String status = redisTemplate.opsForValue().get("order:" + orderId); if (!"CREATED".equals(status)) { throw new PaymentException("非法支付状态"); } redisTemplate.opsForValue().set("order:" + orderId, "PAYING", 600); return true; } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return false; } } ``` --- ### 三、Vue2.0前端控制(结合引用[3]) #### 1. Avue表格支付状态绑定 ```javascript // 在avue配置中增加支付状态控制 export default { data() { return { tableOption: { column: [ { label: '支付状态', prop: 'payStatus', type: 'select', dicData: [ { label: '待支付', value: 'CREATED' }, { label: '支付中', value: 'PAYING' }, { label: '已完成', value: 'COMPLETED' } ] } ] } } } } ``` #### 2. 支付按钮防重点击 ```javascript // 使用async/await实现防重提交 methods: { async handlePayment(orderId) { this.loading = true; try { const res = await this.$axios.post('/api/payment', { orderId, amount: this.form.amount }); if (res.data.code === 200) { this.$message.success('支付成功'); this.$refs.crud.refresh(); // 刷新avue表格[^3] } } finally { this.loading = false; } } } ``` --- ### 四、异常处理方案 1. **金额不一致防护** ```java // 支付回调时校验金额 @Transactional public void checkAmount(String orderId, BigDecimal amount) { Order order = orderMapper.selectById(orderId); if (order.getTotalAmount().compareTo(amount) != 0) { redisTemplate.opsForValue().set("order:"+orderId, "ERROR", 3600); throw new AmountMismatchException("金额不一致"); } } ``` 2. **状态恢复机制** ```bash # 通过Redis监控自动恢复异常订单 redis-cli --scan --pattern 'order:*' | while read key; do status=$(redis-cli get $key) if [ "$status" = "PAYING" ]; then ttl=$(redis-cli ttl $key) if [ $ttl -lt 300 ]; then redis-cli setex $key 600 "CREATED" fi fi done ``` --- ### 五、监控与优化(参考引用[4]实践) 1. **Redis监控指标** ```properties # application.properties spring.redis.metrics.enabled=true management.endpoints.web.exposure.include=redismetrics ``` 2. **支付链路追踪** ```java // 复用通用系统的日志模块[^2] @Slf4j @Aspect @Component public class PaymentLogAspect { @Around("execution(* com..payment.*(..))") public Object logPayment(ProceedingJoinPoint pjp) throws Throwable { log.info("支付操作开始: {}", pjp.getSignature()); Object result = pjp.proceed(); log.info("支付操作完成: {}", pjp.getArgs()); return result; } } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值