Java 基础记录
SpringBoot
SpringBoot优点
- Create stand-alone Spring applications
创建独立Spring应用 - Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
内嵌web服务器 - Provide opinionated 'starter' dependencies to simplify your build configuration
自动starter依赖,简化构建配置 - Automatically configure Spring and 3rd party libraries whenever possible
自动配置Spring以及第三方功能 - Provide production-ready features such as metrics, health checks, and externalized configuration
提供生产级别的监控、健康检查及外部化配置 - Absolutely no code generation and no requirement for XML configuration
无代码生成、无需编写XML
运行原理
先说pom.xml文件
- 父依赖
其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件!
依赖管理
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
点进去,发现还有一个父依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
几乎声明了所有开发中常用的依赖的版本号,自动版本仲裁机制
- 开发导入starter场景启动器
1、见到很多 spring-boot-starter-* : *就某种场景
2、只要引入starter,这个场景的所有常规需要的依赖我们都自动引入
3、SpringBoot所有支持的场景
https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
4、见到的 *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。
5、所有场景启动器最底层的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
- 引入Maven依赖,无需配置版本号,自动版本仲裁。也可以重写版本
<properties>
<mysql.version>5.1.43</mysql.version>
</properties>
- 引入非版本仲裁的jar,要写版本号
自动配置
- 如Tomcat、SpringMVC的一些组件、字符编码、默认包结构等常用的默认Web功能在SpringBoot里面都有默认的值,不需要我们再去配置,若是默认的版本或配置不符合要求,可以如下这样快捷更改
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<mybatis.plus.version>3.3.1</mybatis.plus.version>
<swagger.ui>2.9.2</swagger.ui>
<tomcat.version>9.0.31</tomcat.version>
</properties>
AOP 与 IOC
AOP
-
说明:AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
-
原理:基于代理模式的方式实现,在调用目标方法之前会先调用代理类的目标方法,然后由代理类返回调用结果。spring aop使用了动态代理的代理方式
-
核心概念:
- 切面:散落在系统各处的通用的业务逻辑代码,如上图中的日志模块,权限模块,事务模块等,切面用来装载pointcut和advice
- 通知:所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类
- 连接点:被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器
- 切入点:拦截的方法,连接点拦截后变成切入点
- 目标对象:代理的目标对象,指要织入的对象模块,如上图的模块一、二、三
- 织入:通过切入点切入,将切面应用到目标对象并导致代理对象创建的过程
- AOP代理:AOP框架创建的对象,包含通知。在Spring中,AOP代理可以是JDK动态代理或CGLIB代理
-
例子:假如业务模块一、二、三都需要日志记录,那么如果都在三个模块内写日志逻辑,那么会有两个问题:
-
打破模块的封装性
-
有很多重复代码
解决重复代码问题,可以通过封装日志逻辑为一个类,然后在各个模块需要的地方通过该类来试下日志功能,但是还是不能解决影响模块封装性的问题。
那么AOP就可以解决,它使用切面,动态地织入到各模块中(实际就是使用代理来管理模块对象),这样既解决了重复代码问题又不会影响模块的封装性
-
IOC
- 说明:IoC(Inverse of Control:控制反转)是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由Spring框架来管理。将对象之间的相互依赖关系交给 IOC 容器来管理,并由 IOC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。 IOC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。
- 优点:降低代码之间的耦合度,实现开闭原则
- 实现:
- 读取注解或配置文件,获取所需要的service,拿到类名
- 使用反射,基于类名实例化对应的对象实例
- 将对象实例,通过构造函数或者setter,传递给调用者
SpringMVC工作机制
- 客户端(浏览器)发送请求,直接请求到前端控制器(DispatcherServlet)。
- 前端控制器(DispatcherServlet)根据请求信息调用处理器映射器(HandlerMapping),解析请求对应的处理器(Handler)。
- 解析到对应的 Handler(也就是我们平常说的 Controller 控制器)后,开始由处理器适配器(HandlerAdapter) 适配器处理。
- 处理器适配器(HandlerAdapter)会根据 Handler来调用真正的处理器开处理请求,并处理相应的业务逻辑。
- 处理器处理完业务后,会返回一个 ModelAndView 对象,Model 是返回的数据对象,View 是个逻辑上的 View。
- 视图解析器(ViewResolver) 会根据逻辑 View 查找实际的 View。
- 前端控制器(DispatcherServlet)把返回的 Model 传给 View(视图渲染)。
- 把 View 返回给请求者(浏览器)
spring中使用的常用设计模式
- 单例模式:这个比如在创建bean的时候
- 工厂模式:这个很明显,在各种BeanFactory以及ApplicationContext创建中都用到了
- 代理模式:在Aop实现中用到了JDK的动态代理
- 模版方法模式:Spring中的JdbcTemplate
- 策略模式:在Aop的实现中,采用了两种不同的方式,JDK动态代理和CGLIB代理
- 观察者模式:如ApplicationListener
- 适配器模式 : Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller。
Redis
数据类型
五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
做什么
- 缓存
- 分布式锁 : 通过 Redis 来做分布式锁是一种比较常见的方式。通常情况下,我们都是基于 Redisson 来实现分布式锁
- 限流 :一般是通过 Redis + Lua 脚本的方式来实现限流。
- 消息队列 :Redis 自带的 list 数据结构可以作为一个简单的队列使用。
- 复杂业务场景 :通过 Redis 以及 Redis 扩展(比如 Redisson)提供的数据结构,我们可以很方便地完成很多复杂的业务场景比如通过 bitmap 统计活跃用户、通过 sorted set 维护排行榜。
- ......
持久化
-
快照(snapshotting)持久化(RDB)
Redis 可以通过创建快照来获得存储在内存里面的数据在某个时间点上的副本。Redis 创建快照之后,可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本(Redis 主从结构,主要用来提高 Redis 性能),还可以将快照留在原地以便重启服务器的时候使用。快照持久化是 Redis 默认采用的持久化方式,在 Redis.conf 配置文件中默认有此下配置:
save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。 save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。 save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
-
AOF(append-only file)持久化
开启 AOF 持久化后每执行一条会更改 Redis 中的数据的命令,Redis 就会将该命令写入到内存缓存 server.aof_buf 中,然后再根据 appendfsync 配置来决定何时将其同步到硬盘中的 AOF 文件。在 Redis 的配置文件中存在三种不同的 AOF 持久化方式,它们分别是:
appendonly yes # 开启 AOF(append only file)方式的持久化 appendfsync always #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度 appendfsync everysec #每秒钟同步一次,显示地将多个写命令同步到硬盘 appendfsync no #让操作系统决定何时进行同步
为了兼顾数据和写入性能,用户可以考虑 appendfsync everysec 选项
事务
Redis 可以通过 MULTI,EXEC,DISCARD 和 WATCH 等命令来实现事务(transaction)功能。使用 MULTI 命令后可以输入多个命令。Redis 不会立即执行这些命令,而是将它们放到队列,当调用了 EXEC 命令将执行所有命令。但是,Redis 的事务和我们平时理解的关系型数据库的事务不同,Redis 是不支持 roll back 的,因而不满足原子性的(而且不满足持久性)。
MySQL
事务
关系型数据库(例如:MySQL、SQL Server、Oracle 等)事务都有 ACID 特性:
ACID 特性:
- 原子性(Atomicity) : 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
- 一致性(Consistency): 执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的;
- 隔离性(Isolation): 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
- 持久性(Durability): 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
事务隔离级别:
-
READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
-
READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
-
REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
-
SERIALIZABLE(可串行化): 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)。我们可以通过SELECT @@tx_isolation;命令来查看,MySQL 8.0 该命令改为SELECT @@transaction_isolation;
索引
索引的作用就相当于目录的作用,有目录了,我们只需要先去目录里查找字的位置,然后直接翻到那一页就行了。
索引的优缺点
优点 :
- 使用索引可以大大加快 数据的检索速度(大大减少检索的数据量), 这也是创建索引的最主要的原因。
- 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
缺点 :
- 创建索引和维护索引需要耗费许多时间。当对表中的数据进行增删改的时候,如果数据有索引,那么索引也需要动态的修改,会降低 SQL 执行效率。
- 索引需要使用物理文件存储,也会耗费一定空间。
索引的底层数据结构
Hash表 & B+树
哈希表是键值对的集合,通过键(key)即可快速取出对应的值(value)(利用哈希算法),因此哈希表可以快速检索数据(接近 O(1))。
B 树& B+树
目前大部分数据库系统及文件系统都采用 B-Tree 或其变种 B+Tree 作为索引结构。
索引类型
- 主键索引
- 唯一索引(Unique Key) :唯一索引也是一种约束。唯一索引的属性列不能出现重复的数据,但是允许数据为 NULL
- 普通索引(Index) :普通索引的唯一作用就是为了快速查询数据,一张表允许创建多个普通索引,并允许数据重复和 NULL。
- 前缀索引(Prefix) :前缀索引只适用于字符串类型的数据。前缀索引是对文本的前几个字符创建索引,相比普通索引建立的数据更小, 因为只取前几个字符。
- 全文索引(Full Text) :全文索引主要是为了检索大文本数据中的关键字的信息。