SpringBoot学习日记 Day6:解锁微服务与高效任务处理

一、开篇:从单体到微服务的思维转变

刚开始接触微服务时,我总习惯把所有功能写在一个项目里。直到项目越来越臃肿,每次修改都要全量部署,才意识到微服务架构的价值。今天我们就来探索SpringBoot在微服务场景下的强大能力!

二、多模块项目:微服务的雏形

1. 创建父工程(pom.xml关键配置)

<packaging>pom</packaging>
<modules><module>weather-service</module><module>user-service</module><module>common</module>
</modules><!-- 统一依赖管理 -->
<dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.7.3</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement>

2. 子模块示例:common模块

common/
├── src/
│   ├── main/
│   │   ├── java/com/example/common/
│   │   │   ├── exception/  # 公共异常类
│   │   │   ├── utils/      # 工具类
│   │   │   └── config/     # 公共配置
│   ├── resources/
├── pom.xml

子模块pom.xml特点:

<parent><groupId>com.example</groupId><artifactId>parent-project</artifactId><version>1.0.0</version>
</parent><dependencies><!-- 模块间依赖 --><dependency><groupId>com.example</groupId><artifactId>common</artifactId><version>${project.version}</version></dependency>
</dependencies>

三、REST客户端:服务间通信的桥梁

1. RestTemplate基础用法

@Service
public class WeatherService {private final RestTemplate restTemplate;// 推荐使用构造器注入public WeatherService(RestTemplateBuilder builder) {this.restTemplate = builder.rootUri("https://api.weather.com").setConnectTimeout(Duration.ofSeconds(3)).build();}public WeatherData getWeather(String city) {String url = "/v1/current?city={city}";try {return restTemplate.getForObject(url, WeatherData.class, city);} catch (RestClientException e) {throw new BusinessException("天气服务调用失败", e);}}
}

2. WebClient响应式调用

@Service
public class ReactiveWeatherService {private final WebClient webClient;public ReactiveWeatherService(WebClient.Builder builder) {this.webClient = builder.baseUrl("https://api.weather.com").build();}public Mono<WeatherData> getWeatherAsync(String city) {return webClient.get().uri("/v1/current?city={city}", city).retrieve().bodyToMono(WeatherData.class).timeout(Duration.ofSeconds(2)).onErrorResume(e -> Mono.error(new BusinessException("天气服务异常")));}
}

3. 重试机制增强健壮性

@Bean
public RestTemplate restTemplate() {return new RestTemplateBuilder().interceptors(new RetryableRestTemplateInterceptor()).build();
}// 自定义拦截器
public class RetryableRestTemplateInterceptor implements ClientHttpRequestInterceptor {@Overridepublic ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {int retryCount = 0;ClientHttpResponse response;while (retryCount < 3) {try {response = execution.execute(request, body);if (response.getStatusCode().is5xxServerError()) {throw new IOException("Server error");}return response;} catch (IOException e) {retryCount++;if (retryCount >= 3) {throw e;}Thread.sleep(1000 * retryCount);}}throw new IOException("Request failed after retries");}
}

四、定时任务:后台执行的瑞士军刀

1. 基础定时任务

@Slf4j
@Component
@EnableScheduling
public class WeatherDataSyncTask {// 每30分钟执行一次@Scheduled(fixedRate = 30 * 60 * 1000)public void syncWeatherData() {log.info("开始同步天气数据...");// 业务逻辑}// 每天凌晨1点执行@Scheduled(cron = "0 0 1 * * ?")public void clearOldData() {log.info("清理过期数据...");}
}

2. 动态定时任务(数据库配置触发时间)

@Service
public class DynamicTaskService {@Autowiredprivate ThreadPoolTaskScheduler taskScheduler;private ScheduledFuture<?> future;public void startTask(String taskId, Runnable task, String cron) {stopTask(taskId); // 先停止已有任务future = taskScheduler.schedule(task, new CronTrigger(cron));}public void stopTask(String taskId) {if (future != null) {future.cancel(true);}}
}// 配置线程池
@Configuration
public class TaskConfig {@Beanpublic ThreadPoolTaskScheduler taskScheduler() {ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();scheduler.setPoolSize(5);scheduler.setThreadNamePrefix("task-");return scheduler;}
}

五、异步处理:释放系统吞吐潜力

1. 快速启用异步

@SpringBootApplication
@EnableAsync
public class MyApp {public static void main(String[] args) {SpringApplication.run(MyApp.class, args);}
}// 自定义线程池
@Configuration
public class AsyncConfig {@Bean(name = "asyncExecutor")public Executor asyncExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(100);executor.setThreadNamePrefix("Async-");executor.initialize();return executor;}
}

2. 异步方法实践

