SpringBoot3进阶用法

news2024/10/7 18:25:00

标签:切面.调度.邮件.监控;

一、简介

在上篇《SpringBoot3基础》中已经完成入门案例的开发和测试,在这篇内容中再来看看进阶功能的用法;

主要涉及如下几个功能点:

调度任务:在应用中提供一定的轻量级的调度能力,比如方法按指定的定时规则执行,或者异步执行,从而完成相应的代码逻辑;

邮件发送:邮件作为消息体系中的渠道,是常用的功能;

应用监控:实时或定期监控应用的健康状态,以及各种关键的指标信息;

切面编程:通过预编译方式和运行期动态代理实现程序中部分功能统一维护的技术,可以将业务流程中的部分逻辑解耦处理,提升可复用性;

二、工程搭建

1、工程结构

2、依赖管理

<!-- 基础框架依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>${spring-boot.version}</version>
</dependency>

<!-- 应用监控组件 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>${spring-boot.version}</version>
</dependency>

<!-- 切面编程组件 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    <version>${spring-boot.version}</version>
</dependency>

<!-- 邮件发送组件 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
    <version>${spring-boot.version}</version>
</dependency>

这里再细致的查看一下各个功能的组件依赖体系,SpringBoot只是提供了强大的集成能力;

3、启动类

注意在启动类中使用注解开启了异步EnableAsync和调度EnableScheduling的能力;

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

三、切面编程

1、定义注解

定义一个方法级的注解;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface DefAop {
    /**
     * 模块描述
     */
    String modelDesc();

    /**
     * 其他信息
     */
    String otherInfo();
}

2、注解切面

在切面中使用Around环绕通知类型,会拦截到DefAop注解标记的方法,然后解析获取各种信息,进而嵌入自定义的流程逻辑;

@Component
@Aspect
public class LogicAop {

    private static final Logger logger = LoggerFactory.getLogger(LogicAop.class) ;
    
    /**
     * 切入点
     */
    @Pointcut("@annotation(com.boot.senior.aop.DefAop)")
    public void defAopPointCut() {

    }

    /**
     * 环绕切入
     */
    @Around("defAopPointCut()")
    public Object around (ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object result = null ;
        try{
            // 执行方法
            result = proceedingJoinPoint.proceed();
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            // 处理逻辑
            buildLogicAop(proceedingJoinPoint) ;
        }
        return result ;
    }

    /**
     * 构建处理逻辑
     */
    private void buildLogicAop (ProceedingJoinPoint point){
        // 获取方法
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method reqMethod = signature.getMethod();

        // 获取注解
        DefAop defAop = reqMethod.getAnnotation(DefAop.class);
        String modelDesc = defAop.modelDesc() ;
        String otherInfo = defAop.otherInfo();
        logger.info("DefAop-modelDesc:{}",modelDesc);
        logger.info("DefAop-otherInfo:{}",otherInfo);
    }
}

四、调度任务

1、异步处理

1.1 方法定义

通过Async注解标识两个方法,方法在执行时会休眠10秒,其中一个注解指定异步执行使用asyncPool线程池;

@Service
public class AsyncService {

    private static final Logger log = LoggerFactory.getLogger(AsyncService.class);

    @Async
    public void asyncJob (){
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("async-job-01-end...");
    }

    @Async("asyncPool")
    public void asyncJobPool (){
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("async-job-02-end...");
    }
}

1.2 线程池

定义一个ThreadPoolTaskExecutor线程池对象;

@Configuration
public class PoolConfig {

    @Bean("asyncPool")
    public Executor asyncPool () {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 线程池命名前缀
        executor.setThreadNamePrefix("async-pool-");
        // 核心线程数5
        executor.setCorePoolSize(5);
        // 最大线程数10
        executor.setMaxPoolSize(10);
        // 缓冲执行任务的队列50
        executor.setQueueCapacity(50);
        // 线程的空闲时间60秒
        executor.setKeepAliveSeconds(60);
        // 线程池对拒绝任务的处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 线程池关闭的时等待所有任务都完成再继续销毁其他的Bean
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 设置线程池中任务的等待时间
        executor.setAwaitTerminationSeconds(300);
        return executor;
    }
}

1.3 输出信息

从输出的日志信息中可以发现,两个异步方法所使用的线程池不一样,asyncJob采用默认的cTaskExecutor线程池,asyncJobPool方法采用的是async-pool线程池;

