Spring 和 ORM 等框架
关键点
Spring
- 框架设计
- 6大模块:Core (Bean / Context / AOP), Testing (Mock / TextContext), Data Access (Tx / JDBC / ORM), Spring MVC / WebFlux (web), Integration (remoting / JMS / WS), Language (Kotlin / Groovy).
- 引入 Spring ≈ 引入一种研发协作模式:项目天然水平分层(展示层,业务层,服务层,持久化层),项目垂直分层(按业务模块),项目组件化(细粒度拆解,更好地协作管控)。
- Spring AOP (Aspect Oriented Programming)
- 需求:Spring 在 Bean 的生命周期管理和其他对象间引用装配的核心功能基础上,增加中间层,实现对象包装(不改变原有 Bean 的定义功能,通过代理 or 字节码增强技术实现),满足针对已有代码的额外控制需求。
- Spring AOP 通过
动态代理
实现。 - 对象装配思路的改进:IoC (Inverse of Control),也称“依赖注入(DI, Dependency Injection)”。
- 使用:运行期无需改代码,只需修改配置文件。
- 属性之间的循环依赖问题:Spring 中,相互依赖的对象各自独立创建,内部属性各自装配。在使用 AOP 的场景,显式拿到 Bean;之后通过代码显式地注入其他依赖对象时,从中间层拿到的是代理类或运行期生成的子类(而非真实对象),故不存在循环依赖问题。
- 概念:Advice 通知(前置/后置/环绕), joint point 连接点(插入切面,调用方法), PointCut 切点(插入增强处理), Aspect 切面(通知和切点的结合), Introduction 引入(现有类添加新的方法/属性), Weaving 织入(增强处理加入目标对象)。
- 使用
- 接口类型的对象:默认使用 jdkProxy (JDK的动态代理),生成代理。如果也使用字节码增强技术,需要开启 proxyTargetClass 选项。
- 非接口类型的对象:默认使用 CGlib 做字节码增强,生成子类。
- 相同点:都是先操作代理/子类,最终再调用原始对象/方法,返回结果。
- 方式:代码(AOP 的类) + XML;注解。
- 典型用途:日志,权限判断,事务控制。
- 字节码增强 vs 反射
- 字节码操作:运行期在内存里动态拼出的新类型。
- 反射:破坏了面向对象的封装;窥探内部,隐式调用。
- Spring Bean
- Spring 中的一个类,可以注册成一个 Bean,之后被 Spring 初始化成一个可用对象。Spring 是对 Bean 管理的基础设施。
- Bean 的加载过程:构造函数 --> 依赖注入 --> BeanName Aware --> BeanFactory Aware --> ApplicationContext Aware --> BeanPostPrecessor 前置方法 --> InitializingBean --> 自定义 init() 方法 --> BeanPostProcessor 后置方法 --> Bean 的使用 --> DisposableBean --> 自定义 destroy() 方法
- 代码过程:Bean 的实例化、属性赋值、初始化(先检查 Aware 装配,之后做前置处理,调用 init() 方法,然后做后置处理)、销毁等。
- 思考:与 ClassLoader 的加载过程有哪些相似?
- Spring XML
- 需求:Spring Bean 的配置
- 方式演化:XML 配置 --> 半自动注解配置 --> Java Config 配置 --> 全自动注解配置。
- XML 的 schemas(描述 XML 文件格式)的定义:XSD 文件(Spring 中默认格式,功能更全),DTD 文件(文档类型的定义,格式为“注册//组织//类型 标签//语言”)。
- XSD 文件在当前 jar 包中。
- spring.schemas 文本文件在 Spring-bean 的 jar 包,用于校验 XML 文件内容/格式。
- spring.handlers:运行期将 XML 的 Bean 定义加载,变成实际运行的 JAVA 对象的 Bean。
- 配置原理
- 使用 Spring 自带的自定义标签,定义一个 applicationContext.xml 文件。
- 通过 spring.schemas 文本文件,找到 jar 包中的 XSD 文件,校验 XML 文件配置的正确性。
- Spring 程序被加载、Spring 容器初始化的过程中,schemaLocation 找到每个 NS 对应的 NamespaceHandler,将 DOM 对象树解析成对象,将内容交给 NamespaceHandler,最终变成 Spring 的 Bean。
- 配置简化(牺牲灵活性)
- 自动化 XML 配置工具
- XSD 和 Bean 之间的转换:Spring @Comments 注解里的组件 XmlBeans
- XSD 和实体类之间的转换:XmlBeans 类库
- 插件:Spring-xbean
- 解析 XML 的工具
- DOM:全部加载到内存,解析成 DOM 对象树。
- SAX / StAX:流式便利节点。
- XML 和 Bean/POJO JAVA 对象的相互转换的工具
- xbean
- XStream 开源框架
- 需求:Spring Bean 的配置
- Spring Messaging
- Messaging:发送、接收消息,消息的流动
- MQ 应用场景:同步转异步 / 简化多系统间通信的网络拓扑。
- JMS (Java Messaging Service):JAVA 中的消息规范
- 工具包:javax.jms.*
- 消息模式:Queue(一个消费者;默认持久化),Topic(多个消费者;默认无持久化)。
- 消息的行为模式:生产消费模式,发布订阅模式
- Messaging:发送、接收消息,消息的流动
Spring Boot
- 框架设计
- 从 Spring 到 Spring Boot 的优化:“约定大于配置”(零配置 & 默认约定)。
- 基于 Maven 和 POM
- 核心原理:自动化配置,Spring Boot Starter(将对应的框架技术和 Spring 框架做粘合)。
- 功能特性:独立运行的 Spring 应用,无需部署 WAR 包,限定性的 starter 依赖,必要时自动化配置,提供生产 produce-ready 特性。
- 配置
- 文件:默认 resources 文件夹存放默认配置文件 application.yml 或 application.properties;多种配置文件,默认使用 spring.profiles.active 属性决定运行环境(开发/测试/生产)时的配置文件。
- 加载:通过配置类加载成 Configuration,之后创建 Bean 并初始化。
- 条件化自动配置:运行时灵活组装,避免冲突。
- Spring Boot Starter
- 独立项目,单独打包;结构与一般的 JAVA 项目一致。
- 配置文件:spring.provides(写入当前 starter 的名字),spring.factories(写入自动配置的类),addtional-spring-configuration-metadata.json(类似Spring的XSD文件)。
- SpringBootConfiguration类: Spring Boot 项目被拉起的入口点。
- JDBC & ORM——Hibernate/MyBatis
- JAVA 数据库操作核心 API————JDBC:使用统一的编程模型访问不同的数据库。
- 每个数据库需要提供独一无二的驱动包。
- 缓存优化:DataSource,Pool 连接池(提高应用程序可用性)。
- JDBC 上的增强:加 XA 事务,使用连接池,MySQL 驱动 JDBC 接口。
- ORM
- Hibernate:先定`实体类和 hbm 映射关系文件 --> 使用 HQL 操作对象中的属性,用面向对象的方式写 SQL --> 返回的数据自动变成配置好的映射关系。优势:可以使用 JPA 接口操作,作为 JPA(Java Persistence API) 规范的适配实现。
- MyBatis:半自动化ORM。可以用 XML 或注解配置映射,将接口和 POJOs 映射成数据库记录。
- Spring / Spring Boot 集成 ORM / JPA
- Spring 操作关系型数据库
- Spring JDBC 组件:封装 JDBC 接口,使用连接池等技术,操作管理 DataSource。
- Spring ORM 包:封装 JPA 接口,操作 EntityManager。
- Spring 操作非关系型数据库:类似JPA操作关系型数据库(使用面向对象操作)。
- Spring 管理事务
- JDBC 层:编程式事务管理
- Spring 框架层:事务管理器 + AOP
- Spring 集成 MyBatis:项目中 resources 文件夹下有各实体类的 mapper.xml 配置(mapper 在 MyBatis 里相当于 DAO)。
- Spring 集成 Hibernate / JPA
- 配置
EntityManagerFactory
:注入数据源,指定JPA的适配器是Hibernate的JPA,指定实体类的位置,指定其他配置属性。 - 配置事务管理器(EntityManager 接口由 Hibernate 适配器自动生成)。
- 其他类似 Spring 集成 MyBatis
- 配置
- Spring Boot 集成更简单。
- Spring 操作关系型数据库
- JAVA 数据库操作核心 API————JDBC:使用统一的编程模型访问不同的数据库。
经验认识
Spring / Spring Boot 使用 ORM 的经验
- 本地事务
- 多数据源
- 数据库连接池配置
- ORM 内的复杂 SQL,级联查询
- ORM 辅助工具、插件
设计模式 & 设计原则
- 设计原则
- 面向对象的设计和编程原则 SOLID
- 最小知识原则 KISS:(核心)高内聚,低耦合。
- 编码规范
- 设计模式
- GoF 23(23个经典设计模式;面向接口编程)
- 分类:创建型,结构型,行为型。
- 模式的3个层次:解决方案层(架构模式),组件层(框架模式),代码层(GoF 23 设计模式)。
- GoF 23(23个经典设计模式;面向接口编程)
单元测试
- 本质:白盒测试 + 自动化测试
- 粒度:单元测试(业务方法测试;开发人员编写,数量 > 业务方法) --> 集成测试(服务测试) --> 功能测试(端到端测试)。
- 优势
- 明确所有的边界处理
- 保证代码符合预期
- 在开发时期提前发现问题,降低 bug 修复成本
- 经验
- 一个方法一个case,且断言要充分、提示要明确
- 应覆盖所有边界条件
- 充分使用 Mock 技术
- 不好写,则反向优化代码,解决代码设计问题
- 批量测试使用参数化的单元测试
- 单元测试默认是单线程的(可能有“环境污染问题”)
- 尽量少修改全局变量、静态变量
- 合理使用 before, after, setup 准备环境
- 尽量不使用外部的数据库和资源
- 若必须使用,考虑嵌入式数据库、事务的自动回滚
- 合理使用通用测试基类(避免重复)
- 配合 checkstyle、coverage 等工具
- 制定单测覆盖率基线