@Service
public class LogService {@Async("asyncExecutor")public CompletableFuture<Void> saveLogAsync(Log log) {// 模拟耗时操作Thread.sleep(1000);logRepository.save(log);return CompletableFuture.completedFuture(null);}@Asyncpublic void processInBackground() {// 无返回值的异步方法}
}// 调用示例
@RestController
public class LogController {@PostMapping("/logs")public Result<Void> addLog(@RequestBody Log log) {logService.saveLogAsync(log); // 异步执行return Result.success();}
}

六、实战项目:天气服务系统

1. 系统架构

weather-service (主模块)
├── 调用外部天气API
├── 定时缓存数据
├── 提供REST接口
│
common (公共模块)
├── 异常处理
├── 工具类

2. 核心代码片段

天气数据缓存:

@Cacheable(value = "weather", key = "#city")
public WeatherData getCachedWeather(String city) {return externalApiClient.getWeather(city);
}@Scheduled(fixedRate = 30 * 60 * 1000)
@CacheEvict(value = "weather", allEntries = true)
public void refreshCache() {log.info("清空天气缓存");
}

异步日志记录:

@Async
public void asyncAddAccessLog(HttpServletRequest request) {AccessLog log = new AccessLog();log.setPath(request.getRequestURI());log.setIp(request.getRemoteAddr());log.setCreateTime(LocalDateTime.now());logRepository.save(log);
}

七、避坑指南

1. 跨模块扫描问题:
- 主类添加@ComponentScan("com.example")
- 确保包结构有共同父包

2. RestTemplate单例问题:
- 推荐通过RestTemplateBuilder创建
- 为不同服务创建不同的RestTemplate实例

3. 定时任务阻塞:
- 默认使用单线程,长时间任务会影响其他任务
- 务必配置线程池

4. 异步失效场景:
- 同事务问题:自调用或private方法无效
- 异常处理:主线程无法捕获异步方法异常

八、明日计划

1. 学习SpringBoot Actuator监控
2. 集成Prometheus+Grafana
3. 实现健康检查与指标暴露
4. 探索SpringBoot Admin

思考题:在微服务架构下,如果天气服务和用户服务需要频繁通信,RestTemplate和WebClient哪种方式更适合?为什么?欢迎在评论区分享你的见解!

如果觉得这篇学习日记有帮助,请点赞收藏支持~完整天气服务示例代码可通过私信获取。在实际开发中遇到异步或定时任务问题也欢迎留言讨论!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/92597.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/92597.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机械学习--DBSCAN 算法(附实战案例)

DBSCAN 算法详解DBSCAN&#xff08;Density-Based Spatial Clustering of Applications with Noise&#xff0c;带噪声的基于密度的空间聚类应用&#xff09;是一种经典的密度聚类算法&#xff0c;由 Martin Ester 等人于 1996 年提出。与 K-means 等基于距离的聚类算法不同&am…

【昇腾】基于RK3588 arm架构Ubuntu22.04系统上适配Atlas 200I A2加速模块安装EP模式下的驱动固件包_20250808

一、背景 1.1 主要的硬件是&#xff1a;1.2 主要的软件是&#xff1a; RK3588跑操作系统Atlas 200I A2加速模块作为EP模式关键参数版本说明CPU架构aarch64OS版本Ubuntu 22.04.5 LTSkernel版本5.10.198 二、适配 准备固件run包文件&#xff1a;Ascend-hdk-310b-npu-firmware_7.…

如何在 VS Code 中进行 `cherry-pick`

cherry-pick 是 Git 的一个功能&#xff0c;允许你选择某个 commit 并将其应用到当前分支&#xff0c;而无需合并整个分支。在 VS Code 中&#xff0c;你可以通过 内置的 Git 功能 或 终端 来完成 cherry-pick。方法 1&#xff1a;使用 VS Code 的 Git 图形界面&#xff08;GUI…

STM32CubeMX(十三)FatFs文件系统(SPI驱动W25Qxx)

目录 一、知识点 1. 什么是Fatfs文件系统? 2. Fatfs操作系统控制流程 二、实战操作 1.CubeMX配置 2. 配置串口以及SPI 3. 修改功能映射接口 4. 添加测试代码 5. 实验现象 在完成本章之前需要完成一些基础配置,详情查看下面的文章。 STM32CubeMX(二)新建工…

【前端后端部署】将前后端项目部署到云服务器

更多笔记在这里☞ 全栈之路&#xff1a; https://gitee.com/oldbe/notes 【跳转到】 觉得有用请点个 star &#xff0c;非常感谢&#xff01; 现在AI太强大&#xff0c;开发个人产品的门槛和成本太低了&#xff0c;只要你有好的想法都可以很快速的开发一款产品 1.…

vue如何监听localstorage

在Vue中监听localStorage的变化可以通过几种方式实现&#xff0c;但需要注意的是&#xff0c;localStorage本身不提供原生的事件监听机制&#xff0c;如DOM元素的MutationObserver。不过&#xff0c;你可以通过一些间接的方法来监听localStorage的变化。方法1&#xff1a;使用w…

灰狼算法+四模型对比!GWO-CNN-LSTM-Attention系列四模型多变量时序预测

摘要&#xff1a;聚划算&#xff01;大对比&#xff01;灰狼算法四模型对比&#xff01;GWO-CNN-LSTM-Attention系列四模型多变量时序预测&#xff0c;该代码特别适合需要横向对比不同深度学习模型性能的时序预测场景&#xff0c;研究者可通过参数快速适配不同预测需求&#xf…

冒泡排序实现以及优化

一&#xff0c;冒泡排序说明冒泡排序是从第一个元素开始和后面一个元素进行判断是否满足左小右大&#xff0c;如果不满足就交换位置&#xff0c;再拿第二个和第三个进行上述操作一直到第n-1和第n个。经过上述的一轮操作就可以把第一个最大值放到最右边&#xff0c;在进行n轮上述…

水下管道巡检机器人cad【10张】三维图+设计说明书

摘 要 水下管道是水下油气管道的生命线&#xff0c;水下管道巡检机器人可以替代人工完成水下油气管道状态的实时监测和数据反馈&#xff0c;有助于工作人员对水下油气管道的运行情况实时掌握。 本文完成了水下管道巡检机器人的总体设计&#xff0c;采用三维设计软件Solidwor…

SQL(结构化查询语言)的四大核心分类

这张图展示了 SQL&#xff08;结构化查询语言&#xff09;的四大核心分类&#xff0c;分别对应不同的数据库操作场景。以下是逐类解析&#xff1a;1. 数据操作语言&#xff08;DML&#xff1a;Data Manipulation Language&#xff09;作用&#xff1a;用于操作数据库中的数据&a…

AI(1)-神经网络(正向传播与反向传播)

&#x1f34b;&#x1f34b;AI学习&#x1f34b;&#x1f34b;&#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一下博主…

嵌入式Linux学习 - 数据结构6

五、哈希表1. 哈希算法将数据通过哈希算法映射成一个键值&#xff0c;存取都在同一位置实现数据的高效存储和查找将时间复杂度尽可能降低至O(1)2. 哈希碰撞多个数据通过哈希算法得到的键值相同&#xff0c;称为产生哈希碰撞3. 哈希表构建哈希表存放0-100之间的数据将0 - 100之间…

GitHub 趋势日报 (2025年08月07日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图1894nautilus_trader354stagehand315openai-cookbook263sim242ollama230prisma154v…

android 使用openimagelib OpenImage 实现点击放大图片,浏览

在 Android 中使用 OpenImageLib(假设这是一个开源图片加载库,类似于 Glide 或 Picasso)实现 点击放大图片并浏览 的功能,通常需要结合 图片查看器库(如 PhotoView)和 图片加载库(如 OpenImageLib)。以下是完整的实现方案: 1. 添加依赖 (1) 添加 OpenImageLib 依赖 …

计算机视觉CS231n学习(4)

深度学习软件 &#xff08;这一部分去看tensorflow和pytorch的笔记&#xff09; &#xff08;见专栏&#xff09;tensorflow和pytorch区别 tensorflow&#xff0c;我们先构建显示的图&#xff0c;然后重复运行它 pytorch&#xff0c;我们每次做前向传播时&#xff0c;都构建一个…

【具身智能】具身智能的革命——人形机器人如何重塑人类日常生活

还在为高昂的AI开发成本发愁?这本书教你如何在个人电脑上引爆DeepSeek的澎湃算力! 2025年被誉为具身智能的元年,人形机器人技术迅猛发展,将深刻改变人类生活方式。本文从具身智能的核心概念入手,探讨人形机器人的硬件架构、感知系统、运动控制和决策算法等技术基础。结合…

Jira Service Management企业服务管理:IT、HR、法务、财务等部门如何落地现代企业服务管理理念与实践

Jira Service Management 服务管理方法Jira Service Management 服务管理方法将开发、IT运营和业务团队整合至一个统一平台&#xff0c;以实现更高效的协作。任何团队都能够快速响应业务变化&#xff0c;为客户和员工提供卓越体验。Jira Service Management 提供直观、经济高效…

软件开发 - danger 与 dangerous、warn 与 warning

danger 与 dangerous 1、danger词性&#xff1a;n.含义&#xff1a;指可能造成伤害或损失的情况或事物# 例词in 【danger】&#xff08;处于危险中&#xff09; out of 【danger】&#xff08;脱离危险&#xff09;# 例句After the surgery, the doctor said the patient was o…

为何毫米波需要采用不同的DPD方法?如何量化其值?

摘要 在5G新无线电技术标准中&#xff0c;除了sub-6 GHz频率外&#xff0c;还利用毫米波(mmWave)频率来提高吞吐量。毫米波频率的使用为大幅提高数据吞吐量带来了独特的机会&#xff0c;同时也带来了新的实施挑战。本文探讨sub-6 GHz和毫米波基站无线电之间的架构差异&#xff…

【数据结构入门】栈和队列的OJ题

目录 1. 有效的括号 分析&#xff1a; 代码&#xff1a; 2. 用队列实现栈 分析&#xff1a; 代码&#xff1a; 3. 用栈实现队列 分析&#xff1a; 代码&#xff1a; 4. 设计循环队列 思路&#xff1a; 代码&#xff1a; 定义循环队列结构体&#xff1a; 初始化结…