SpringBoot原理
1、配置优先级
在SpringBoot项目当中支持的三类配置文件:
- applicaiton.properties
- application.yml
- application.yml
在SpringBoot项目当中,如果需要配置一个属性,可以通过这三种方式当中的任意一种来配置,那如果项目当中通知存在这三种配置文件,且都配置了同一种属性,如:Tomcat端口号,那哪一份配置文件会生效呢?
-
application.properties
server.port=8080
-
application.yml
server:
port: 8081
-
application.yaml
server:
port: 8082
测试:
-
properties、yaml、yml三种配置文件同时存在时:
properteis、yml、yaml三种配置文件中,优先级最高的是properteis
-
yaml、yml两种配置文件同时存在
配置文件优先级排名(从高到低):
- properties配置文件
- yml配置文件
- yaml配置文件
注意:虽然SpringBoot支持多种格式配置文件,但是在项目开发时,推荐统一使用一种格式的配置(yml是主流)
在SpringBoot项目当中除了以上3中配置文件外,SpringBoot为了增强程序的扩展性,除了支持配置文件的配置方式以外,还支持另外两种常见的配置方式:
-
Java系统属性配置(格式:-Dkey=value)
-Dserver.port=9000
-
命令行参数(格式:–key=value)
--server.port=10010
优先级(从低到高):
- application.yaml
- application.yml
- application.properties
- java系统属性
- 命令行参数
Bean管理
获取Bean
默认情况下,SpringBoot项目在启动的时候会自动创建IOC容器(也称为Spring容器),并且在启动的过程中会自动的将bean对象都创建好,存放在IOC容器当中,应用程序在运行时需要依赖什么bean对象,就直接进行依赖注入就可以。
而在Spring容器中提供了一些方法,可以主动从IOC容器中获取到bean对象。
-
根据name获取bean
Object getBean(String name)
-
根据类型获取bean
<T> T getBean(Class<T> requiredType)
-
根据name获取bean(带类型转换)
<T> T getBean(String name, Class<T> requiredType)
控制器:DeptController
@Slf4j
@RestController
@RequestMapping("/depts")
public class DeptController {
@Autowired
private DeptService deptService;
public DeptController(){
System.out.println("DeptController constructor.....");
}
@GetMapping
public Result list() {
log.info("查询所有部门数据");
List<Dept> deptList = deptService.list();
return Result.success(deptList);
}
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id) {
// 日志记录
log.info("根据id删除部门");
deptService.delete(id);
return Result.success();
}
@PostMapping
public Result add(@RequestBody Dept dept) {
// 日志信息
log.info("新增部门:{}", dept);
// 调用service层添加功能
deptService.insert(dept);
return Result.success();
}
}
业务实现类:DeptServiceImpl
@Slf4j
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptMapper deptMapper;
// 查询所有的部门数据
@Override
@MyLog // 自定义注解(表示:当前方法属于目标方法)
public List<Dept> list() {
List<Dept> deptList = deptMapper.list();
return deptList;
}
// 根据id删除部门信息
@Override
@MyLog // 自定义注解(表示:当前方法属于目标方法)
@Transactional(rollbackFor = Exception.class)
public void delete(Integer id) {
// 根据部门id删除部门信息
deptMapper.deleteById(id);
}
@Override
@MyLog // 自定义注解(表示:当前方法属于目标方法)
public void insert(Dept dept) {
dept.setCreateTime(LocalDateTime.now());
dept.setUpdateTime(LocalDateTime.now());
deptMapper.insert(dept);
}
}
Mapper接口:
@Mapper
public interface DeptMapper {
// 查询所有部门数据
List<Dept> list();
// 根据id删除部门数据
void deleteById(Integer id);
// 新增部门信息
void insert(Dept dept);
}
测试类:
@SpringBootTest
class DemoApplicationTests {
@Autowired
private ApplicationContext applicationContext;
// 获取bean对象
@Test
void testGetBean() {
// 根据bean的名称获取
DeptController bean1 = (DeptController) applicationContext.getBean("deptController");
System.out.println(bean1);
// 根据bean的类型获取
DeptController bean2 = applicationContext.getBean(DeptController.class);
System.out.println(bean2);
// 根据bean的名称及类型获取
DeptController bean3 = applicationContext.getBean("deptController", DeptController.class);
System.out.println(bean3);
}
}
程序运行后控制台日志:
输出的bean对象地址值是一样的,默认情况下,IOC中的bean对象是单例
Bean作用域
在Spring中支持五中作用域,后三种在web环境才生效:
作用域 | 说明 |
---|---|
singleton | 容器内同名称的bean只有一个实例(单例)(默认) |
prototype | 每次使用该bean时会创建新的实例(非单例) |
request | 每次请求范围内会创建新的实例(web环境中,了解) |
session | 每个会话范围内会创建新的实例(web环境中,了解) |
application | 每个应用范围内会创建新的实例(web环境中,了解) |
设置一个bean的作用域:
- 可以借助Spring中的@Scope注解来进行配置作用域
注意事项:
- singleton
- IOC容器中的bean默认使用的作用域:singleton(单例)
- 默认singleton的bean,在容器启动时被创建,可以使用@Lazy注解来延迟初始化(延迟到第一次使用时)
- prototype
- prototype的bean,在每一次使用该bean的时候都会创建一个新的实例
- 实际开发当中,绝大部分的bean是单例的,也就是说绝大部分bean不需要配置scope属性
第三方Bean
在pom.xml文件中,引入dom4j:
<!--Dom4j-->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
</dependency>
如果需要第三方bean时,通常会单独定义一个配置类
@Configuration // 配置类(在配置类中对第三方bean进行集中的配置管理)
public class CommonConfig {
// 声明第三方bean
@Bean // 将当前方法的返回值对象交给IOC容器管理,成为IOC容器bean
// 通过@Bean注解的name/value属性指定bean名称,如果未指定,默认是方法名
public SAXReader reader(DeptService deptService) {
System.out.println(deptService);
return new SAXReader();
}
}
测试类:
@SpringBootTest
class DemoApplicationTests {
@Autowired
private SAXReader saxReader;
@Test
public void testThirdBean() throws DocumentException {
Document document = saxReader.read(this.getClass().getClassLoader().getResource("test.xml"));
Element rootElement = document.getRootElement();
String name = rootElement.element("name").getText();
String age = rootElement.element("age").getText();
System.out.println(name + ":" + age);
}
}
执行测试方法后,控制台输出日志:
Tom : 18
在方法上加上一个@Bean注解,Spring容器在启动的时候,会自动的调用这个方法,并将方法的返回值声明为Spring容器当中的Bean对象。
注意:
- 通过@Bean注解的name或value属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名
- 如果第三方bean需要依赖其它bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配
关于Bean需要保持的一个原则:
-
如果在项目当中自己定义的类,想将这些类交给IOC容器管理,直接使用@Component以及它的衍生类注解来声明即可
-
如果这个类不是自己定义的,而是引入第三方依赖当中提供的类,而且还想将这个类交给IOC容器管理,此时就需要在配置类中定义一个方法,在方法上加一个@Bean注解,通过这种方式来声明第三方的bean对象
SpringBoot原理
介绍
Spring是目前世界上最流行的Java框架,它可以帮助我们更加快速、更加容易的来构建Java项目。而在Spring家族当中提供了很多优秀的框架,而所有框架都是基于一个基础框架二点SpringFramework(也就是Spring框架)。但是直接基于Spring框架进行项目的开发,会比较繁琐。
主要体现在两个地方:
- 在pom.xml中依赖配置比较繁琐,在项目开发时,需要自己去找到对应的依赖,还需要找到依赖它配套的依赖以及对应的版本,否则就会出现版本冲突问题。
- 在使用Spring框架进行项目开发时,需要在Spring的配置文件中做大量的配置,这就造成了Spring框架入门难度较大,学习成本较高
基于Spring存在的问题,官方在Spring框架4.0版本之后,又推出了一个全新的框架:SpringBoot
通过SpringBoot来简化Spring框架的开发。直接基于SpringBoot来构架Java项目,会让项目开发更加简单,更加快捷
SpringBoot框架之所以用起来更加简单、快捷,是因为SpringBoot框架底层提供了两个重要的功能:一个是起步依赖,一个是自动配置
通过SpringBoot所提供的起步依赖,就可以大大的简化pom文件当中依赖的配置,从而解决了Spring框架当中依赖配置繁琐的问题
通过自动配置的功能就可以大大的简化框架在使用时bean的声明以及bean的配置。只需要引入程序开发时所需要的起步依赖。
起步依赖
假如没有使用SpringBoot,用的是Spring框架进行web程序的开发,此时就需要引入web程序开发所需要的一些依赖
spring-webmvc依赖:这是spring框架进行web程序开发所需要的依赖
servlet-api依赖:Servlet基础依赖
jackson-databind依赖:JSON处理工具包
如果要使用AOP,还需要引入aop依赖:aspect依赖
项目中所引入的这些依赖,还需要保证版本匹配,否则就可能会出现版本冲突问题
但是如果使用SpringBoot的话,就只需要引入web开发的起步依赖:springboot-starter-web
结论:起步依赖的原理就是Maven的依赖传递
- 在SpringBoot提供的这些起步依赖当中,以提供了当前程序开发所需要的所有常见依赖
- 如:springboot-starter-web,这是web开发的常见依赖,在web开发的起步依赖当中,就集成了web开发中常见的依赖:json、web、webmvc、tomcat等。只需要引入这一个依赖,其他的依赖都会自动的通过maven的依赖传递进来
自动配置
SpringBoot的自动配置就是当Spring容器启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要手动声明,从而简化了开发,省去了繁琐的配置操作
@Configuration底层就是@Component,所以配置类最终也是SpringIOC容器当中的一个bean对象
在IOC容器中除了自己定义的bean以外,还有很多配置类,这些配置类都是SpringBoot在启动的时候加载进来的配置类,这些配置类加载进来之后,它会生成很多的bean对象。当要使用这些配置类生成的bean对象时,可以使用@Autowired就自动注入了。
源码小结
自动配置原理源码入口就是@SpringBootApplication注解,在这个注解中封装了3个注解,分别是:
- @SpringBootConfiguration
- 声明当前类是一个配置类
- @ComponentScan
- 进行组件扫描(SpringBoot中默认扫描的就是启动类所在的当前包及其子包)
- @EnableAutoConfiguration
- 封装了@Import注解(Import注解中指定了一个ImportSelector接口的实现类)
- 在实现类重写的selectImports()方法,读取当前项目下所有依赖jar包中METAINF/spring.factories、METAINF/spring/org.springframework.boot.autoconfigure.AutoConfigurat ion.imports两个文件里面定义的配置类(配置类中定义了@Bean注解标识的方法)
@Conditional
条件装配注解:@Conditional
- 作用:按照一定的条件进行判断,在满足给定条件后才会注册对应的bean对象到Spring的IOC容器中
- 位置:方法、类
- @Conditional本身是一个父注解,派生出大量的子注解:
- @ConditionalOnClass:判断环境中有对应字节码文件,才注册到IOC容器
- @ConditionalOnMissingBean:判断环境中没有对应的bean(类型或名称),才注册bean到IOC容器中
- @ConditionalOnProperty:判断配置文件中有对应属性和值,才注册bean到IOC容器