极客时间-Spring全家桶学习笔记

Spring全家桶走一波!

网络资源:

Spring比较全面 通俗易入门的文章
Spring 注解配置工作原理源码解读

Spring注解2

Spring中的事件机制
还不错的csdn博客
Spring源码解析

透过现象看原理:详解 Spring 中 Bean 的this 调用导致 AOP 失效的原因

相关本地笔记:

Spring类图与源码分析

Java调试:

Java调试那点事儿

怎样阅读Java异常信息

脑图:

如何配置单数据源

关于Spring数据源的配置

  • 引入对应数据库驱动 —— H2
  • 引入JDBC依赖 ——spring-boot-starter-jdbc
  • 通过/acturator/beans 查看bean

直接配置所需要的Bean

数据源相关

  • DataSource(根据所选连接池实现决定)
  • 事务相关(可选)
    • PlatformTransactionManager(DataSourceTransactionManager)
    • TransactionTemplate
  • 操作相关
  • JdbcTemplate


源码:

JDK DataSource接口注释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
用于连接此DataSource对象表示的物理数据源的工厂。作为DriverManager工具的替代方案,DataSource对象是获取连接的首选方法。实现DataSource接口的对象通常将使用基于Java™命名和目录(JNDI)API的命名服务进行注册。
DataSource接口由驱动程序供应商实现。有三种类型的实现:
基本实现 - 生成标准Connection对象
连接池实现 - 生成一个将自动参与连接池的Connection对象。此实现适用于中间层连接池管理器。
分布式事务实现 - 生成可用于分布式事务的Connection对象,并且几乎总是参与连接池。此实现与中间层事务管理器一起使用,并且几乎总是与连接池管理器一起使用。
DataSource对象具有可在必要时进行修改的属性。例如,如果将数据源移动到其他服务器,则可以更改服务器的属性。好处是因为可以更改数据源的属性,所以不需要更改访问该数据源的任何代码。
通过DataSource对象访问的驱动程序不会向DriverManager注册自己。而是通过查找操作检索DataSource对象,然后用于创建Connection对象。通过基本实现,通过DataSource对象获得的连接与通过DriverManager工具获得的连接相同。
DataSource的实现必须包含public no-arg构造函数。


public interface DataSource extends CommonDataSource, Wrapper {

Connection getConnection() throws SQLException;


Connection getConnection(String username, String password)
throws SQLException;
}

application.properties

Spring-JDBC-Template


问题:

  1. 使用H2创建的表,用IDEA连接到数据库里却根本找不到那张表,h2的url和用户名都一模一样,这个表是创建到哪里去了? 并且我连接h2的时候随便填url 和 用户名都能成功。。。这他妈。。。 先记录下

Spring 多数据源配置

不同数据源配置要分开

关注每次使用的配置源
  • 有多个DataSource时系统如何判断
  • 对应的设施(事务,ORM) 等如何选择DataSource
手工配置两组 DataSource 以及相关内容
与 Spring Boot 协同工作
  • 配置 @Primary 类型的 Bean
  • 排除 SpringBoot 的自动配置
    • DataSourceAutoConfiguration
    • DataSourceTransactiononManagerAutoConfiguration
    • JdbcTemplateConfiguration
在代码中自己控制多数据源的配置

连接池:HikariCP & Alibaba Druid

HikariCP 为什么快

1.字节码级别的优化 很多方法通过 JavaAssist 生成
2.大量小的改进
  • 用 FastStatementList 代替 ArrayList
  • 无锁集合 ConcurrentBag 的使用
  • 代理类的优化 (比如使用 invokestatic 代替 Invokevirtual)

Druid

经过阿里巴巴各大系统的考验,值得信赖
实用的功能
  • 详细的监控
  • ExceptionSroter 针对主流数据库的返回码都有支持
  • SQL 防注入
  • 内置加密配置
  • 众多扩展点 方便定制

Spring 的 JDBC 操作类

spring-jdbc
  • core,JdbcTemplate 等相关核心接口和类
  • datasource,数据源相关的辅助类
  • object,将基本的 JDBC 操作封装成对象
  • support,错误码等其他辅助工具