[schedule-pool-1] c.boot.senior.schedule.ScheduleService   : async-job-02-end...
[cTaskExecutor-1] c.boot.senior.schedule.ScheduleService   : async-job-01-end...

2、调度任务

2.1 调度配置

通过实现SchedulingConfigurer接口,来修改调度任务的配置,这里重新定义任务执行的线程池;

@Configuration
public class ScheduleConfig implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));
    }
}

2.2 调度方法

通过Scheduled注解来标记方法,基于定时器的规则设定,来统一管理方法的执行时间;

@Component
public class ScheduleJob {
    private static final Logger log = LoggerFactory.getLogger(ScheduleJob.class);

    private static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") ;

    /**
     * 上一次开始执行时间点之后10秒再执行
     */
    @Scheduled(fixedRate = 10000)
    private void timerJob1(){
        log.info("timer-job-1:{}",format.format(new Date()));
    }

    /**
     * 上一次执行完毕时间点之后10秒再执行
     */
    @Scheduled(fixedDelay = 10000)
    private void timerJob2(){
        log.info("timer-job-2:{}",format.format(new Date()));
    }

    /**
     * Cron表达式:每30秒执行一次
     */
    @Scheduled(cron = "0/30 * * * * ?")
    private void timerJob3(){
        log.info("timer-job-3:{}",format.format(new Date()));
    }
}

五、邮件发送

1、邮件配置

采用QQ邮箱来模拟邮件的发送方,需要先开启smtp邮件传输协议,在QQ邮箱的设置/账户路径下,并且获取相应的授权码,在项目的配置中使用;

spring:
  application:
    name: boot-senior
  # 邮件配置
  mail:
    host: smtp.qq.com
    port: 465
    protocol: smtps
    username: 邮箱账号
    password: 邮箱授权码
    properties:
      mail.smtp.ssl.enable: true

2、方法封装

定义一个简单的邮件发送方法,并且可以添加附件,是常用的功能之一;另外也可以通过Html静态页渲染,再转换为邮件内容的方式;

@Service
public class SendMailService {

    @Value("${spring.mail.username}")
    private String userName ;

    @Resource
    private JavaMailSender sender;

    /**
     * 带附件的邮件发送方法
     * @param toUsers 接收人
     * @param subject 主题
     * @param content 内容
     * @param attachPath 附件地址
     * @return java.lang.String
     * @since 2023-07-10 17:03
     */
    public String sendMail (String[] toUsers,String subject,
                            String content,String attachPath) throws Exception {
        // MIME邮件类
        MimeMessage mimeMessage = sender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
        // 邮件发送方From和接收方To
        helper.setFrom(userName);
        helper.setTo(toUsers);
        // 邮件主题和内容
        helper.setSubject(subject);
        helper.setText(content);
        // 邮件中的附件
        File attachFile = ResourceUtils.getFile(attachPath);
        helper.addAttachment(attachFile.getName(), attachFile);
        // 执行邮件发送命令
        sender.send(mimeMessage);
        return "send...mail...sus" ;
    }
}

测试结果

六、应用监控

1、监控配置

springbootactuator组件中,可以通过提供的Rest接口,来获取应用的监控信息;

# 应用监控配置
management:
  endpoints:
    web:
      exposure:
        # 打开所有的监控点
        include: "*"
      base-path: /monitor
  endpoint:
    health:
      enabled: true
      show-details: always
    beans:
      enabled: true
    shutdown:
      enabled: true

2、相关接口

2.1 Get类型接口:主机:端口/monitor/health,查看应用的健康信息,三个核心指标:status状态,diskSpace磁盘空间,ping检查;

{
    /* 状态值 */
	"status": "UP",
	"components": {
	    /* 磁盘空间 */
		"diskSpace": {
			"status": "UP",
			"details": {
				"total": 250685575168,
				"free": 112149811200,
				"threshold": 10485760,
				"path": "Path/butte-spring-parent/.",
				"exists": true
			}
		},
		/* Ping检查 */
		"ping": {
			"status": "UP"
		}
	}
}

2.2 Get类型接口:主机:端口/monitor/beans,查看bean列表;

{
	"contexts": {
		"boot-senior": {
			"beans": {
				"asyncPool": {
					"scope": "singleton",
					"type": "org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor",
					"resource": "class path resource [com/boot/senior/schedule/PoolConfig.class]"
				},
				"asyncService": {
					"scope": "singleton",
					"type": "com.boot.senior.schedule.AsyncService$$SpringCGLIB$$0"
				}
			}
		}
	}
}

