【Java】配置redis 注解 @Async 实现异步调用方法 uuid 完整代码(个人梳理)

本文介绍了如何在Java中配置Redis,并利用@Async注解实现异步方法处理批量请求。在后台接收到请求后,生成唯一UUID,将处理结果以UUID为键存储在Redis中,前端通过轮询获取处理状态并展示。

【Java】配置redis 注解 @Async 实现异步方法 uuid 完整代码(个人梳理)

【Java】配置redis 注解 @Async 实现异步方法 uuid 完整代码(个人梳理)



前言

前台发送批处理请求到后台,后台接受请求,生成唯一值uuid,调用异步处理方法,将实时处理结果以uuid为key值存储到redis中, 前台接收到请求后不断以uuid轮询后台,后台将redis中处理结果返还前台进行页面展示。


一、配置redis.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd  
                        http://www.springframework.org/schema/context  
                        http://www.springframework.org/schema/context/spring-context-4.0.xsd">
	<!-- Jedis线程 -->
	<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
		<property name="maxIdle" value="20" />
		<property name="minIdle" value="5" />
		<property name="maxTotal" value="100" />
		<property name="testOnBorrow" value="true" />
	</bean>

	<!-- jedis客户端单机版 -->
	<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
		<constructor-arg name="host" value="192.168.1.201"></constructor-arg>
		<constructor-arg name="port" value="自己的端口号"></constructor-arg>
		<constructor-arg name="password" value="自己的密码"></constructor-arg>
		<constructor-arg name="timeout" value="3000"></constructor-arg>
		<constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>
	</bean>

    <bean id="jedisClient" class="com.自己的包名.training.util.jedis.JedisClientSingleImpl"/>
</beans>

二、配置Jedis工具类

1.JedisClient

package com.自己的包名.training.util.jedis;

import java.util.Set;

/**
 * Created by Administrator 
 */
public interface JedisClient {
   
   
    /**
     * 获取缓存
     * @param key
     * @return
     */
    String get(String key);

    byte[] get(byte[] key);

    /**
     * 设置缓存
     * @param key
     * @param value
     * @return
     */
    String set(String key, String value);

    /**
     * 设置缓存
     * @param key
     * @param value
     * @param expire 过去时间
     * @return
     */
    String set(String key, String value, int expire);

    String set(byte[] key, byte[] value);

    String set(byte[] key, byte[] value, int expire);

    /**
     * 哈希 获取缓存
     * @param hkey
     * @param key
     * @return
     */
    String hget(String hkey, String key);

    /**
     * 哈希 设置缓存
     * @param hkey
     * @param key
     * @param value
     * @return
     */
    long hset(String hkey, String key, String value);

    /**
     *获取自增值
     * @param key
     * @return
     */
    long incr(String key);

    /**
     *设置有效期
     * @param key
     * @param second
     * @return
     */
    long expire(String key, int second);

    /**
     *获取有效期
     * @param key
     * @return
     */
    long ttl(String key);

    /**
     * 删除缓存
     * @param key
     * @return
     */
    long del(String key);

    long del(byte[] key);

    /**
     * 删除哈希 缓存
     * @param hkey
     * @param key
     * @return
     */
    long hdel(String hkey, String key);

    Set<byte[]> keys(String pattern);

    /**
     * 刷新数据
     */
    void flushDB();

    Long dbSize();
}

2.配置JedisClientSingleImpl

package com.自己的包名.training.util.jedis;

import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.Set;

public class JedisClientSingleImpl implements JedisClient{
   
   

	@Autowired
	private JedisPool jedisPool;

	@Override
	public String get(String key) {
   
   
		String value = null;
		Jedis jedis = jedisPool.getResource();
		try{
   
   
			value = jedis.get(key);
		} catch (Exception e) {
   
   
			jedisPool.returnBrokenResource(jedis);
		} finally {
   
   
			jedisPool.returnResource(jedis);
		}
		return value;
	}