常用的 Bean 注解
  • @Compoent 通用的注解定义通用的Bean
  • @Repository 数据库操作在Repository中,但是虎哥封装了一层Biz 都在Biz层中
  • @Service
  • @Controller
    • @RestController
      • @MixRestController

源码 JdbcTemplate

  • query
  • queryForObject
  • queryForList
  • update
  • execute

Spring 的 JDBC 异常抽象

Consistent Exception Hierarchy 一致的异常层次,无论发生什么异常 Spring都会把异常转换为自己的异常
Spring 是怎么认识那些错误码的
通过 SQLErrorCodeSQLExceptionTranslator 解析错误码
ErrorCode 定义
  • org/springframwork/jdbc/support/sql-error-codes.xml
  • Classpath 下的 sql-error-codes.xml(自己定义的错误)
定制错误码解析逻辑

13. 课程答疑

答疑内容清单:
  • 开发环境相关的说明
  • 一些 Spring 常用注解的简介
  • 关于 Actuator Endponints 访问不到的说明
  • 多数据源、分库分别、读写分离的关系
  • 与内部方法调用与事务的课后问题
  • REQUIRES_NEW 与 NESTED 事务传播特性的说明
  • Alibaba Druid 的一些展开说明

Java基础前置

Util 包希望大家能掌握

日志框架希望能掌握 SLF

Apache-Commons 包

Maven的使用

SpringData JPA Repository 怎样从接口 转变为真正能执行的 Bean

Spring 常用注解

Java Config 相关注解
  • @Configuration
  • @ImportResource
  • @ComponentScan
  • @Bean
  • @ConfigurationProperties
定义相关的注解
  • @Compoent / @Repository / @Service
  • @Controller / @RestController
  • @RequestMapping
注入相关注解
  • @AutoWired / @Qualifier / @Resource
  • @Value
    • 注入常量或者 Spel 等表达式

多数据源、分库分表、读写分离

常见情况:
  • 系统需要访问几个完全不同的数据库
  • 系统需要访问同一个库的主库与备库
  • 系统需要访问一组做了分库分表的数据库

数据库中间件 DB_Proxy

如果分库分表 建议使用数据库中间件 如果读写分离,Client 做就可以满足

Spring 事务的本质

  • Spring 的声明式事务本质上是通过 AOP 来增强了类的功能
  • Spring 的 AOP 本质上就是为类做了一个代理
    • 看似在调用自己的类,实际上使用的是增强后的代理类。
  • 问题的解法
    • 访问增强后的代理类方法,而非直接访问自身方法

REQUIRES_NEW 和 NESTED 的区别

REQUIRES_NEW,始终启动一个新的事务
  • 两个事务没有关联
NESTED,在原事务内启动一个内嵌事务
  • 两个事务有关联
  • 外部事务回滚,内部事务也会回滚
讲Spring JPA 和 MyBatis的章节 有讲怎样使用 example 这块值得学一下,先过一遍

使用 Docker 帮助开发

Spring MVC的核心

DispatcherServlet (Spring的核心)

Web上下文的层次

应用程序上下文的继承关系:

Servelet WebApplicationContext 继承 Root WebApplicationContext

问题:

如果在Servlet WebApplicationContext中配置了AOP拦截增强,拦截对象在Root中,则不生效。

Context Hierarchy (上下文层次结构)

  • Controller
  • xxxResolver
    • ViewResolver
    • HandlerExceptionResolver
    • MultipartResolver
  • HandlerMapping
  • @Controller
    • @RestController
  • @RequestMapping
    • @GetMapping / @PostMapping
    • @PutMapping / @DeleteMapping
  • @RequestBody / @ResponseBody / @ResponseStatus

Spring的应用程序上下文(重点)

依赖注入是通过Spring的上下文 ApplicationContext实现的。

  • ApplicationContext

    • ClassPathXmlApplicationContext

      在ClassPath类路径中寻找XML文件构成ApplicationContext

    • FileSystemXmlApplicationContext

      在文件系统中寻找XML文件构成ApplicationContext

    • AnnotationConfigApplicationContext

      根据注解构成ApplicationContext

