目录
要搞清楚SpringBoot的自动配置原理,要从SpringBoot启动类上使用的核心注解@SpringBootApplication开始分析:
@SpringBootConfiguration注解上使用了@Configuration,表明SpringBoot启动类就是
@EnableAutoConfiguration注解(自动配置核心注解):
SpingBoot原理
配置优先级
优先级 : 命令行参数 > 系统属性参数 > properties 参数 > yml 参数 > yaml 参数 思考:如果项目已经打包上线了,这个时候我们又如何来设置 Java 系统属性和命令行参数呢? java -Dserver .port = 9000 -jar XXXXX.jar --server .port = 10010 下面我们来演示下打包程序运行时指定 Java 系统属性和命令行参数: 1. 执行 maven 打包指令 package ,把项目打成 jar 文件 2. 使用命令: java -jar 方式运行 jar 文件程序 项目打包: 运行 jar 程序: 同时设置 Java 系统属性和命令行参数 仅设置 Java 系统属性 注意事项: Springboot 项目进行打包时,需要引入插件 spring-boot-maven-plugin ( 基于官网 骨架创建项目,会自动添加该插件 )Bean管理
在前面的课程当中,我们已经讲过了我们可以通过 Spring 当中提供的注解 @Component 以及它的三个衍生注解(@Controller 、 @Service 、 @Repository )来声明 IOC 容器中的 bean 对象,同时我们也学习了如何为应用程序注入运行时所需要依赖的bean 对象,也就是依赖注入 DI 。 我们今天主要学习 IOC 容器中 Bean 的其他使用细节,主要学习以下三方面: 1. 如何从 IOC 容器中手动的获取到 bean 对象 2. bean 的作用域配置 3. 管理第三方的 bean 对象获取Bean
默认情况下, SpringBoot 项目在启动的时候会 自动 的创建 IOC 容器 ( 也称为 Spring 容器 ) ,并且在启动的过程当中会 自动 的将bean 对象都创建好,存放在 IOC 容器当中。应用程序在运行时需要依赖什么 bean对象,就直接进行依赖注入就可以了。 而在 Spring 容器中提供了一些方法,可以主动从 IOC 容器中获取到 bean 对象,下面介绍 3 种常用方式: 1. 根据 name 获取 bean Object getBean ( String name ) 2.根据类型获取bean < T > T getBean ( Class < T > requiredType ) 3. 根据 name 获取 bean (带类型转换) < T > T getBean ( String name , Class < T > requiredType ) 思考:要从 IOC 容器当中来获取到 bean 对象,需要先拿到 IOC 容器对象,怎么样才能拿到 IOC 容器呢? 想获取到 IOC 容器,直接将 IOC 容器对象注入进来就可以了Bean作用域
在前面我们提到的 IOC 容器当中, 默认bean对象是单例模式(只有一个实例对象) 。那么如何设置 bean对象为非单例呢?需要设置bean 的作用域。 在 Spring 中支持五种作用域,后三种在 web 环境才生效: 知道了 bean 的 5 种作用域了,我们要怎么去设置一个 bean 的作用域呢? 可以借助 Spring 中的 @Scope 注解来进行配置作用域 注意事项: IOC 容器中的 bean 默认使用的作用域: singleton ( 单例 ) 默认 singleton 的 bean ,在 容器启动时被创建 ,可以使用 @Lazy注解 来延迟初始化 ( 延迟到 第一次使用时 ) 注意事项: prototype 的 bean ,每一次使用该 bean 的时候都会创建一个新的实例 实际开发当中, 绝大部分的Bean是单例的 ,也就是说绝大部分 Bean 不需要配置 scope 属性第三方Bean
学习完 bean 的获取、 bean 的作用域之后,接下来我们再来学习第三方 bean 的配置。 之前我们所配置的 bean ,像 controller 、 service , dao 三层体系下编写的类,这些类都是我们在项 目当中自己定义的类 ( 自定义类 ) 。当我们要声明这些 bean ,也非常简单,我们只需要在类上加上 @Component 以及它的这三个衍生注解( @Controller 、 @Service 、 @Repository ),就可以来声 明这个 bean 对象了。 但是在我们项目开发当中,还有一种情况就是这个类它不是我们自己编写的,而是我们引入的第三方依赖当中提供的。 那么我们应该怎样使用并定义第三方的 bean 呢? 如果要管理的 bean 对象来自于第三方(不是自定义的),是无法用 @Component 及衍生注解声明 bean 的,就需要用到 @Bean 注解。 说明 :以上在 启动类中声明第三方Bean的作法 , 不建议使用 ( 项目中要保证启动类的纯粹性 )SpringBoot原理
SpringBoot 使我们能够集中精力地去关注业务功能的开发,而不用过多地关注框架本身的配置使用。而我们前面所讲解的都是面向应用层面的技术,接下来我们开始学习SpringBoot 的原理,这部分内容偏向于底层的原理分析。 在剖析 SpringBoot 的原理之前,我们先来快速回顾一下我们前面所讲解的 Spring 家族的框架。 Spring 是目前世界上最流行的 Java 框架,它可以帮助我们更加快速、更加容易的来构建 Java 项目。而在Spring 家族当中提供了很多优秀的框架,而所有的框架都是基于一个基础框架的 SpringFramework( 也就是 Spring 框架 ) 。而前面我们也提到,如果我们直接基于 Spring 框架进行项 目的开发,会比较繁琐。 这个繁琐主要体现在两个地方: 1. 在 pom.xml 中依赖配置比较繁琐,在项目开发时,需要自己去找到对应的依赖,还需要找到依赖 它所配套的依赖以及对应版本,否则就会出现版本冲突问题。 2. 在使用 Spring 框架进行项目开发时,需要在 Spring 的配置文件中做大量的配置,这就造成 Spring 框架入门难度较大,学习成本较高。 基于 Spring 存在的问题,官方在 Spring 框架 4.0 版本之后,又推出了一个全新的框架:SpringBoot。 通过 SpringBoot 来简化 Spring 框架的开发 ( 是简化不是替代 ) 。我们直接基于 SpringBoot 来 构建 Java 项目,会让我们的项目开发更加简单,更加快捷。 SpringBoot 框架之所以使用起来更简单更快捷,是因为 SpringBoot 框架底层提供了两个非常重要的 功能: 一个是起步依赖,一个是自动配置。 通过 SpringBoot 所提供的起步依赖,就可以大大的简化 pom 文件当中依赖的配置,从而解决了 Spring 框架当中依赖配置繁琐的问题。 通过自动配置的功能就可以大大的简化框架在使用时 bean 的声明以及 bean 的配置。我们只需要引 入程序开发时所需要的起步依赖,项目开发时所用到常见的配置都已经有了,我们直接使用就可以 了。起步依赖
如果我们使用了 SpringBoot ,就不需要像上面这么繁琐的引入依赖了。我们只需要引入一个依赖就可以了,那就是web 开发的起步依赖: springboot-starter-web 。 为什么我们只需要引入一个 web 开发的起步依赖, web 开发所需要的所有的依赖都有了呢? 因为Maven的依赖传递。 结论:起步依赖的原理就是Maven的依赖传递。自动配置
SpringBoot 的自动配置就是当 Spring 容器启动后,一些配置类、 bean 对象就自动存入到了 IOC 容器 中,不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作。自动配置原理
思考:引入进来的第三方依赖当中的 bean 以及配置类为什么没有生效? • 原因在我们之前讲解IOC 的时候有提到过,在类上添加 @Component 注解来声明 bean 对象时,还需要保证@Component 注解能被 Spring 的组件扫描到。 • SpringBoot项目中的 @SpringBootApplication 注解,具有包扫描的作用,但是它只会扫描启 动类所在的当前包以及子包。 • 当前包: com.itheima , 第三方依赖中提供的包: com.example ( 扫描不到 ) 那么如何解决以上问题的呢? 方案1:@ComponentScan 组件扫描 缺点: 1. 使用繁琐 2. 性能低 方案2:@Import 导入(使用@Import导入的类会被Spring加载到IOC容器中) 1). 使用 @Import 导入普通类: 2). 使用 @Import 导入配置类: 3). 使用 @Import 导入 ImportSelector 接口实现类: 4). 使用第三方依赖提供的 @EnableXxxxx 注解原理分析
源码跟踪技巧: 在跟踪框架源码的时候,一定要抓住关键点,找到核心流程。一定不要从头到尾一行代码去看,一 个方法的去研究,一定要找到关键流程,抓住关键点,先在宏观上对整个流程或者整个原理有一个 认识,有精力再去研究其中的细节。要搞清楚SpringBoot的自动配置原理,要从SpringBoot启动类上使用的核心注解@SpringBootApplication开始分析:
@SpringBootConfiguration注解上使用了@Configuration,表明SpringBoot启动类就是
一个配置类。 @Indexed 注解,是用来加速应用启动的(不用关心)。@ComponentScan注解:
@ComponentScan 注解是用来进行组件扫描的,扫描启动类 所在的包及其子包下所有被 @Component及其衍生注解声明的类。 SpringBoot 启动类,之所以 具备扫描包功能 ,就是因为包含了 @ComponentScan 注解。@EnableAutoConfiguration注解(自动配置核心注解):
使用@Import注解,导入了实现ImportSelector接口的实现类。
AutoConfigurationImportSelector类是ImportSelector接口的实现类。
AutoConfigurationImportSelector 类中重写了 ImportSelector 接口的 selectImports() 方 法: selectImports() 方法底层调用 getAutoConfigurationEntry() 方法,获取可自动配置的 配置类信息集合 getAutoConfigurationEntry() 方法通过调用 getCandidateConfigurations(annotationMetadata, attributes) 方法获取在配置文 件中配置的所有自动配置类的集合 getCandidateConfigurations 方法的功能: 获取所有基于 META INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imp orts 文件、 META-INF/spring.factories 文件中配置类的集合 META- INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件和 META-INF/spring.factories 文件这两个文件在哪里呢? 通常在引入的起步依赖中,都有包含以上两个文件