2.3 Post类型接口:主机:端口/monitor/shutdown,关闭应用程序;

{
    "message": "Shutting down, bye..."
}

E N D END END

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

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

相关文章

AcWing 93:递归实现组合型枚举 ← DFS

【题目来源】https://www.acwing.com/problem/content/95/【题目描述】 从 1∼n 这 n 个整数中随机选出 m 个&#xff0c;输出所有可能的选择方案。【输入格式】 两个整数 n&#xff0c;m&#xff0c;在同一行用空格隔开。【输出格式】 按照从小到大的顺序输出所有方案&#xf…

uniapp根据高度表格合并

没有发现比较友好的能够合并表格单元格插件就自己简单写了一个,暂时格式比较固定 一、效果如下 二、UI视图+逻辑代码 <template><view><uni-card :is-shadow="false" is-full

怎么把CAD高版本转低版本?CAD版本转换方法分享

CAD文件版本转换通常是为了确保更高版本的CAD软件能够打开旧版本的文件。此外&#xff0c;不同版本的CAD软件可能具有不同的功能&#xff0c;因此转换文件版本可以确保可以在任何版本的软件中使用文件。此外&#xff0c;如果我们需要与其他人共享文件&#xff0c;则需要将文件转…

基于EEGLAB的ICA分析

目录 1.ICA原理 2.ICA的实现 3.ICA成分识别 4.ICLabel识别并去除伪迹 5.ICA成分识别练习 1.ICA原理 得到的每一个地形图&#xff0c;实际上就是它的权重谱。 投射&#xff1a;根据原成分恢复原始信号。 选择性投射&#xff1a;去伪。 2.ICA的实现 extended&#xff0c;1&…

bigemap如何添加在线地图源?

第一步 打开浏览器&#xff0c;找到你要访问的地图的URL地址&#xff0c;并且确认可以正常在浏览器中访问&#xff1b;浏览器中不能访问&#xff0c;同样也不能在软件中访问。 以下为常用地图源地址&#xff1a; 天地图&#xff1a; http://map.tianditu.gov.cn 包含&a…

小程序的api使用 以及一些weui组件实列获取头像 扫码等

今日目标 响应式单位rpx小程序的生命周期 【重点】20%小程序框架 weui 【重点】 50%内置API 【重点】30%综合练习 1. 响应式rpx 1.1 rpx单位 rpx是微信小程序提出的一个尺寸单位&#xff0c;将整个手机屏幕宽度分为750份&#xff0c;1rpx 就是 1/750&#xff0c;避免不同手…

知网期刊《中阿科技论坛》简介及投稿须知

知网期刊《中阿科技论坛》简介及投稿须知 主管单位&#xff1a;宁夏回族自治区科学技术厅 主办单位&#xff1a;宁夏回族自治区对外科技交流中心(中国一阿拉伯国家技术转移中心) 刊  期&#xff1a;月刊 国际刊号&#xff1a;ISSN 2096-7268 国内刊号&#xff1a;CN 64-…

一场大规模山体滑坡摧毁了世界最高峰之一

安纳普尔纳四号峰在喜马拉雅山山体滑坡中倒塌&#xff0c;科学家们终于弄清楚了它发生的时间和方式。 现今尼泊尔安纳普尔纳四号峰的景色&#xff0c;展示了中世纪时期倒塌的面貌。图片来源&#xff1a;Jrme Lav 山为什么不会永远生长&#xff1f;碰撞的构造板块不断地将山脉推…

下载网络文件到本地

文章目录 目录 前言 操作步骤 1.引入 2.读取出文件内容 3.筛选出URL 4.下载表情包 总结 前言 这里记录一次用代码下载网络文件的过程&#xff0c;以获取抖音表情包为例。 一、操作步骤 1.引入 首先抖音有网页版&#xff0c;用浏览器就可以观看&#xff0c;用户评论发布表情在…

《Vue.js实战》——基础篇(1)

目录 资源&#xff1a;&#x1f31f; 一、初识Vue.js&#x1f44b; Vue.js是什么&#xff1f;&#x1f647; MVVM模式 ✍ Vue.js有什么不同 ☔ 如何使用Vue.js? ☁ 传统的前端开发模式 ☀ Vue.js的开发模式 &#x1f5fb; 二、数据绑定和第一个Vue应用 &#x1f5f…