Spring MVC 请求处理机制

FrontController 就是 DispatcherServlet

DispatcherServlet内部处理一个请求的大致流程

绑定一些 Attribute
  • WebApplicationContext / LocalResolver / ThemeResolver
处理 Multipart
  • 如果是, 则将请求转为 MultipartHttpServeletRequest
Handler 处理
  • 如果找到对应 Handler, 执行 Controller 及前后置处理器逻辑处理返回的Model 呈现视图

源码 : DispatcherServlet

核心方法:doService , doDispatcher

09 | 如何通过Spring JDBC 访问数据库

org.springframework:spring-jdbc Maven模块下包含着 Spring 对JDBC的封装

  • core,JdbcTemplate 等相关核心接口和类
  • datasource, 数据源相关的辅助类
  • object,将基本的 JDBC 操作封装成对象
  • support,错误码等其他辅助工具

简单的 JDBC 操作

JdbcTemplate
  • query
  • queryForObject
  • queryForList
  • update
  • execute

Coding

知识点:

  1. 使用Spring-JdbcTemplate进行CRUD操作
  2. SQL 批处理操作: jdbcTemplate.batchUpdate , NamedParameterJdbcTemplate 2个都可以完成

修改的点:

  1. 将数据库从H2改为了Mysql

问题:

  1. data.sql 和 schema.sql 这俩 sql 文件是怎么被执行的

    springboot文档

    文档中说明,SpringBoot 可以自动创建表(DDL scripts) 。可以识别在 root classpath下的 schema.sql 和 data.sql

    1
    Spring Boot can automatically create the schema (DDL scripts) of your DataSource and initialize it (DML scripts). It loads SQL from the standard root classpath locations: schema.sql and data.sql, respectively. In addition, Spring Boot processes the schema-${platform}.sql and data-${platform}.sql files (if present), where platform is the value of spring.datasource.platform. This allows you to switch to database-specific scripts if necessary. For example, you might choose to set it to the vendor name of the database (hsqldb, h2, oracle, mysql, postgresql, and so on).

    看来这个是Spring Boot 做的自动配置的增强。 用就完事了

  1. 10,11 | 什么是 Spring 的事务抽象

一致的事务模型
  • JDBC/Hibernate/Mybatis
  • DataSource/JTA
事务抽象核心接口
  • PlatformTransactionManager
    • DataSourceTrasactionManager
    • HibernateTransactionManager
    • JtaTransactionManager
  • TransactionDefinition
    • Propagation
    • Isolation
    • Timeout
    • Read-only status
1
2
3
4
5
6
7
//提交事务
void commit(TransactionStatus status) throws TransactionException
//回滚事务
void rollback(TransactionStatus status) throws TransactionException

//这个现在不在 TransactionDefinition里了,而是在 PlatformTransactionManager.java 这个接口里
TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException
事务传播特性 7 种 但是在官方文档中只提了3种
默认 REQUIRED 级别

Spring 默认值是 -1 取决于具体的数据库

Isolation 枚举类设置事务的隔离级别,默认是-1。

编程式事务的使用:

一般是直接使用 TransactionTemplate

Execute 方法 ,如果有返回值使用 TransactionCallback 没有返回值使用 TransactionCallbackWithoutResult

声明式事务

The following images shows a Conceptual view of calling a method on a transactional proxy:
通过 AOP proxy 做了一层封装 在方法上增强

tx

使用注解配置事务
开启事务:

@EnableTransactionManagement

  • 该注解需要在 @Configuration 类上使用
  • proxyTragetClass:如果有接口的话使用接口,没有的话使用CGLIB直接对类做增强
  • order:AOP拦截的顺序,默认最低优先级
  • model :是否使用AspectJ ,一般就是要默认的 Java的就看用了。

@Transactional 该注解也有很多配置项

该类用于描述单个方法或类上的事务属性。

类级别此注解默认应用于声明类及其子类的所有方法。

请注意,它不适用于类层次结构中的祖先类,方法需要在本地重新声明才能参与子类级别的注释。

判断怎样回滚

