当前位置: 首页 > wzjs >正文

天成信息网站建设自助建站平台医疗器械龙头股

天成信息网站建设自助建站平台,医疗器械龙头股,wordpress手动更新,盐城网站优化摘要 本文是《Spring Boot 实战派》系列的第七篇,继续深入性能优化领域。文章将聚焦于解决两类常见的业务场景:耗时操作阻塞用户请求和周期性自动化任务。 我们将首先学习如何使用 Spring 的 Async 注解,将耗时操作(如发送邮件、…
摘要

本文是《Spring Boot 实战派》系列的第七篇,继续深入性能优化领域。文章将聚焦于解决两类常见的业务场景:耗时操作阻塞用户请求周期性自动化任务

我们将首先学习如何使用 Spring 的 @Async 注解,将耗时操作(如发送邮件、生成报表)从主请求线程中剥离,实现异步执行,从而做到接口的瞬时响应,极大提升用户体验。接着,我们会深入探讨如何配置和优化异步任务的线程池。随后,文章将详细讲解如何使用 @Scheduled 注解,轻松创建强大的定时任务,并详解 cron 表达式的用法,实现如“每天凌晨执行数据清理”等自动化需求。

系列回顾:
在上一篇中,我们通过整合 Redis 缓存,极大地提升了应用“读”的性能,让高频查询接口快如闪电。但是,应用的性能瓶颈不仅仅在“读”。想象一个用户注册的场景:用户点击“注册”按钮后,系统需要创建用户、发送欢迎邮件、初始化积分… 如果这些操作都在一个请求里同步完成,用户可能要盯着加载圈转好几秒,这种糟糕的体验足以劝退大量用户。

欢迎来到性能优化的第二站!

今天,我们要解决的核心问题是:如何优雅地处理那些“慢”操作,不让它们阻塞主流程,影响用户体验。 我们将学习 Spring Boot 提供的两个强大的“多线程”利器:@Async@Scheduled

  1. @Async (异步任务): 就像给耗时任务开了一个“VIP通道”。主线程把任务交给它之后,就可以立即返回,继续处理其他事情,而这个耗时任务则在后台的另一个线程里默默执行。
  2. @Scheduled (定时任务): 就像给应用设置了一个“智能闹钟”。你可以让它在指定的时间(如每晚12点)或按固定的频率(如每5分钟)自动执行某个任务,无需人工干预。

第一部分:异步的魔力 —— 使用 @Async 提升响应速度

场景:模拟用户注册后发送欢迎邮件

我们将创建一个用户注册接口。在用户数据成功存入数据库后,需要调用一个模拟的“邮件发送服务”。这个邮件服务会故意休眠3秒,来模拟网络延迟和SMTP服务器的处理耗时。

1. 开启异步功能

@EnableCaching 类似,我们需要一个注解来告诉 Spring 开启异步方法执行的支持。在主启动类 MyFirstAppApplication.java 或任何一个配置类上,添加 @EnableAsync

@SpringBootApplication
@EnableCaching
@EnableAsync // 开启异步方法执行支持
public class MyFirstAppApplication {public static void main(String[] args) {SpringApplication.run(MyFirstAppApplication.class, args);}
}

2. 创建一个模拟的邮件服务

service 包下,创建一个 EmailService.java

package com.example.myfirstapp.service;import com.example.myfirstapp.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;@Service
public class EmailService {private static final Logger log = LoggerFactory.getLogger(EmailService.class);@Async // 核心注解:将此方法标记为异步方法public void sendWelcomeEmail(User user) {log.info("开始向 {} 发送欢迎邮件...", user.getName());try {// 模拟耗时 3 秒Thread.sleep(3000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}log.info("欢迎邮件已成功发送至 {} !", user.getName());}
}

关键点:

  • @Async 注解被放在了 sendWelcomeEmail 方法上。当其他 Bean 调用这个方法时,Spring 会拦截这个调用,将它提交到一个后台线程池中执行,然后立即返回,调用方不会被阻塞。
  • 重要限制: 异步方法必须是 public 的。并且,在同一个类中的方法调用(this.someAsyncMethod())是不会触发异步的,因为它绕过了 Spring 的代理机制。必须是通过 Spring 注入的 Bean 进行调用。

3. 在注册逻辑中调用异步方法

我们将改造 UserService,在添加用户后,调用 EmailService

package com.example.myfirstapp.service;import com.example.myfirstapp.entity.User;
// ... 其他 import
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {// ...@Autowiredprivate EmailService emailService;public User registerUser(User user) {System.out.println("主线程:开始注册用户...");User savedUser = userRepository.save(user); // 同步保存用户emailService.sendWelcomeEmail(savedUser); // 异步发送邮件System.out.println("主线程:用户注册方法返回,无需等待邮件发送。");return savedUser;}// ... 其他方法
}

注意:为了演示,我们创建了一个新的 registerUser 方法。

4. 测试效果

创建一个新的注册接口,并用 Postman 测试。

  • UserController.java
    @PostMapping("/register")
    public Result<User> register(@RequestBody User user) {return Result.success(userService.registerUser(user));
    }
    

测试流程:

  1. 启动应用。
  2. 用 Postman 调用 POST /users/register,Body 中传入用户信息。
  3. 观察响应时间: 你会发现 Postman 几乎是瞬间就收到了响应。
  4. 观察控制台日志:
    主线程:开始注册用户...
    // 日志来自 EmailService,注意线程名不是 main
    [   task-1] c.e.m.service.EmailService      : 开始向 [用户名] 发送欢迎邮件... 
    主线程:用户注册方法返回,无需等待邮件发送。
    // 3秒后...
    [   task-1] c.e.m.service.EmailService      : 欢迎邮件已成功发送至 [用户名] !
    

日志清晰地显示,主线程在调用邮件服务后立即返回,而邮件发送的逻辑则在另一个名为 task-1 的线程中执行。我们成功地释放了主线程!

进阶:自定义异步线程池

Spring Boot 的默认异步线程池核心线程数为8,队列无限大。在生产环境中,这可能导致内存溢出。我们通常需要自定义线程池。

config 包下创建 AsyncConfig.java

package com.example.myfirstapp.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;@Configuration
public class AsyncConfig {@Bean(name = "taskExecutor")public Executor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5); // 核心线程数executor.setMaxPoolSize(10); // 最大线程数executor.setQueueCapacity(25); // 任务队列容量executor.setThreadNamePrefix("MyAsync-"); // 线程名前缀executor.initialize();return executor;}
}

