Spring | Java后端
介绍
Spring 是一个轻量级 Java 开发框架,设计目标是为开发者提供一个一站式轻量级应用开发平台,即简化 Java 开发,让 Spring 负责基础架构,使得 Java 开发者可以专注于应用的开发。
Spring 总共大约有 20 个模块,比较重要的有:
- spring core:提供了框架的基本组成部分,包括控制反转和依赖注入功能。
- spring beans:提供了 BeanFactory,是工厂模式的一个经典实现,Spring 将管理对象称为 Bean。
- spring context:构建于 core 封装包基础上的 context 封装包,提供了一种框架式的对象访问方法。
- spring aop:提供了面向切面的编程实现,可以自定义过滤器、切点等。
Spring 框架的核心是 IoC 容器和 AOP 模块。通过 IoC 容器组织和管理应用中各个组件及其关系,通过 AOP 以动态非侵入的方式增强服务。
Spring 优点:
方便解耦,简化开发(高内聚低耦合)
AOP 编程的支持
面向切面编程 → 对 Spring 容器中的实例做增强
声明式事务的支持
只需通过配置就可完成对事务的管理,无需手动编程
方便程序的测试
提供对单元测试的支持,即单元测试类也可以获得 Spring 容器中的实例
方便集成各种优秀框架
比如 MyBatis
降低 JavaEE API 的使用难度
控制反转 IoC
Inverse of Control,一种设计思想(不是一个具体的技术实现)
- 控制:对象创建(实例化、管理)的权力。
- 反转:原先生成权在应用程序,引入 Spring 后应用程序将实例的控制权交给 Spring。
IoC vs 工厂模式
IoC 基本上都是通过反射拿到 Bean 构造器在运行时动态创建 Bean 的,工厂模式是在编译期创建产品对象的。
依赖注入 DI
Dependency Injection,组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。
控制反转是通过依赖注入实现的,其实它们是同一个概念的不同角度描述。IoC 是设计思想,DI 是实现方式。
IoC/DI 好处
将类实例化的过程透明化,主动创建对象过程变成被动接收,方便调用方使用
IoC 容器就像是一个工厂,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的,把应用从复杂的依赖关系中解放出来(比如一个 Service 实现类可能依赖了很多其他类,假如需要实例化这个 Service,可能要每次都要搞清这个 Service 所有依赖的类的构造函数)。
编译期依赖变成了运行时依赖,降低了对象和对象之间的耦合度,符合高内聚低耦合的设计思想。
IoC 容器默认使用单例模式管理对象,效率高,可以减少内存的占用。
Spring 模块
Spring 5.x 主要模块:

Core Container
Spring 框架的核心/基础模块,主要提供 IoC/DI 功能的支持。
Spring 其他所有的功能基本都需要依赖于该模块。
- Beans 模块:提供了框架的基础部分,提供对 bean 的创建、配置和管理等功能的支持,包括控制反转和依赖注入。
- Core 模块:Spring 框架基本的核心工具类。
- Context 模块:提供对国际化、事件传播、资源加载等功能的支持。
- Expression 模块:提供对表达式语言 SpEL (Spring Expression Language)的支持,只依赖于 core 模块,不依赖于其他模块,可以单独使用。
Data Access/Integration
- JDBC 模块:提供了对数据库访问的抽象 JDBC。不同的数据库都有自己独立的 API 用于操作数据库,而 Java 程序只需要和 JDBC API 交互,这样就屏蔽了数据库的影响。
- Transaction 模块:支持编程和声明式事务管理。
- ORM 模块:提供对 Hibernate、iBatis 等 ORM 框架的支持,还可以使用 Spring 事务管理,无需额外控制事务。
- OXM 模块:提供了一个支持 Object /XML 映射的抽象层实现,将 Java 对象映射成 XML 数据,或者将 XML 数据映射成 Java 对象。
- JMS 模块 : 指 Java 消息服务,提供一套“消息生产者、消息消费者”模板用于更加简单的使用 JMS,JMS 用于用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
Web
- Web 模块:对 Web 功能的实现提供一些最基础的支持,例如多文件上传功能、使用的 Servlet 监听器的 IOC 容器初始化以及 Web 应用上下文。
- WebMVC 模块:提供对 Spring MVC 的实现。
- WebSocket 模块:提供了对 WebSocket 的支持,WebSocket 可以让客户端和服务端进行双向通信。
- Webflux 模块:提供对 WebFlux 的支持。WebFlux 是 Spring Framework 5.0 中引入的新的响应式框架。与 Spring MVC 不同,它不需要 Servlet API,是完全异步且非阻塞的。
AOP
提供了面向切面编程实现,提供比如日志记录、权限控制、性能统计等通用功能和业务逻辑分离的技术,并且能动态的把这些功能添加到需要的代码中,降低业务逻辑和通用功能的耦合。
Aspects
提供与 AspectJ 的集成,是一个功能强大且成熟的面向切面编程(AOP)框架。
Instrument
提供了类工具的支持和类加载器的实现,以在特定的应用服务器中使用。
Messaging
提供了对消息传递体系结构和协议的支持。
Test
Spring 团队提倡测试驱动开发(TDD)。有了 IoC 的帮助,单元测试和集成测试变得更简单。
Spring 的测试模块对 JUnit(单元测试框架)、TestNG(类似 JUnit)等常用的测试框架支持的都比较好。
Spring Bean
Bean 指那些被 IoC 容器所管理的对象。
通过配置元数据来告诉 IoC 容器哪些对象需要管理,配置元数据可以是 XML 文件、注解或者 Java 配置类。
注册方式
基于 XML 文件
使用被 Spring 命名空间的所支持的一系列的 XML 标签来实现的。
步骤:① 配置 xx.xml 文件;② 声明命名空间和配置 bean。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:user="http://www.zerooo.top/schema/user"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.zerooo.top/schema/user
http://www.zerooo.top/schema/user.xsd">
<bean id="userService" class="top.zerooo.www.service.UserServiceImpl">
<property name="userDao" ref="userDao"/>
<property name="tmpConst" value="zero"/>
</bean>
<user:self-user id="user" userId="12" name="aaa"/>
</beans>这种方式出现很多早前的 SSM 项目中,将第三方类库或者一些配置工具类都以这种方式进行配置,主要原因是由于第三方类不支持 Spring 注解。
优点: 可以使用于任何场景,结构清晰,通俗易懂。
缺点: 配置繁琐,不易维护,枯燥无味,扩展性差。
Spring 命名空间是一种机制,用于将 XML 配置文件中的元素和属性与 Java 类或属性进行映射。
命名空间的作用是自动为 XML 标签补全前缀,避免标签命名冲突(因为开发者可自定义命名空间和标签名,存在冲突可能)。
Spring 常用命名空间:beans、context、jdbc、tx、aop、mvc 等。
一些缩写:xmlns (xml namespace)声明使用的命名空间,xsi (xml schema instance)声明遵守的 xml 规范,xsd (xml schema definition)定义 XML 配置文件的结构。
使用 xsi:schemaLocation 可以指定命名空间对应的 xsd 文件。
关于 bean 的 id 和 name
bean 有一个或若干标识符,
基于注解
通过在类上加注解的方式,来声明一个类交给 Spring 管理,前提是需要先配置Spring的注解扫描器。
用于标注组件的注解:@Component(通用)、@Controller/@RestController(控制层)、@Service(服务层)、@Repository(持久层/Dao 层)。
步骤:① 对类添加 @Component 相关的注解;② 设置 ComponentScan 的 basePackage,比如在 XML 配置文件中设置
<context:component-scan base-package='top.zerooo.www'>
,或者在 SpringBoot 启动类上添加@ComponentScan("top.zerooo.www")
注解,或者在代码中创建使用 IoC 容器时指定扫描的 basePackage。优点:开发便捷,通俗易懂,方便维护。
缺点:具有局限性,对于一些第三方资源,无法添加注解。只能采用 XML 或 JavaConfig 的方式配置。
基于 JavaConfig 配置类
JavaConfig 是 Spring 社区的产品,它提供了配置 Spring IoC 容器的纯 Java 方法。
将类的创建交给我们配置的 JavcConfig 类来完成,Spring 只负责维护和管理,采用纯 Java 创建方式。其本质上就是把在 XML 上的配置声明转移到 Java 配置类中。
步骤:① 创建一个配置类, 添加 @Configuration 注解声明为配置类;② 在配置类中创建方法,方法上加上 @bean,该方法用于创建实例并返回,该实例创建后会交给 Spring 管理,方法名建议与实例名相同(首字母小写)。注:实例类自身不需要加任何注解。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class BeansConfig {
/**
* @return user dao
*/
public UserDaoImpl userDao() {
return new UserDaoImpl();
}
/**
* @return user service
*/
public UserServiceImpl userService() {
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(userDao());
return userService;
}
}优点:适用于任何场景,配置方便,因为是纯 Java 代码,扩展性高,十分灵活,可以充分利用 Java 中的面向对象功能。
缺点:由于是采用 Java 类的方式,声明不明显,如果大量配置,可读性比较差。
实例化方式
使用构造器(利用反射)
bean 的 \<bean> 需要 class 属性写 bean 的全类名,代表构造器。
无参构造器(默认)
使用 \<property> 子标签,属性有 name、value、ref。
有参构造器
使用 \<constructor-arg> 子标签,属性有 name、value、ref。
工厂
bean 的 \<bean> 需要 class 属性写工厂类的全类名。
静态工厂
产品 bean 对应 \<bean> 的 factory-method 属性写静态工厂生产 bean 的方法名(必须是静态方法)。
实例工厂
实例工厂自身需要使用 \<bean> 注册。
产品 bean 对应 \<bean> 的 factory-bean 属性写实例工厂注册的 id(因此实例工厂对应 \<bean> 需要写 id 属性),factory-method 属性写生产产品 bean 的方法名。
FactoryBean
接口,提供生产方法,通过实现该接口定制实例化 Bean 的逻辑,生成特定类型的 Bean。
其实现类需要注册。
注意不要与Spring 容器 BeanFactory 混淆。
依赖注入方式
setter 方法注入
在基于 XML 文件的注册方式下,使用 \<property> 都是通过 setter 方法注入(因为是使用无参构造器实例化)。
在基于注解的注册方式下,可以使用 @Autowired 和 @Resource 在要进行依赖注入的 setter 方法上标注。
1 |
|
首先实例化对象,然后才实例化所有依赖的对象。表现了 bean 之间的聚合关系。
构造器注入
通过容器触发有参构造器来实现。
不能提供无参构造器,否则 Spring 默认会使用无参构造器实例化。
在基于 XML 文件的注册方式下,使用 \<constructor-arg> 都是通过构造器参数注入。
在基于注解的注册方式下,可以且只能使用 @Autowired 实现构造器注入。从 Spring 4.3 版本开始可以不加 @Autowired 也能实现构造器注入,前提是有且只有一个有参构造器。
1 |
|
保证所有一个对象所有依赖的对象先实例化后,才实例化这个对象。表达了 bean 之间的一种强聚合关系:组合关系。
只有使用构造器注入才能注入 final 属性(懂得都懂)。
属性注入
本质是利用反射机制。
1 |
|
三种注入方式的比较:

自动装配
装配:在 Bean 与 Bean 之间建立依赖关系的行为
XML 配置中通过 \<constructor-arg> 和 \<property> 中的 ref 属性,是手动去维护 Bean 与 Bean 之间的依赖关系,可以不手动而选择自动装配。
自动装配模式:
- no:默认,不自动装配
- byName:按 id 或 name 属性值
- byType:按 class 属性
- constructor:与 byType 类似,只是它应用于构造器参数
- autodetect:先尝试 constructor,如果失败再尝试 byType(Spring3.0 之后弃用)
XML 方式和注解方式都有对应的自动装配
XML 方式
通过 \<bean> 的 autowire 属性进行设置,autowire 属性的 5 个取值对应 5 种自动装配模式
设置 autowire 后可以省去原先带有 ref 属性的 \<constructor-arg> 和 \<property>
注解方式
@Autowired
可以应用到属性、setter 方法、非 setter 方法及构造函数等
默认按类型进行装配,如果想按名称可以结合 @Qualifier 一起使用
默认要求依赖对象必须存在,若允许为 null,可以设置 required 属性为 false
@Resource
作用与 @Autowired 相同,区别在于其默认按名称装配
有 name 和 type 两个属性,可以指定按名称或按类型;如果都不指定,就先按名称,若失败则再按类型。如果都无法匹配,则抛出 NoSuchBeanDefinitionException 异常
@Qualifier
与 @Autowired 注解配合使用,会将默认的按类型装配改为按名称装配,名称由 @Qualifier 的参数指定
生命周期