源码:

Demo

这里第三个要注意,想想运行结果是什么,方法内做调用是否可以有@Transaction增强效果?

三段代码,可以看到

insertRecord()正常插入

insertThenRollBack() 会在插入后抛出一个异常,该异常与@Transaction中配置的rollbackfor一致,导致事务回滚

invokeInsertThenRollBack()方法是单纯的对insertThenRollBack()做了一个调用。

运行结果:

可以看到第一个正常插入,第二个事务回滚,第三个事务并没有回滚。但是它明明调用了带有@Transaction注解的一个会回滚的方法,原因是什么?

原因:

在Spring中,其实是对你定义的类做了代理和增强,既然是代理,Spring只有调用代理类才能有增强,如果方法是在类内部做调用的话,本身那个方法是没有事务的,所以该方法不会有事务回滚。

思考题:如果希望方法内调用是带事务的该怎么做?

在当前类的方法中通过 AopContext.currentProxy()获取当前类的代理对象,然后再调用代理对象的方法,事务就会生效了。

还有种更简单的做法是把自己的实例注入进来,内部方法调用改为直接调用注入的实例。因为Spring其实是为你创建了一个代理,那我们调用代理就好了。

问题:

Spring创建代理的过程?是在装载bean的时候创建的吗?还是与AOP相关

Q:目前来看代理肯定是跟AOP有关的了。

13 | 课程答疑

  • 开发环境相关
  • Spring 常用注解
  • 关于 Actuator Endpoints 访问不到的说明
  • 多数据源,分库分表,读写分写的关系
  • 内部方法调用与事务的课后问题
  • REQUIRES_NEW 与 NESTED 事务传播性的问题
  • Alibab Druid 的一些展开说明

23 | SpringBucks实战项目小结

  • 简单了解 Java Persistence API 背景
  • 学习了 JPA 的常用注解
  • 学习Lombok 使用方法
  • 学习 Spring Data JPA 基本用法
  • 学习 Mybatis及其相关工具的基本用法
    • 这里可以看一下MyBatis PageHelper的源码实现,分析一下其思路,因为这个框架比较小 好学。

Example的用法

做状态机的时候会判断状态的流转方向

24 | 通过Docker 辅助开发

本章实践:在MacOS本地装一个Docker 并成功搭建开发环境。

容器没有操作系统的相关细节,所以快很多。

Docker的架构

Docker

  • 简化了重复搭建开发环境的工作
  • 交付系统更为流程
  • 伸缩性更好
Docker常用命令
  • docker pull
  • docker search
容器相关
  • docker run
  • docker start/stop <容器名>
  • docer ps <容器名>
  • docker logs <容器名>

docker run 的常用选项

docker run [OPTIONS] IMAGE [COMMAND] [ARG…]
选项说明
  • -d 后台运行容器
  • -e 设置环境变量
  • –expose / -p 宿主端口:容器端口
  • —name 指定容器名称
  • —link 链接不同容器
  • -v 宿主目录:容器目录,挂载磁盘卷

启动Mongo的命令:

1
docker run --name mongo -p 27017:27017 -v ~/docker-data/mongo:/data/db -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=admin -d mongo

成功启动 Mongo 在后台运行

在 Terminal 中连接 mongo
1
docker exec -it mongo bash

OK 连接成功

在 mongo 中使用刚才设置好的 环境变量 登录

1
mongo -u admin -p admin
成功登录 mongo docker 的 shell 中

25 | 在 Spring 中访问 MongoDB NoSQL 章节开始

说实话 这一章不太想学 因为没什么地方用到这个

36 | 通过 AOP 打印数据访问

Spring AOP 的一些核心概念

概念 含义
Aspect 切面
Join Point 俩节点
Advice 通知,在连接点执行的动作
Pointcut 切入点,说明如何匹配连接点
Introduction 引入,为现有类型声明额外的方法和属性
Target object 目标对象
AOP Proxy AOP 代理对象,可以是 JDK 动态代理,也可以是 CGLIB 代理
Weaving 织入,连接切面与目标对象或类型创建代理的过程。
分享到:
0%