@Async 注解中,你可以指定使用这个线程池:@Async("taskExecutor")


第二部分:自动化的节拍 —— 使用 @Scheduled 创建定时任务

场景:创建一个每分钟打印一次当前时间的定时任务

这在很多场景都很有用,比如:

  • 每天凌晨1点,进行数据备份和清理。
  • 每小时,同步一次外部数据。
  • 每5分钟,检查一次系统健康状况并发送报告。

1. 开启定时任务功能

在主启动类或任何配置类上,添加 @EnableScheduling 注解。

@SpringBootApplication
@EnableCaching
@EnableAsync
@EnableScheduling // 开启定时任务支持
public class MyFirstAppApplication {// ...
}

2. 创建定时任务类

创建一个新的 servicetask 包,在其中创建 ScheduledTasks.java

package com.example.myfirstapp.task;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;@Component
public class ScheduledTasks {private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");/*** 使用 fixedRate,表示每隔 60 秒执行一次。* 从上一次任务开始时计时。*/@Scheduled(fixedRate = 60000)public void reportCurrentTime() {log.info("现在时间是 (fixedRate): {}", formatter.format(LocalDateTime.now()));}/*** 使用 cron 表达式,表示每分钟的第 0 秒执行(即每分钟的开始)。* 这是最常用和最强大的方式。*/@Scheduled(cron = "0 * * * * ?")public void reportCurrentTimeWithCron() {log.info("现在时间是 (cron): {}", formatter.format(LocalDateTime.now()));}
}

注解解读:

  • @Scheduled: 核心注解,标记这是一个定时任务。
  • fixedRate = 60000: 表示任务执行的固定频率,单位是毫秒。无论上一次任务执行了多久,下一次任务都会在上一次任务开始后的60秒后启动。
  • fixedDelay = 60000: 与 fixedRate 类似,但它是从上一次任务结束后开始计时。如果任务执行耗时5秒,那么下一次任务将在65秒后启动。
  • cron = "0 * * * * ?": 使用 Cron 表达式,提供了极高的灵活性。