作用域
通常有下面几种
- singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的,对单例设计模式的应用
- prototype : 每次请求都会创建一个新的 bean 实例
- request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效
- session : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效
- global-session : 全局 session 作用域,仅仅在基于 portlet 的 web 应用中才有意义
配置方式:bean 标签的 scope 属性、@Scope
AOP
Aspect oriented Programming,面向切面编程,能将那些与业务无关,却为业务模块所共同调用的逻辑(例如日志管理、资源释放、事务处理等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性
Spring AOP
基于动态代理,根据委托类是否实现了某个接口选择使用 JDK 还是 Cglib 在运行时创建代理对象
通知组件 implements MethodInterceptor(Object proceed = methodInvocation.proceed()
)会对委托类所有方法做增强,还要通过委托类组件和通知组件注册一个代理组件
AspectJ
属于静态织入,基于字节码操作,有一个专门的字节码生成器来生成 class 文件
织入时机有:编译期织入、编译后织入、类加载后织入
Pointcut 可精确到方法,能设置多个
execution 表达式、自定义注解(指哪打哪)
Advise
implements MethodInterceptor
Aspect 切面类
相对于切点时间可以做多种增强:Before、After、Around(上面的 Advise 相当于这种)、AfterReturning、AfterThrowing,它们在切面类中以方法形式存在(实际上每个方法最终都会被适配成相应的 MethodInterceptor 对象)
这些增强方法可以传入参数 JoinPoint,通过它可以拿到代理类对象、委托类对象、委托类类名、切点方法名、切点方法参数等信息
Spring MVC
MVC:模型(Model)、视图(View)、控制器(Controller),其核心思想是通过将业务逻辑、数据、显示分离来组织代码。
SpringMVC 是 Spring 基础上的一个 MVC 框架,主要处理 web 开发的路径映射和视图渲染。
Spring MVC 下我们一般把后端项目分为 Service 层(处理业务)、Dao 层(数据库操作)、Entity 层(实体类)、Controller 层(控制层,返回数据给前台页面)。
Controller 层
负责业务模块流程的控制,需要调用 Service 层的接口来控制业务流程。
Controller 层通过接收前端传过来的参数进行业务操作,再将处理结果返回到前端。
Service 层
主要负责业务模块的逻辑应用设计,并给 Controller 层的类提供接口进行调用。
一般就是自己写的方法封装起来,就是简单声明一下,具体实现在serviceImpl 中。这样我们就可以在应用中调用 service 接口进行业务处理。
Service 层业务实现,具体调用到已经定义的 DAO 的接口。
Dao (Data Access Object) 层
对数据库进行数据持久化操作,它的方法语句是直接针对数据库操作的,主要实现一些数据的增删改查。
核心思想是把数据库封装一下,让与数据库的交道看起来像在和一个对象打交道,这个对象通常就是 DAO。当我们操作这个对象的时候,这个对象会自动产生 SQL 语句来和数据库进行交互,我们就只需要使用 DAO 就行了。
Entity 层
用于存放实体类,与数据库中的属性值基本一致,实现 getter 和 setter 方法。
一般数据库一张表对应一个实体类,类属性同表字段一一对应。
分层结构(阿里 Java 开发手册)

简化版:

Manager 层主要用于封装 Service层中的通用业务逻辑,实现业务逻辑的复用。
领域模型(阿里 Java 开发手册)
DO (Data Object)
与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。
DTO (Data Transfer Object)
数据传输对象,Service 或 Manager 向外传输的对象。
VO (View Object)
显示层对象,通常是 Web 向模板渲染引擎层传输的对象。
QO (Query Object)
数据查询对象,各层接收上层的查询请求。
注意超过2个参数的查询封装,禁止使用 Map 类来传输。
BO (Business Object)
业务对象,可以由 Service 层输出的封装业务逻辑的对象。
业务对象和数据对象不一定是一一对应的,通常一个业务对象对应着多个数据对象。
领域模型命名规约:
- 数据对象:
xxxDO
,xxx
即为数据表名。 - 数据传输对象:
xxxDTO
,xxx
为业务领域相关的名称。 - 展示对象:
xxxVO
,xxx
一般为网页名称。 POJO
是DO/DTO/BO/VO
的统称,禁止命名成xxxPOJO
。
以上内容属于规约。「规约」通俗的讲就是规则的约定,是一种大家(组织/团队)共同约定好并一起遵守执行的规则合集;它不是一般意义上的标准规则,不同的组织/团队可以使用的规则是不一样的。
分层结构和领域模型的设计都是为业务服务的,设计的好坏最终还是要取决于业务效果,适合的就是好的。
工作原理/流程
- 客户端发送请求,直接请求到 DispatcherServlet
- DispatcherServlet 拿请求信息调用 HandlerMapping
- HandlerMapping 根据请求匹配到对应的 Handler,然后将找到的 Handler 和所有与之匹配的 HandlerInterceptor 绑定到创建的 HandlerExecutionChain 对象上并返回
- DispatcherServlet 拿到对应的 Handler 后,交由 HandlerAdapter 适配器处理
- HandlerAdapter 调用真正的 Handler 方法处理相应的业务逻辑,处理结束后会返回一个 ModelAndView 对象,Model 是返回的数据对象,View 是个逻辑上的 View
- ViewResolver 会根据逻辑 View 查找实际的 View
- DispaterServlet 把返回的 Model 传给 View(视图渲染)
- 把 View 返回给客户端
Spring 设计模式
工厂模式
Spring 工厂模式:通过 BeanFactory 或 ApplicationContext 创建 bean 对象
二者都可以代指为 IoC 容器,两者对比:
- BeanFactory :延迟创建 Bean,相比于 ApplicationContext 来说会占用更少的内存,程序启动速度更快
- ApplicationContext :容器启动时创建注册的所有 bean
BeanFactory 仅提供了最基本的依赖注入支持, ApplicationContext 扩展了 BeanFactory,除了有 BeanFactory 的功能还有额外更多功能,大多数场合都是直接使用 ApplicationContext 而非更加底层的 BeanFactory。
ApplicationContext 常用的三个实现类:
- ClassPathXmlApplication:从 classpath 下的 xml 配置文件中读取上下文并生成上下文定义,适用于 xml 配置的方式。
- FileSystemXmlApplication:从文件系统中的 xml 配置文件读取上下文。
- XmlWebApplicationContext:从 Web 应用中的配置文件读取上下文。
单例模式
Spring 中 bean 的默认作用域就是 singleton(单例) 的
代理设计模式
Spring AOP 的实现基于动态代理,属于运行时增强;AspectJ 基于字节码操作,静态织入,属于编译时增强
Spring AOP 已经集成了 AspectJ
适配器模式
Spring AOP 中的适配器模式
Spring AOP 中的 Advice 使用到了适配器模式
Advice 类型有 Before、After、Around、AfterReturning、AfterThrowing,每个类型的 Advice 都有相应的过滤器。最终 Advice 都要通过适配器适配成 MethodInterceptor 接口类型的对象
Spring MVC 中的适配器模式
Spring MVC的 Handler 有多种表现形式,比如 @RequestMapping、Servlet、HttpRequestHandler,不同的 Handler 处理请求的方式会有差异。适配器模式能模糊掉具体的实现,如果不利用适配器模式的话,就得 DispatcherServlet 去判断
Spring 事务
程序是否支持事务首先取决于数据库存储引擎
Spring 事务管理方式
编程式事务管理
通过 TransactionTemplate 或者 TransactionManager 手动管理事务,实际应用中很少使用
声明式事务管理
基于 @Transactional 的注解方式(实际是通过 AOP 实现)
Spring 事务管理相关接口
PlatformTransactionManager 事务管理器
提供了管理事务的方法:获得事务、提交事务、回滚事务
Spring 为各个平台如 JDBC(DataSourceTransactionManager)、Hibernate(HibernateTransactionManager) 等都提供了对应的事务管理器
TransactionDefinition 事务属性
定义了一些基本的事务属性。 事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上
事务属性包含了 5 个方面:隔离级别、传播行为、回滚规则、是否只读、事务超时
TransactionStatus 事务状态
用来记录事务的状态。该接口定义了一组方法,用来获取或判断事务的相应状态信息
事务传播行为
事务传播行为(propagation behavior)是 Spring 框架独有的事务增强特性
简单理解就是多个事务方法相互调用时,事务如何在这些方法间传播
Spring 中共有七种事务传播机制:
不需要事务
PROPAGATION_NEVER
没有就非事务执行,有就抛异常
PROPAGATION_NOT_SUPPORTED
没有就非事务执行,有就挂起,然后非事务执行
可以有事务,也可以没有事务
PROPAGATION_SUPPORTS
调用者有事务就加入,一起在事务中执行,没有就非事务执行
一定需要事务
PROPAGATION_REQUIRES_NEW
有没有都新建事务。如果调用者有事务,就挂起调用者已经开启的
PROPAGATION_REQUIRED(Spring 默认)
如果没有,就新建一个事务。如果有,就加入当前事务,一起在事务中运行
PROPAGATION_NESTED
如果没有,就新建一个事务。如果有,就在当前事务中嵌套事务
PROPAGATOIN_MANDATORY
如果没有事务就报错。如果有,就加入当前事务,一起在事务中运行
需要注意:
- NESTED 里层事务的回滚,不会影响外层事务;但若外层事务出异常回滚,里层的事务也会回滚
- REQIRES_NEW 外围不影响内部,但内部影响外围
隔离级别
TransactionDefinition.ISOLATION_DEFAULT
使用后端数据库默认的隔离级别
MySQL 默认 REPEATABLE_READ,Oracle 默认 READ_COMMITTED
TransactionDefinition.ISOLATION_READ_UNCOMMITTED
读未提交
TransactionDefinition.ISOLATION_READ_COMMITTED
读已提交
TransactionDefinition.ISOLATION_REPEATABLE_READ
可重复读
TransactionDefinition.ISOLATION_SERIALIZABLE
序列化
@Transactional 使用
作用范围
- 方法 :只能应用到 public 方法上,否则不生效
- 类 :对该类中所有的 public 方法都生效
- 接口 :不推荐
常用配置参数
Spring Boot
什么是 Spring Boot
Spring Boot 是 Spring 开源组织下的子项目,是 Spring 组件一站式解决方案,主要是简化了使用 Spring 的难度,简省了繁重的配置,提供了各种启动器,开发者能快速上手。
好处
- 容易上手,提升开发效率,为 Spring 开发提供一个更快、更广泛的入门体验
- 开箱即用,远离繁琐的配置
- 提供了一系列大型项目通用的非业务性功能,例如:内嵌服务器、安全管理、运行数据监控、运行状况检查和外部化配置等
- 避免大量的 Maven 导入和各种版本冲突
starter
starter 是对第三方组件的一种“包装”,它整合了第三方组件自身和其他可能用到的组件的依赖以及组件的自动配置类与默认配置信息,让用户摆脱了要使用该组件时需要处理各种依赖和配置的困扰。如果用户需要自定义配置,只需在 application 配置文件中进行
自动装配
自动装配基于 Spring 工厂加载机制(类似于 Java SPI 机制),它要求第三方在 classpath:/META-INF 下提供 spring.factories 文件,内容是组件的自动配置类的全限定类名,这样 SpringBoot 应用在启动时就会去扫描 classpath:/META-INF 下的所有 spring.factories 文件,拿到所有第三方组件的自动配置类的全限定类名,把这些自动配置类全部加载到 JVM 内存中
SpringFactoriesLoader 是工厂加载机制的核心底层实现类,上述过程就是由它完成。SpringFactoriesLoader 是被谁调用的?
在 Spring Boot 应用里,只需要在启动类加上 @SpringBootApplication 注解就可以实现自动装配。@SpringBootApplication 是一个复合注解(@SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan),真正实现自动装配的注解是 @EnableAutoConfiguration,它会向容器中注入 ImportSelector,SpringFactoriesLoader 就是它调用的
实际上 SpringBoot 是对第三方组件的自动配置类的自动发现与加载,而具体的装(注册)配(配置)工作则是由自动配置类完成。在自动配置类中,使用 @Bean 对组件进行注册,使用 @EnableConfigurationProperties 引入 Properties 参数类,利用参数类拿到默认的配置值对组件配置
约定优于配置的体现
- 自动装配(主要):默认的组件,组件配置默认的名称、类型和值,默认的依赖,依赖默认的版本号
- 以 application 为名的默认配置文件,默认有四个地方可以存放:项目根目录下、项目根目录下的 config 目录下、config 目录下、resources 目录下的 config 目录下
项目运行方式
- 直接执行启动类的 main 方法
- 用 Maven/Gradle 插件运行
- 打包用命令或者放到容器中运行
Spring Boot 打成的 jar 和普通的 jar 区别
Spring Boot 项目最终打包成的 jar 是可执行 jar ,这种 jar 可以直接通过 java -jar xxx.jar 命令来运行,这种 jar 不可以作为普通的 jar 被其他项目依赖,即使依赖了也无法使用其中的类
Spring Boot 的 jar 无法被其他项目依赖,主要还是他和普通 jar 的结构不同。普通的 jar 包,解压后直接就是包名,包里就是我们的代码,而 Spring Boot 打包成的可执行 jar 解压后,在 \BOOT-INF\classes 目录下才是我们的代码,因此无法被直接引用。如果非要引用,可以在 pom.xml 文件中增加配置,将 Spring Boot 项目打包成两个 jar ,一个可执行,一个可引用
异常处理
使用 @ControllerAdvice 做全局的异常处理
整合 Mybatis
- 引入 mybatis-spring-boot-starter 和数据库驱动的依赖
- 给 DataSource 提供参数
- 在启动类上使用 @MapperScan 配置扫描包路径
- 在配置文件配置其他参数,比如缓存和懒加载
路径
classpath
classpath 等价于 main/java + main/resources + 第三方 jar 包的根目录。
build 构建生成的 target/classes 和 package 打包生成的 jar 包根路径都属于所谓的 classpath,也就是根路径。
打包和构建都会在根路径下创建 META-INF 文件夹,如果在 resource 文件夹中再创建一个 META-INF 文件夹,并在该文件夹中建立其他的静态资源,这些自己创建的静态资源在打包或构建时也会一起打包到 classpath:/META-INF 文件夹下。
file 路径
file 路径就是项目路径,例如:
又例如,在项目下的 config/test 创建 test.yml,用命令行指定该配置文件来启动项目时,启动参数是 `--spring.config.location=file:./config/test.yml`,或者使用注解 `@PropertySource(value = {"file:./config/test.yml"})`。
SpringBoot 的配置文件加载位置与优先级
SpringBoot 启动会扫描以下位置的 application.properties 或者 application.yml 文件作为 Spring Boot 的默认配置文件:
file:./config/
file:./
classpath:/config/
classpath:/
优先级由高到底,高优先级的配置会覆盖低优先级的配置,所有的配置会形成互补配置。
如果同一个目录下,有 application.yml 也有 application.properties,默认先读取 application.properties。
面试题补充
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 ZERO!