一、SpringBoot实用开发篇
1.热部署
当你修改代码后,无需重新启动项目就能实现项目的实时变化称为热部署
(1).热部署流程
1. 添加热部署依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
2. 修改完代码后点击 快捷键 Ctrl + F9
(2).关于热部署(快捷)
①:重启 (Restart): 自定义开发代码,包含类、页面、配置文件等,加载位置restart类加载器
②:重载 (ReLoad): jar包,加载位置base类加载器
③: 开启开发者工具后启用热部署
④: 使用构建项目操作启动热部署 (ctrl+F9 )
⑤: 热部署仅仅加载当前开发者自定义开发的资源,不加载iar资源
本质上重启程序和热部署的重建项目底层做的事情是不同的。
不过尽管如此,还是觉得重新启动程序和热部署都需要点击。 那么如何才能更加的智能方便呢?
勾选如下选项
当你如上配置完热部署之后、离开IDEA页面 5秒 它就会自动再次部署程序。
(3).修改热部署的"作用域"
4. Java后端的代码包括配置yml文件会参与热部署,而前端页面当中,也就是静态资源的改变并不需要参与热部署,保存之后就可以直接刷新内容。
我们也可以自由选择哪些文件参与热部署,哪些不参与。
在application.yml配置中
devtools:
restart:
exclude: static/**,public/**,config/application.yml
(4). 如何关闭热部署?
仅仅依靠在配置文件中使用指令是没有办法保证完全关闭热部署的,如下
在application.yml配置中
devtools:
restart:
enabled: false
因为文件之间都存在着优先级,而优先级高的文件还是无法被关闭,因此我们可以在启动项当中关闭。
@SpringBootApplication
public class SSMPApplication{
public static void main(String args){
System.setProperty("spring.devtools.restart.enabled","false");
SpringApplication.run(SSMPApplication.class)
}}
2.配置高级
(1).第三方Bean属性绑定
@EnableConfigurationProperties注解可以将使用@ConfigurationProperties注解对应的类加入Spring容器
@EnableConfigurationProperties与@ConfigurationProperties不能同时使用
前者的好处? EnableConfigurationProperties清晰的指出了参与属性配置的类、这样方便你统一管理
①:宽松绑定
@ConfigurationProperties
绑定属性支持属性名宽松绑定 @Value就不持支
②:常用计量单位应用
③:数据校验
开启数据校验有助于系统安全性,J2EE规范中JSR303规范定义了一组有关数据校验相关的API
导入依赖:
<!-- 导入JSR303规范-->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<!--使用hibernate框架提供的校验器-->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
使用注解
③:进制数据转换规则
3.测试
(1).加载测试专用属性
加载测试范围配置应用与小范围测试,它会加载src中的文件,用来测试类的运行
在测试类旁边加入属性将内容设置为 yml 文件中的属性再赋值,如此一来该属性就可以在测试类中进行调用了。
注释中赋值 与 yml文件中赋值可以同时存在,但是前者的赋值会覆盖后者
测试类注释中也有与运行类相同的 args 字符串数组
优先级: args > properties > yml
使用@Import注解加载当前测试类专用配置 可以加载第三方Bean属性
(2).测试类中启动web环境(虚拟请求状态匹配)
每次启动的端口号都是随机的,整个环境也是模拟环境
如果报错则出现下列信息:
(3).请求匹配响应体、请求头等
例子中使用的是String类型,但是我们都知道实际开发中前后端传输的通常都是JSON格式
(4).业务层测试事务回滚
我们在做项目的时候,使用test类来测试程序效果的时候,难免会对数据库发生改动。这在实际开发中是不允许的,
(5).随机数据测试
测试用例设置随机数据、random中有提供限制参数大小之类的对象
4.数据层解决方案
(1).SQL
①:数据源配置
现有数据层解决方案技术选型: Druid + MyBatis-Plus + MySQL
SpringBoot提供了三种内嵌的数据源对象供开发者选择:
①:HikariCP: 默认内置数据源对象
②:Tomcat提供DataSource: HikariP不可用的情况下,目在web环境中,将使用tomcat服务器配置的数据源对象
③:Commons DBCP: Hikari不可用,tomcat数据源也不可用,将使用dbcp数据源
②:.JdbcTemplate
内置的持久化解决方案
需要导入依赖
③:内嵌数据库(H2)
配置好后在浏览器中输入 localhost/h2 便可以进入可视化管理页面
SpringBoot提供了3种内嵌数据库供开发者选择,提高开发测试效率
H2
HSQL
Derby
设置当前项目为web工程,并配置H2管理控制台参数 用户名默认 sa 默认密码 123456
server:
port: 80
spring:
h2:
console:
enabled: true
path: /h2
server:
port: 8080
datasource:
url: jdbc:h2:~/test
username: sa
password: 123456
(1).NoSQL
市面上常见的NoSQL解决方案
Redis 、 Mongo 、 ES
①:Redis
回头我会另开一篇博客
Redis是一款key-value存储结构的内存级NoSQL数据库
支持多种数据存储格式、支持持久化、支持集群
导入redis对应starter依赖
<!--redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--jedis依赖-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
首先需要先启动redis、再到yml中配置redis的host与port端口 Redis默认6379
spring:
redis:
host: 192.168.5.128
port: 6379
client-type: jedis
在Springboot中调用Redis方法跟JDBC一样需要先建立一个对象,然后再使用对象.ops来选择各种数据存储类型的接口API创建一个新对象
这个对象之后就可以使用该类型的不同方法来存取数据等等操作。
MySQL能够提供结构化的数据、可是响应速度慢
Redis响应速度很快、可是却没有结构化的数据
此时我们需要用到
②:MongoDB
MongoDB是一个开源、高性能、无模式的文档型数据库。NOSQL数据库产品中的一种,是最像关系型数据库的非关系型数据库
什么数据适合使用MongoDB来存储、比如直播间人气、打赏数据、游戏道具数据。这种一旦使用会频繁改变的数据。
如果存放在MySQL,那每秒钟执行的CURD影响太大了
5.整合第三方技术
(1).缓存
缓存是一种介于数据永久存储介质与数据应用之间的数据临时存储介质
使用缓存可以有效的减少低速数据读取过程的次数(例如磁盘10),提高系统性能
缓存不仅可以用于提高永久性存储介质的数据读取效率,还可以提供临时的数据存储空间
①:缓存使用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
之后还需要再项目运行类上方写入 @EnableCaching
注释启用缓存
最终在Controller层处理器方法上方写入 @Cacheable()
注释,这个注释有两个形参
第一个形参value表示你存放数据空间的名字,还有一个key。采用截图中 #变量名
的方式当作key
它能够将方法返回值存入Cache
···
开启@Cahceable
缓存了之后,我们执行这个搜索操作。第一次会与数据库产生交互,之后将查询到的数据自动存入缓存。
第二次再调用的时候就会自动从缓存中调用出来,不会与数据库产生交互。但是并不是每个业务都适合,那有什么办法可以
只存但是第二次查询的时候不取呢?
答案是@CachePut
它的形参与@Cacheable
是相同的
···
举个栗子: 很多网站注册需要手机验证码,当验证码发送给你之后,它如果使用@Cacheable存到缓存,那么你第二次再让它发送验证码岂不是重复了吗?然而现实中这是不可能的。所以我们使用@Cacheput,将验证码存起来,但是并不能取出来。当用户输入了验证码之后呢,就可以用缓存中的验证码来比较用户输入的验证码是否正确。
SpringBoot提供的缓存技术除了提供默认的缓存方案,还可以对其他缓存技术进行整合,统一接口,方便缓存技术
的开发与管理。SpringBoot整合了非常多中缓存技术但缺缺少了一个 memcached
技术
那整合到底有什么好处呢? 更换缓存技术并不会对源码造成影响!
②:缓存使用中存在的错误💢
这是项目Controller层的其中一个控制类,checkcode方法当中直接调用get是得到的值是null,是不是因为在同一个类中直接调用方法,是不会走IOC容器的,会直接调用。所以get方法的注释也失效了。
所以需要放到其他类让spring加载对象到容器当中,我修改代码为String cacheCode = 类.get(smsCode.getTele());。这样才能够有效启动注释,
如果我改为String cacheCode = 当前类.get(smsCode.getTele());同样也不会走IOC容器
@Cacheput 注释中的内容取出来,可以写一个方法,返回类型可以是存储类型。return 返回类型,或者return null
③:Ehchahe缓存
首先添加依赖ehcache
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
在yml文件中配置缓存为ehcache
spring:
cache:
type: ehcache
ehcache:
config: ehcache.xml
配置你的eacache文件
ehcache使用配置文件来做的缓存方案、Redis是直接在yml中配置
④:关于LRU、LFU的淘汰机制
假设我们cache中存在四个key、每秒访问一个、上方记录访问次数,下方访问最后一次访问的秒数。最终得到下图
LRU: 将距离目前最久没有运行的key淘汰,如图name 9秒才使用的内容是离目前最近一次使用的。age 5秒是缓存中最早前才用过一次的数据。所以淘汰age
LFU: 将目前使用次数最少的key淘汰,这个最好理解。用的少就别放进cache,换频繁使用的key进来
⑤:缓存供应商:jetcache
jetCache对SpringCache进行了封装,在原有功能基础上实现了多级缓存、缓存统计、自动刷新、异步调用、数据报表等功能
两两组合任意搭配
还是经典加依赖、不过此处需要加版本,因为springboot本身已经提供了一种方案。这里没有整合jetcache所以需要自己加版本
<dependency>
<groupId>com.alicp.jetcache</groupId>
<artifactId>jetcache-starter-redis</artifactId>
<version>2.6.2</version>
</dependency>
yml配置
测试类上方加入 @EnableCreateCacheAnnotation
(2).任务
定时任务是企业应用中常见的操作
年度报表、缓存统计报告
本质上就是个线程、能提供的方法也相当有限,因此市面上有开拓了一些更精致的定时任务技术
Quartz 、 Spring Task
①:相关概念
专用词 | 相关概念 |
---|---|
工作(Job) | 用于定义具体执行的工作 |
工作明细(JobDetail) | 用于描述定时工作相关的信息 |
触发器(Trigger) | 用于描述触发工作的规则,通常使用cron表达式定义调度规则 |
调度器(Scheduler) | 描述了工作明细与触发器的对应关系 |
②:整合步骤
加入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
<scope>test</scope>
</dependency>
任务类、里面书写你的工作
配置类,
下方的写法只是一个基础格式、使用链式编程、你输入一个.就可以看到各种方法,根据自己需求使用
一眼就能感受到,这个任务的配置是非常的墨迹, 所以我们使用以下的快速版本
①:加入@EnableScheduling
注释
①:创建一个任务配置类,不同的任务上面加入@Scheduled,并且写入不同的cron表达式
(3).整合JavaMail
加入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
在application.yml中配置你的账号密码以及服务
编写service接口与实例
测试类调用
包括网络图片等
发送附件
(4).消息
①:相关概念
消息发送方: 生产者
消息接收方: 消费者
同步消息: 生产者发送之后需等待
消费者回应才能继续发送消息
异步消息: 生产者发送之后无需等待
消费者回应就能继续发送消息
企业级应用中广泛使用的三种异步消息传递技术
①:JMS: 一个规范、等同于JDBC规范、提供了与消息服务相关的API接口
JMS消息模型: 两种
-peer-2-peer: 点对点模型
,消息发送到一个队列中,队列保存信息。队列的消息只能被一个消费者消费,或超时
-publish-subscribe: 发布订阅模型
,消息可以被多个消费者消费,生产者和消费者完全独立,不需要感知对方的存在
JMS消息种类:
TextMessage、 MapMessage、 BytesMessage
、 StreamMessage、 ObjectMessage、 Message(只有消息头和属性)
②:AMQP: 一种协议 (高级消息队列协议,也是消息代理规范),规范了网络交换的数据格式,兼容JMS
优点: 具有跨平台性,服务器供应商,生产者,消费者可以使用不同的语言来实现
AMOP消息模型
direct exchange
fanout exchange
topic exchange
headers exchange
system exchange
AMOP消息种类: byte[]
AMQP的存在相当于统一了世界使用的语言
**③:MQTT:**消息队列遥测传输,专为小设备设计,是物联网(IOT)
生态系统中主要成分之一
(5).监控
①:监控的意义
监控服务状态是否宕机
监控服务运行指标(内存、虚拟机、线程、请求等)
监控日志
管理服务 (服务下线)
②:监控的实施方式
为了方便的看到每个程序/服务的运行状态和运行指标。我们有开发一款应用用来监视所有的服务。
获取服务信息的方式有两种,一种是服务主动上传、一种是应用程序主动向服务索取。
前者,比方说服务器5s上传一次,这样的坏处是得到的信息很有可能不是实时的。
所以说后者才是大部分企业选用的,应用程序主动索取信息。除此之外,还需要配置服务开放哪一些信息给应用程序监控
③:配置服务器端
加入依赖
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>2.5.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
yml 配置端口
启动项上方@EnableAdminServer
④:配置客户端
假如client依赖,版本要与springboot一致。我的客户端和服务器版本都是一样的
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.7.10</version>
</dependency>
yml配置,url是服务器地址。
启动服务器和客户端能够发现,啥也监测不到,因为默认是不允许查看的
能看到右边的健康列表,我们在客户端yml配置,默认是never。换成always就可以查看到客户端的健康信息
如何查看全部信息呢?
endpoints:
web:
exposure:
include: '*'
⑤:配置客户端信息
我们后期处理微服务会有相当多的数据、所以必须添加一些信息我们才知道得到的是那个服务的
detail 设置单个信息、Details 设置一个数组信息
简单来说,你可以根据不同的条件来限制,服务器反馈的信息。