Cron 表达式详解 (从左到右):
秒 分 时 日 月 周

  • * : 匹配任意值。
  • ? : 只能用在“日”和“周”字段,表示不指定值。
  • / : 表示步长。0/15 在“秒”字段表示每15秒执行一次(0, 15, 30, 45)。
  • , : 列出枚举值。MON,WED,FRI 在“周”字段表示周一、周三、周五。
  • - : 表示范围。9-17 在“时”字段表示从9点到17点。

常用 Cron 表达式示例:

  • 0 0 1 * * ? : 每天凌晨1点执行。
  • 0 0/30 9-17 * * ? : 每天9点到17点之间,每半小时执行一次。
  • 0 15 10 ? * MON-FRI : 每周一至周五的上午10点15分执行。

3. 运行并观察日志

重启应用,你不需要做任何操作。静静地观察控制台日志,你会发现每隔一分钟,ScheduledTasks 里的方法就会被自动执行,并打印出当前时间。

注意: 默认情况下,所有 @Scheduled 任务共享同一个单线程。如果一个任务执行时间过长,会阻塞其他任务。如果你的定时任务很多或很耗时,建议像配置异步任务一样,配置一个专门的定时任务线程池。


总结与展望

今天,我们为应用赋予了“分身”和“自律”的能力,学会了:

  • 使用 @Async 将耗时操作异步化,实现了接口的快速响应,极大地提升了用户体验。
  • 如何自定义异步任务线程池,以适应生产环境的需求。
  • 使用 @Scheduled 和强大的 Cron 表达式,创建了灵活可靠的定时任务,实现了应用的自动化运维。

至此,我们的应用不仅在功能、安全、配置上趋于完善,在性能表现和架构合理性上也迈上了一个新台阶。

接下来,我们将进入微服务的前哨站。一个现代化的应用,很少是孤立存在的,它需要与系统中的其他服务进行通信。在下一篇 《【微服务基石篇】服务间的对话:RestTemplate、WebClient 与 OpenFeign 对比与实战》 中,我们将学习 Spring Boot 中进行服务间 HTTP 调用的三种主流方式,为你踏入微服务世界做好最充分的准备。我们下期见!

http://www.dtcms.com/wzjs/73076.html

相关文章:

  • 做网站模板的软件友情链接交换系统
  • 中山网站建设哪家好四川seo关键词工具
  • 装修公司怎么做网站推广手机端怎么刷排名
  • 中国建设招标网是什么网站seo教程 seo之家
  • b2b电子商务网站注册拉新任务接单放单平台
  • 网站建设怎么外包好武汉刚刚突然宣布
  • 海口建设厅网站做整站优化
  • 个人做网站用哪个主机好百度度小店申请入口
  • wordpress解压后怎么安装百度搜索关键词排名优化
  • 邵阳网页seo技术好的培训机构
  • 做封面字体下载好的网站河南靠谱seo地址
  • 东莞网站优化的具体方案重庆做网络优化公司电话
  • 怎么自己做推广网站seo推广一年要多少钱
  • 天津开发区网站微信crm系统
  • 建设一个网站需要什么百度如何收录网站
  • 成品网站源码在线百度新版本更新下载
  • 南昌网站设计哪家专业好广告词
  • 新手怎么做淘宝店铺汕头seo代理商
  • 如何办网站北京百度推广代理公司
  • 专业做校园文化的网站seo建站技巧
  • wordpress怎么登录界面太原百度网站快速优化
  • wordpress实现多重筛选5g站长工具seo综合查询
  • 重庆网站建设策划网站推广网络推广
  • 怎么做网站的用户注册直通车关键词优化
  • 专题网站开发工具有哪些无锡百度关键词优化
  • 网站服务器空间价格seo课程培训视频
  • 绍兴网站建设报价百度网页版入口
  • 建公司网站要多少钱代发百度关键词排名
  • 万州集团网站建设百度站长平台app
  • 一个人做两个博客网站深圳网络推广软件