	@Override
	public byte[] get(byte[] key) {
   
   
		byte[] value = null;
		Jedis jedis = jedisPool.getResource();
		try{
   
   
			value = jedis.get(key);
		} catch (Exception e) {
   
   
			jedisPool.returnBrokenResource(jedis);
		} finally {
   
   
			jedisPool.returnResource(jedis);
		}
		return value;
	}

	@Override
	public String set(String key, String value) {
   
   
		Jedis jedis = jedisPool.getResource();
		try {
   
   
			value = jedis.set(key, value);
		}catch (Exception e) {
   
   
			jedisPool.returnBrokenResource(jedis);
		} finally {
   
   
			jedisPool.returnResource(jedis);
		}
		return value;
	}

	@Override
	public String set(String key, String value, int expire) 
<think>我们将构建一个前后端分离的异步数据同步方案: 前端:React(使用axios进行HTTP请求) 后端:Spring Boot(使用@Async实现异步处理) 整体流程: 1. 前端调用后端同步接口 2. 后端立即返回任务ID(表示已接受请求,任务进入处理队列) 3. 前端轮询任务状态直到完成 4. 后端异步执行同步任务更新状态 后端实现步骤: a. 创建任务模型和状态存储(使用内存或数据库,这里使用ConcurrentHashMap模拟) b. 使用Spring的@Async实现异步方法 c. 提供两个接口:启动同步(返回任务ID)、查询任务状态 前端实现步骤: a. 调用启动接口获取任务ID b. 使用setInterval轮询状态接口 c. 根据状态更新UI(轮询直到任务完成) 下面分别给出前后端代码: ### 后端代码 (Spring Boot) 1. 添加依赖(pom.xml): ```xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- 使用H2作为内存数据库,简化示例 --> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> </dependencies> ``` 2. 启用异步支持(主类上添加注解): ```java @SpringBootApplication @EnableAsync public class AsyncDemoApplication { public static void main(String[] args) { SpringApplication.run(AsyncDemoApplication.class, args); } } ``` 3. 创建任务状态模型和存储服务: ```java import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.springframework.stereotype.Service; @Service public class TaskService { // 存储任务状态,实际生产环境可用数据库或Redis private Map<String, String> taskStatusMap = new ConcurrentHashMap<>(); public void createTask(String taskId) { taskStatusMap.put(taskId, "PENDING"); } public void updateTaskStatus(String taskId, String status) { taskStatusMap.put(taskId, status); } public String getTaskStatus(String taskId) { return taskStatusMap.getOrDefault(taskId, "NOT_FOUND"); } } ``` 4. 控制器和异步服务: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.UUID; @RestController @RequestMapping("/api/sync") public class SyncController { @Autowired private TaskService taskService; @Autowired private SyncService syncService; // 启动同步 @PostMapping("/start") public SyncResponse startSync() { String taskId = UUID.randomUUID().toString(); taskService.createTask(taskId); // 异步调用同步方法 syncService.performSync(taskId); return new SyncResponse(taskId); } // 查询任务状态 @GetMapping("/status/{taskId}") public TaskStatusResponse getTaskStatus(@PathVariable String taskId) { String status = taskService.getTaskStatus(taskId); return new TaskStatusResponse(taskId, status); } } // 异步服务 @Service public class SyncService { @Autowired private TaskService taskService; @Async public void performSync(String taskId) { try { taskService.updateTaskStatus(taskId, "RUNNING"); // 模拟耗时操作(例如:同步数据) Thread.sleep(5000); // 5秒 // 实际同步逻辑... taskService.updateTaskStatus(taskId, "COMPLETED"); } catch (InterruptedException e) { taskService.updateTaskStatus(taskId, "FAILED"); e.printStackTrace(); } } } // 响应模型 public class SyncResponse { private String taskId; public SyncResponse(String taskId) { this.taskId = taskId; } // getter and setter } public class TaskStatusResponse { private String taskId; private String status; public TaskStatusResponse(String taskId, String status) { this.taskId = taskId; this.status = status; } // getters and setters } ``` ### 前端代码 (React) 1. 安装axios: `npm install axios` 2. 组件示例: ```jsx import React, { useState } from 'react'; import axios from 'axios'; const SyncComponent = () => { const [taskId, setTaskId] = useState(null); const [status, setStatus] = useState(''); const [isLoading, setIsLoading] = useState(false); const startSync = async () => { setIsLoading(true); try { const response = await axios.post('http://localhost:8080/api/sync/start'); const newTaskId = response.data.taskId; setTaskId(newTaskId); setStatus('pending'); // 开始轮询状态 const intervalId = setInterval(async () => { try { const statusResponse = await axios.get(`http://localhost:8080/api/sync/status/${newTaskId}`); const currentStatus = statusResponse.data.status; setStatus(currentStatus); // 如果任务完成或失败,清除轮询 if (currentStatus === 'COMPLETED' || currentStatus === 'FAILED') { clearInterval(intervalId); setIsLoading(false); } } catch (error) { console.error('Error checking status:', error); clearInterval(intervalId); setIsLoading(false); } }, 1000); // 每秒轮询一次 } catch (error) { console.error('Error starting sync:', error); setIsLoading(false); } }; return ( <div> <button onClick={startSync} disabled={isLoading}> {isLoading ? 'Syncing...' : 'Start Data Sync'} </button> {taskId && ( <div> <p>Task ID: {taskId}</p> <p>Status: {status}</p> </div> )} </div> ); }; export default SyncComponent; ``` ### 解释 **后端部分**: - `@EnableAsync`:启用Spring的异步执行能力。 - `@Async`:标记方法异步执行,Spring会将其放入线程池中运行。 - 任务状态存储:使用内存中的`ConcurrentHashMap`存储任务状态(实际生产环境应使用数据库或Redis)。 - 接口设计: - `POST /api/sync/start`:创建任务立即返回任务ID,后台异步执行同步。 - `GET /api/sync/status/{taskId}`:根据任务ID查询状态。 **前端部分**: - 使用React的`useState`管理状态(任务ID、状态、加载状态)。 - 点击按钮触发`startSync`函数: - 发送POST请求启动同步,获取任务ID。 - 使用`setInterval`每秒轮询任务状态。 - 当状态变为`COMPLETED`或`FAILED`时停止轮询。 ### 注意事项 1. **线程池配置**:默认情况下,Spring使用一个简单的线程池。生产环境需自定义线程池: ```java @Configuration @EnableAsync public class AsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(25); executor.initialize(); return executor; } } ``` 2. **状态存储**:示例使用内存存储,重启后状态丢失。生产环境应使用数据库或Redis。 3. **轮询优化**:前端轮询可能造成服务端压力,可考虑WebSocket推送状态更新。 ### 扩展建议 - 添加任务超时处理 - 记录任务详细日志 - 实现任务取消功能 - 添加身份验证和权限控制 §§相关问题§§: 1. 如何防止前端频繁轮询给后端造成压力? 2. 除了轮询,还有哪些技术可以实现异步任务状态通知? 3. 在Spring Boot中如何配置多个不同的异步线程池? 4. 如果同步任务需要传递大量参数,后端接口应该如何设计?</think>下面我将详细讲解如何在 React 前端和 Spring Boot 后端之间实现异步数据同步方案,提供完整代码实现和原理说明。 ### 整体架构设计 ```mermaid sequenceDiagram participant F as React前端 participant B as Spring Boot后端 F->>B: 1. 发起同步请求 B-->>F: 2. 立即返回任务ID B->>B: 3. 异步执行同步任务 F->>B: 4. 定期轮询任务状态 B-->>F: 5. 返回任务状态 loop 直到任务完成 F->>B: 继续轮询 B-->>F: 返回最新状态 end B-->>F: 6. 返回最终结果 ``` ### 后端实现 (Spring Boot) #### 1. 添加依赖 (pom.xml) ```xml <dependencies> <!-- Spring Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring Data JPA --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- H2 数据库 (内存数据库) --> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <!-- Spring Async 支持 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-async</artifactId> </dependency> </dependencies> ``` #### 2. 启用异步支持 (主应用类) ```java @SpringBootApplication @EnableAsync public class DataSyncApplication { public static void main(String[] args) { SpringApplication.run(DataSyncApplication.class, args); } @Bean public TaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(25); executor.initialize(); return executor; } } ``` #### 3. 实体类和存储库 ```java @Entity public class SyncTask { @Id private String taskId; private String status; // PENDING, PROCESSING, COMPLETED, FAILED private LocalDateTime createdAt; private LocalDateTime updatedAt; private String result; // 构造函数、getter和setter省略 } public interface SyncTaskRepository extends JpaRepository<SyncTask, String> { } ``` #### 4. 异步服务实现 ```java @Service public class DataSyncService { @Autowired private SyncTaskRepository taskRepository; @Async public CompletableFuture<String> performDataSync(String taskId) { // 更新任务状态为处理中 updateTaskStatus(taskId, "PROCESSING"); try { // 模拟耗时操作(实际替换为真实同步逻辑) Thread.sleep(5000); // 模拟同步结果 String result = "{\"source\": \"CRM\", \"target\": \"ERP\", " + "\"recordsSynced\": 150, \"timestamp\": \"" + LocalDateTime.now() + "\"}"; // 更新任务状态为完成 updateTaskStatus(taskId, "COMPLETED", result); return CompletableFuture.completedFuture(result); } catch (InterruptedException e) { updateTaskStatus(taskId, "FAILED", "同步失败: " + e.getMessage()); return CompletableFuture.failedFuture(e); } } private void updateTaskStatus(String taskId, String status) { updateTaskStatus(taskId, status, null); } private void updateTaskStatus(String taskId, String status, String result) { SyncTask task = taskRepository.findById(taskId) .orElseThrow(() -> new RuntimeException("任务不存在")); task.setStatus(status); task.setUpdatedAt(LocalDateTime.now()); if (result != null) { task.setResult(result); } taskRepository.save(task); } } ``` #### 5. 控制器实现 ```java @RestController @RequestMapping("/api/sync") public class SyncController { @Autowired private DataSyncService dataSyncService; @Autowired private SyncTaskRepository taskRepository; @PostMapping("/start") public ResponseEntity<Map<String, String>> startSync() { // 创建新任务 String taskId = UUID.randomUUID().toString(); SyncTask task = new SyncTask(); task.setTaskId(taskId); task.setStatus("PENDING"); task.setCreatedAt(LocalDateTime.now()); taskRepository.save(task); // 异步启动同步任务 dataSyncService.performDataSync(taskId); return ResponseEntity.ok(Map.of( "taskId", taskId, "statusUrl", "/api/sync/status/" + taskId )); } @GetMapping("/status/{taskId}") public ResponseEntity<Map<String, Object>> getSyncStatus( @PathVariable String taskId) { return taskRepository.findById(taskId) .map(task -> ResponseEntity.ok(Map.of( "taskId", task.getTaskId(), "status", task.getStatus(), "createdAt", task.getCreatedAt(), "updatedAt", task.getUpdatedAt(), "result", task.getResult() ))) .orElse(ResponseEntity.notFound().build()); } } ``` ### 前端实现 (React) #### 1. 同步服务模块 (src/services/syncService.js) ```javascript import axios from 'axios'; const API_BASE_URL = 'http://localhost:8080/api/sync'; export const startSync = async () => { try { const response = await axios.post(`${API_BASE_URL}/start`); return response.data; } catch (error) { console.error('启动同步失败:', error); throw error; } }; export const checkSyncStatus = async (taskId) => { try { const response = await axios.get(`${API_BASE_URL}/status/${taskId}`); return response.data; } catch (error) { console.error('检查状态失败:', error); throw error; } }; ``` #### 2. 同步组件实现 (src/components/SyncComponent.js) ```jsx import React, { useState } from 'react'; import { startSync, checkSyncStatus } from '../services/syncService'; const SyncComponent = () => { const [taskId, setTaskId] = useState(null); const [status, setStatus] = useState('idle'); const [syncResult, setSyncResult] = useState(null); const [error, setError] = useState(null); const [isPolling, setIsPolling] = useState(false); const [pollingInterval, setPollingInterval] = useState(null); const handleStartSync = async () => { try { setStatus('starting'); setError(null); setSyncResult(null); const response = await startSync(); setTaskId(response.taskId); setStatus('pending'); // 开始轮询状态 startPolling(response.taskId); } catch (err) { setError('启动同步失败'); setStatus('error'); } }; const startPolling = (taskId) => { setIsPolling(true); const interval = setInterval(async () => { try { const statusResponse = await checkSyncStatus(taskId); setStatus(statusResponse.status.toLowerCase()); if (statusResponse.result) { setSyncResult(JSON.parse(statusResponse.result)); } // 如果任务完成或失败,停止轮询 if (['completed', 'failed'].includes(statusResponse.status.toLowerCase())) { clearInterval(interval); setIsPolling(false); } } catch (err) { console.error('轮询错误:', err); clearInterval(interval); setIsPolling(false); setError('获取状态失败'); setStatus('error'); } }, 2000); // 每2秒轮询一次 setPollingInterval(interval); }; const getStatusText = () => { switch (status) { case 'idle': return '准备就绪'; case 'starting': return '正在启动同步...'; case 'pending': return '等待处理...'; case 'processing': return '同步进行中...'; case 'completed': return '同步完成!'; case 'failed': return '同步失败'; case 'error': return '发生错误'; default: return '未知状态'; } }; return ( <div className="sync-container"> <h2>数据同步</h2> {!taskId && ( <button onClick={handleStartSync} disabled={status === 'starting'} > {status === 'starting' ? '启动中...' : '开始同步'} </button> )} {taskId && ( <div className="task-info"> <p>任务ID: {taskId}</p> <p>状态: <span className={`status-${status}`}>{getStatusText()}</span></p> {isPolling && <p>正在检查状态...</p>} {status === 'completed' && syncResult && ( <div className="sync-result"> <h3>同步结果</h3> <p>源系统: {syncResult.source}</p> <p>目标系统: {syncResult.target}</p> <p>同步记录数: {syncResult.recordsSynced}</p> <p>完成时间: {syncResult.timestamp}</p> </div> )} {status === 'failed' && ( <div className="error-message"> <p>同步失败,请重试或联系管理员</p> </div> )} </div> )} {error && <div className="error">{error}</div>} </div> ); }; export default SyncComponent; ``` ### 关键实现点解释 1. **后端异步处理**: - 使用 `@EnableAsync` 开启异步支持 - 自定义线程池配置避免资源耗尽 - `@Async` 注解标记异步方法 - `CompletableFuture` 处理异步结果 2. **任务状态管理**: - 使用数据库持久化任务状态 - 任务生命周期:PENDING → PROCESSING → COMPLETED/FAILED - 每个状态变更都记录时间戳 3. **前端交互流程**: - 启动同步后立即返回任务ID - 使用轮询机制检查任务状态 - 状态更新时实时反馈给用户 - 提供完整的错误处理 4. **轮询策略优化**: - 初始轮询间隔2秒 - 长时间运行任务可动态调整间隔 - 任务完成后自动停止轮询 ### 生产环境增强建议 1. **任务超时处理**: ```java @Async @Timeout(value = 30, unit = TimeUnit.MINUTES) public CompletableFuture<String> performDataSync(String taskId) { // ... } ``` 2. **任务取消支持**: ```java @PostMapping("/cancel/{taskId}") public ResponseEntity<?> cancelSync(@PathVariable String taskId) { // 实现任务取消逻辑 } ``` 3. **WebSocket推送**: - 使用STOMP协议替代轮询 - 任务状态变更时主动推送 - 减少不必要的HTTP请求 4. **分布式任务队列**: - 集成RabbitMQ或Kafka - 实现任务持久化和重试 - 支持大规模任务处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值