嵌入式开发学习(STC51-16-ADC模数转换)

内容 通过ADC转换电路采集电位器AD值&#xff0c;将采集的AD值转换成电压值&#xff0c;通过数码管显示出来&#xff1b; 采集光敏电阻的AD值&#xff1b; 采集热敏电阻的AD值&#xff1b; 采集外部通道AIN3的电压值&#xff1b; 为了方便显示&#xff0c;我们可以通过独立…

NeRF室内重建对比:Nerfstudio vs. Luma AI vs. Instant-NGP

十年前&#xff0c;Matterport 改变了房地产业&#xff0c;让房地产买家可以进行数字旅游。 买家可以在房产内从一个点移动到另一个点并环顾四周。 与 2D 照片库相比&#xff0c;这是一个巨大的改进。 然而&#xff0c;买家仍然被房产内的一系列问题所困扰。 推荐&#xff1a;用…

程序员必读 | 《业务架构解构与实践》

之前看书大多"不求甚解", 意会即可&#xff0c;但是找一本新书看是可遇而不可求的。回过头来&#xff0c;摘抄研究一下已经看过的&#xff0c;也是别有一番风味的。本文就是对之前一本书的摘录。 文章中各种暗淡不一的图片&#xff0c;其实是在各种环境下&#xff0c…

Java中Date方法详解

先进行专栏介绍 本专栏是自己学Java的旅途&#xff0c;纯手敲的代码&#xff0c;自己跟着黑马课程学习的&#xff0c;并加入一些自己的理解&#xff0c;对代码和笔记 进行适当修改。希望能对大家能有所帮助&#xff0c;同时也是请大家对我进行监督&#xff0c;对我写的代码进行…

耗时6个月,我做了一款干净、免费、开源的AI数据库

一、Chat2DB简介 在消失的这段时间&#xff0c;我做了一款集成了AI的数据库管理工具Chat2DB。 他是数据库也集成了AIGC的能力&#xff0c;能够将自然语言转换为SQL&#xff0c;也可以将SQL转换为自然语言&#xff0c;还可以给出SQL的优化建议&#xff0c;可以极大提升效率。 …

使用RecyclerView构建灵活的列表界面

使用RecyclerView构建灵活的列表界面 1. 引言 在现代移动应用中&#xff0c;列表界面是最常见的用户界面之一&#xff0c;它能够展示大量的数据&#xff0c;让用户可以浏览和操作。无论是社交媒体的动态流、商品展示、新闻列表还是任务清单&#xff0c;列表界面都扮演着不可或…

智慧城市规划新引擎:探秘数字孪生中的二维与三维GIS技术差异

智慧城市作为人类社会发展的新阶段&#xff0c;正日益引领着我们迈向数字化未来的时代。在智慧城市的建设过程中&#xff0c;地理信息系统&#xff08;GIS&#xff09;扮演着举足轻重的角色。而在GIS的发展中&#xff0c;二维和三维GIS作为两大核心技术&#xff0c;在城市规划与…

LeetCode 周赛 340,质数 / 前缀和 / 极大化最小值 / 最短路 / 平衡二叉树

今天讲 LeetCode 单周赛第 340 场&#xff0c;今天状态不好&#xff0c;掉了一波大分。 2614. 对角线上的质数&#xff08;Easy&#xff09; 这道题是最近第 2 次出现质数问题&#xff0c;注意 1 不是质数&#xff01; 质数判断&#xff1a;$O(n\sqrt(U))$ 2615. 等值距离和…

程序员吐槽培训班简历造假,经验包装竟拿到阿里外包26k的offer

关于程序员速成培训班的传言和八卦很多&#xff0c;近日&#xff0c;又有一个程序员发帖吐槽培训班简历造假&#xff0c;两个大四学生报了个培训班&#xff0c;竟然给包装成有三年工作经验的人&#xff0c;更离谱的是&#xff0c;竟然还拿到了阿里外包26k的offer…… 许多网友表…

数据结构---查找

&#x1f31e;欢迎来到数据结构的世界 &#x1f308;博客主页&#xff1a;卿云阁 &#x1f48c;欢迎关注&#x1f389;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f31f;本文由卿云阁原创&#xff01; &#x1f64f;作者水平很有限&#xff0c;如果发现错误&#xff…