javaWeb后端技术(26) - SpringBoot快速入门(21):SpingBoot原理
SpingBoot原理
我们学习的都是web开发的技术使用,都是面向应用层面的,我们学会了怎么样去用。而我们今天所要学习的是web后端开发的最后一个篇章springboot原理篇,主要偏向于底层原理。
我们今天的课程安排包括这么三个部分:
- 配置优先级:Springboot项目当中属性配置的常见方式以及配置的优先级
- Bean的管理
- 剖析Springboot的底层原理
1. 配置优先级
在我们前面的课程当中,我们已经讲解了SpringBoot项目当中支持的三类配置文件:
- application.properties
- application.yml
- application.yaml
在SpringBoot项目当中,我们要想配置一个属性,可以通过这三种方式当中的任意一种来配置都可以,那么如果项目中同时存在这三种配置文件,且都配置了同一个属性,如:Tomcat端口号,到底哪一份配置文件生效呢?
- application.properties
server.port=8081 |
- application.yml
server: |
- application.yaml
server: |
我们启动SpringBoot程序,测试下三个配置文件中哪个Tomcat端口号生效:
- properties、yaml、yml三种配置文件同时存在
properties、yaml、yml三种配置文件,优先级最高的是properties
- yaml、yml两种配置文件同时存在
配置文件优先级排名(从高到低):
- properties配置文件
- yml配置文件
- yaml配置文件
注意事项:虽然springboot支持多种格式配置文件,但是在项目开发时,推荐统一使用一种格式的配置。(yml是主流)
在SpringBoot项目当中除了以上3种配置文件外,SpringBoot为了增强程序的扩展性,除了支持配置文件的配置方式以外,还支持另外两种常见的配置方式:
Java系统属性配置 (格式: -Dkey=value)
-Dserver.port=9000
命令行参数 (格式:–key=value)
--server.port=10010
那在idea当中运行程序时,如何来指定Java系统属性和命令行参数呢?
- 编辑启动程序的配置信息
重启服务,同时配置Tomcat端口(三种配置文件、系统属性、命令行参数),测试哪个Tomcat端口号生效:
删除命令行参数配置,重启SpringBoot服务:
优先级: 命令行参数 > 系统属性参数 > properties参数 > yml参数 > yaml参数
思考:如果项目已经打包上线了,这个时候我们又如何来设置Java系统属性和命令行参数呢?
java -Dserver.port=9000 -jar XXXXX.jar --server.port=10010 |
下面我们来演示下打包程序运行时指定Java系统属性和命令行参数:
- 执行maven打包指令package,把项目打成jar文件
- 使用命令:java -jar 方式运行jar文件程序
项目打包:
运行jar程序:
- 同时设置Java系统属性和命令行参数
- 仅设置Java系统属性
注意事项:
- Springboot项目进行打包时,需要引入插件 spring-boot-maven-plugin (基于官网骨架创建项目,会自动添加该插件)
在SpringBoot项目当中,常见的属性配置方式有5种, 3种配置文件,加上2种外部属性的配置(Java系统属性、命令行参数)。通过以上的测试,我们也得出了优先级(从低到高):
- application.yaml(忽略)
- application.yml
- application.properties
- java系统属性(-Dxxx=xxx)
- 命令行参数(–xxx=xxx)
2. Bean管理
在前面的课程当中,我们已经讲过了我们可以通过Spring当中提供的注解@Component以及它的三个衍生注解(@Controller、@Service、@Repository)来声明IOC容器中的bean对象,同时我们也学习了如何为应用程序注入运行时所需要依赖的bean对象,也就是依赖注入DI。
我们今天主要学习IOC容器中Bean的其他使用细节,主要学习以下三方面:
- 如何从IOC容器中手动的获取到bean对象
- bean的作用域配置
- 管理第三方的bean对象
接下来我们先来学习第一方面,从IOC容器中获取bean对象。
2.1 获取Bean
默认情况下,SpringBoot项目在启动的时候会自动的创建IOC容器(也称为Spring容器),并且在启动的过程当中会自动的将bean对象都创建好,存放在IOC容器当中。应用程序在运行时需要依赖什么bean对象,就直接进行依赖注入就可以了。
而在Spring容器中提供了一些方法,可以主动从IOC容器中获取到bean对象,下面介绍3种常用方式:
根据name获取bean
Object getBean(String name)
根据类型获取bean
<T> T getBean(Class<T> requiredType)
根据name获取bean(带类型转换)
<T> T getBean(String name, Class<T> requiredType)
思考:要从IOC容器当中来获取到bean对象,需要先拿到IOC容器对象,怎么样才能拿到IOC容器呢?
- 想获取到IOC容器,直接将IOC容器对象注入进来就可以了
控制器:DeptController
|
业务实现类:DeptServiceImpl
|
Mapper接口:
|
测试类:
|
程序运行后控制台日志:
问题:输出的bean对象地址值是一样的,说明IOC容器当中的bean对象有几个?
答案:只有一个。 (默认情况下,IOC中的bean对象是单例)
那么能不能将bean对象设置为非单例的(每次获取的bean都是一个新对象)?
可以,在下一个知识点(bean作用域)中讲解。
注意事项:
- 上述所说的 【Spring项目启动时,会把其中的bean都创建好】还会受到作用域及延迟初始化影响,这里主要针对于默认的单例非延迟加载的bean而言。
2.2 Bean作用域
在前面我们提到的IOC容器当中,默认bean对象是单例模式(只有一个实例对象)。那么如何设置bean对象为非单例呢?需要设置bean的作用域。
在Spring中支持五种作用域,后三种在web环境才生效:
作用域 | 说明 |
---|---|
singleton | 容器内同名称的bean只有一个实例(单例)(默认) |
prototype | 每次使用该bean时会创建新的实例(非单例) |
request | 每个请求范围内会创建新的实例(web环境中,了解) |
session | 每个会话范围内会创建新的实例(web环境中,了解) |
application | 每个应用范围内会创建新的实例(web环境中,了解) |
知道了bean的5种作用域了,我们要怎么去设置一个bean的作用域呢?
- 可以借助Spring中的@Scope注解来进行配置作用域
1). 测试一
- 控制器
//默认bean的作用域为:singleton (单例) |
- 测试类
|
重启SpringBoot服务,运行测试方法,查看控制台打印的日志:
注意事项:
IOC容器中的bean默认使用的作用域:singleton (单例)
默认singleton的bean,在容器启动时被创建,可以使用@Lazy注解来延迟初始化(延迟到第一次使用时)
2). 测试二
修改控制器DeptController代码:
//bean作用域为非单例 |
重启SpringBoot服务,再次执行测试方法,查看控制吧打印的日志:
注意事项:
- prototype的bean,每一次使用该bean的时候都会创建一个新的实例
- 实际开发当中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性
2.3 第三方Bean
学习完bean的获取、bean的作用域之后,接下来我们再来学习第三方bean的配置。
之前我们所配置的bean,像controller、service,dao三层体系下编写的类,这些类都是我们在项目当中自己定义的类(自定义类)。当我们要声明这些bean,也非常简单,我们只需要在类上加上@Component以及它的这三个衍生注解(@Controller、@Service、@Repository),就可以来声明这个bean对象了。
但是在我们项目开发当中,还有一种情况就是这个类它不是我们自己编写的,而是我们引入的第三方依赖当中提供的。
在pom.xml文件中,引入dom4j:
<!--Dom4j--> |
dom4j就是第三方组织提供的。 dom4j中的SAXReader类就是第三方编写的。
当我们需要使用到SAXReader对象时,直接进行依赖注入是不是就可以了呢?
- 按照我们之前的做法,需要在SAXReader类上添加一个注解@Component(将当前类交给IOC容器管理)
结论:第三方提供的类是只读的。无法在第三方类上添加@Component注解或衍生注解。
那么我们应该怎样使用并定义第三方的bean呢?
- 如果要管理的bean对象来自于第三方(不是自定义的),是无法用@Component 及衍生注解声明bean的,就需要用到**@Bean**注解。
解决方案1:在启动类上添加@Bean标识的方法
|
xml文件:
|
测试类:
|
重启SpringBoot服务,执行测试方法后,控制台输出日志:
Tom : 18 |
说明:以上在启动类中声明第三方Bean的作法,不建议使用(项目中要保证启动类的纯粹性)
解决方案2:在配置类中定义@Bean标识的方法
- 如果需要定义第三方Bean时, 通常会单独定义一个配置类
//配置类 (在配置类当中对第三方bean进行集中的配置管理) |
注释掉SpringBoot启动类中创建第三方bean对象的代码,重启服务,执行测试方法,查看控制台日志:
Tom : 18 |
在方法上加上一个@Bean注解,Spring 容器在启动的时候,它会自动的调用这个方法,并将方法的返回值声明为Spring容器当中的Bean对象。
注意事项 :
通过@Bean注解的name或value属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名。
如果第三方bean需要依赖其它bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配。
关于Bean大家只需要保持一个原则:
- 如果是在项目当中我们自己定义的类,想将这些类交给IOC容器管理,我们直接使用
@Component
以及它的衍生注解来声明就可以。 - 如果这个类它不是我们自己定义的,而是引入的第三方依赖当中提供的类,而且我们还想将这个类交给IOC容器管理。此时我们就需要在配置类中定义一个方法,在方法上加上一个@Bean注解,通过这种方式来声明第三方的bean对象。