1、背景
Spring作为Java Web开发使用最频繁的框架,具有非常高的学习价值,在Spring框架源码中包含了很多设计模式(单例、原型、代理、观察者等),读懂这些源码有助于拓宽开发思路,同时也能提高后端排查错误的能力。以下将从IOC、DI、AOP三个主要模块进行Spring框架剖析,同时尝试手写实现Spring的基础功能。
2、Spring模块分析和手写
IOC
什么是IOC?
IOC(Inversion of control)控制反转将对象的获取途径交给spring管理,是spring的核心。
IOC有什么好处?
- 简化代码,不需要去手动new常见的bean对象;
- 面向接口编程,便于内容扩展;
- 方便进行AOP编程;
IOC容器(Bean工厂)做了哪些工作?
负责创建和管理类实例,向使用者提供实例。
IOC容器又称为Bean工厂(工厂模式),使用者调用getBean()方法,工厂则查找相应的Bean定义,生成实例(返回Object对象)。
手写Spring IOC框架
整体设计思路
1、IOC容器本质上是一个bean工厂,主要实现bean的定义、创建和管理。因此我们需要先定义出Bean定义的模型,并把BeanDefinition交给BeanFactory,整体设计思路如图。
BeanDefinition
1、工厂的核心是创建bean对象,有三种方式:new、工厂成员方法、工厂静态方法,因此需要对外提供相应的接口
创建实例图
2、增强功能要求:
bean有作用域的区分(单例或原型),同时需要管理bean的生命周期(初始化、使用、销毁);
BeanFactory
1、BeanDefinition需要注册到BeanFactory中,该过程通过BeanDefinitionRegistry接口实现(注册+发现),并由BeanFactory实现类实现这些接口。
2、BeanFactory接口需要实现最基础的功能:获取bean,即getBean()方法;
3、所以,IOC中的默认bean工厂实现类(DefaultBeanFactory)包含以下功能:
(1)实现bean定义信息的注册;(registerBeanDefinition()方法实现,验证通过后放入beanDefinitionMap中)
(2)实现bean实例的创建;(通过构造器方法、静态工厂方法、工厂bean方法这三种方式的对象创建方式)
(3)实现初始化方法的执行;(通过doInit()方法实现)
(4)实现单例的要求;(可在系统启动时进行初始化,通过PreBuildBeanFactory子类实现)
(5)实现容器关闭是执行单例的销毁操作(通过close()方法实现)
最终逻辑对应类图如下:
4、增强功能:
- 给bean实例增加别名。允许多个别名,也可以有别名的别名(通过AliasRegistry接口中的方法实现针对别名的CRUD)。
图
- 增加更多获取bean实例的接口方法(除了根据beanName以外,还可以根据class类型来获取bean实例的Map/List集合)
图
(此时需要考虑建立type(class)与beanName之间的关系,需要建立一个一对多的Map集合)
-
最终类图如下:
DI
介绍
DI(Dependency injection)依赖注入,对象之间的依赖由IOC容器在运行期决定,即容器会动态地将某个依赖注入到对象中,也就是bean对象的成员变量赋值。
哪些地方会有依赖
- 构造参数依赖(构造方法)
- 属性依赖(getter和setter)
依赖类型
- 直接值
- bean实例
AOP分析
3、bean的生命周期
1、创建
2、使用
3、销毁
4、常用注解
配置与注册相关:
@SpringBootApplication:启动类
@Bean:显式注入bean实例,通常跟Configuration一起使用,第三方工具包常用
@ComponentScan:注解定义要扫描的路径从中找出标识了需要装配的类自动装配到 Spring 的 bean 容器中)。
@value:加载配置文件中的参数
@ConfigurationProperties:读取特定参数并与bean绑定
Bean相关:
@Component、@Controller、@Service、@Configuration:@Component是通用注解,将类备注为bean组件,运行阶段自动创建实例,也可以使用后三者进行语义上的区分。
@Scope:声明bean的作用域(创建方式)
JPA(持久化)相关:
@Entity:声明为数据库表实体
@Table:设置表名
@Id:
@Column:表示对应字段
@Transient:表示不进行持久化下
Rest风格控制器相关:
@RestController:是@Controller和@ResponseBody的合集,表示这是个控制器 bean,并且是将函数的返回值直接填入 HTTP 响应体中,是 REST 风格的控制器
@XXXMapper:有get、post、put、delete,声明在controller类的方法中,表示该方法是处理crud中的其中一种请求。
传值:
@PathVariable:获取路径参数
@RequestParam:获取查询参数(?后面的参数)
@RequestBody获取请求体中的json参数(Content-Type=application/json)
校验:
@NotEmpty
@NotBlank
@NotNull
@Valid:与上面的注解搭配使用
@Validated
Json处理:
@JsonIgnoreProperties或@JsonIgnore
@JsonFormat:格式化json
测试相关:
异常处理相关:
@ControllerAdvice + @ExceptionHandler:统一异常处理