Spring Boot面试杀手锏————自动配置原理

引言

不论在工作中,亦或是求职面试,Spring Boot已经成为我们必知必会的技能项。除了某些老旧的政府项目或金融项目持有观望态度外,如今的各行各业都在飞速的拥抱这个已经不是很新的Spring启动框架。

当然,作为Spring Boot的精髓,自动配置原理的工作过程往往只有在“面试”的时候才能用得上,但是如果在工作中你能够深入的理解Spring Boot的自动配置原理,将无往不利。

Spring Boot的出现,得益于“习惯优于配置”的理念,没有繁琐的配置、难以集成的内容(大多数流行第三方技术都被集成),这是基于Spring 4.x提供的按条件配置Bean的能力。

Spring Boot的配置文件

初识Spring Boot时我们就知道,Spring Boot有一个全局配置文件:application.properties或application.yml。

我们的各种属性都可以在这个文件中进行配置,最常配置的比如:server.port、logging.level.* 等等,然而我们实际用到的往往只是很少的一部分,那么这些属性是否有据可依呢?答案当然是肯定的,这些属性都可以在官方文档中查找到:

https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#common-application-properties

(所以,话又说回来,找资料还得是官方文档,百度出来一大堆,还是稍显业余了一些)

除了官方文档为我们提供了大量的属性解释,我们也可以使用IDE的相关提示功能,比如IDEA的自动提示,和Eclipse的YEdit插件,都可以很好的对你需要配置的属性进行提示,下图是使用Eclipse的YEdit插件的效果,Eclipse的版本是:STS 4。

 以上,是Spring Boot的配置文件的大致使用方法,其实都是些题外话。

那么问题来了:这些配置是如何在Spring Boot项目中生效的呢?那么接下来,就需要聚焦本篇博客的主题:自动配置工作原理或者叫实现方式。

工作原理剖析

Spring Boot关于自动配置的源码在spring-boot-autoconfigure-x.x.x.x.jar中:

当然,自动配置原理的相关描述,官方文档貌似是没有提及。不过我们不难猜出,Spring Boot的启动类上有一个@SpringBootApplication注解,这个注解是Spring Boot项目必不可少的注解。那么自动配置原理一定和这个注解有着千丝万缕的联系!

@EnableAutoConfiguration

 @SpringBootApplication是一个复合注解或派生注解,在@SpringBootApplication中有一个注解@EnableAutoConfiguration,翻译成人话就是开启自动配置,其定义如下:

 而这个注解也是一个派生注解,其中的关键功能由@Import提供,其导入的AutoConfigurationImportSelector的selectImports()方法通过SpringFactoriesLoader.loadFactoryNames()扫描所有具有META-INF/spring.factories的jar包。spring-boot-autoconfigure-x.x.x.x.jar里就有一个这样的spring.factories文件。

这个spring.factories文件也是一组一组的key=value的形式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔,如下图所示:

这个@EnableAutoConfiguration注解通过@SpringBootApplication被间接的标记在了Spring Boot的启动类上。在SpringApplication.run(...)的内部就会执行selectImports()方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。

自动配置生效

每一个XxxxAutoConfiguration自动配置类都是在某些条件之下才会生效的,这些条件的限制在Spring Boot中以注解的形式体现,常见的条件注解有如下几项:

@ConditionalOnBean:当容器里有指定的bean的条件下。

@ConditionalOnMissingBean:当容器里不存在指定bean的条件下。

@ConditionalOnClass:当类路径下有指定类的条件下。

@ConditionalOnMissingClass:当类路径下不存在指定类的条件下。

@ConditionalOnProperty:指定的属性是否有指定的值,比如@ConditionalOnProperties(prefix=”xxx.xxx”, value=”enable”, matchIfMissing=true),代表当xxx.xxx为enable时条件的布尔值为true,如果没有设置的情况下也为true。

以ServletWebServerFactoryAutoConfiguration配置类为例,解释一下全局配置文件中的属性如何生效,比如:server.port=8081,是如何生效的(当然不配置也会有默认值,这个默认值来自于org.apache.catalina.startup.Tomcat)。

在ServletWebServerFactoryAutoConfiguration类上,有一个@EnableConfigurationProperties注解:开启配置属性,而它后面的参数是一个ServerProperties类,这就是习惯优于配置的最终落地点。

在这个类上,我们看到了一个非常熟悉的注解:@ConfigurationProperties,它的作用就是从配置文件中绑定属性到对应的bean上,而@EnableConfigurationProperties负责导入这个已经绑定了属性的bean到spring容器中(见上面截图)。那么所有其他的和这个类相关的属性都可以在全局配置文件中定义,也就是说,真正“限制”我们可以在全局配置文件中配置哪些属性的类就是这些XxxxProperties类,它与配置文件中定义的prefix关键字开头的一组属性是唯一对应的。

至此,我们大致可以了解。在全局配置的属性如:server.port等,通过@ConfigurationProperties注解,绑定到对应的XxxxProperties配置实体类上封装为一个bean,然后再通过@EnableConfigurationProperties注解导入到Spring容器中。

而诸多的XxxxAutoConfiguration自动配置类,就是Spring容器的JavaConfig形式,作用就是为Spring 容器导入bean,而所有导入的bean所需要的属性都通过xxxxProperties的bean来获得。

可能到目前为止还是有所疑惑,但面试的时候,其实远远不需要回答的这么具体,你只需要这样回答:

Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。

通过一张图标来理解一下这一繁复的流程:

 图片来自于王福强老师的博客:https://afoo.me/posts/2015-07-09-how-spring-boot-works.html 

总结

综上是对自动配置原理的讲解。当然,在浏览源码的时候一定要记得不要太过拘泥与代码的实现,而是应该抓住重点脉络。

一定要记得XxxxProperties类的含义是:封装配置文件中相关属性;XxxxAutoConfiguration类的含义是:自动配置类,目的是给容器中添加组件。

而其他的主方法启动,则是为了加载这些五花八门的XxxxAutoConfiguration类。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/558900.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

为什么要坚持写博客

引言 断断续续地写博客已经有一段时间了,作为一个Java中级开发工程师,工作了三年多也算渐渐入了门。不得不说,博客给我的改变是非常大的,那么作为一个技术人员,为什么我觉得必须要坚持写博客?下面&#xf…

Spring Boot——@ConfigurationProperties与@Value的区别

引言 Spring Boot从配置文件中取值的方式有两种,一种是批量注入ConfigurationProperties,另一种是单独注入Value。 它们之间除了批量与单独取值的区别之外,还存在着其他一些使用方式,本篇博客将详细讲解这两种注解之间的区别和使…

Spring Boot —— YAML配置文件

引言 首先,YAML并不是仅仅可以使用在Java项目中,它是一种类似于json结构的标记语言,可以为所有的编程语言服务。它强调更直观的层级表示,比较适合描述配置文件中的层级关系。 Spring Boot可以识别后缀名为".properties&quo…

centos7下docker启动失败解决

centos7下docker启动失败解决 docker安装成功却启动失败,查看docker服务,systemctl status docker.service, 服务日志提示Failed to start Docker Application Container Engine.如下图所示: 解决方法,修改docker文件&#xff0…

Java并发编程实战————Semaphore信号量的使用浅析

引言 本篇博客讲解《Java并发编程实战》中的同步工具类:信号量 的使用和理解。 从概念、含义入手,突出重点,配以代码实例及讲解,并以生活中的案例做类比加强记忆。 什么是信号量 Java中的同步工具类信号量即计数信号量&#x…

JavaCard概述

什么是JavaCard JavaCard,即Java智能卡。以智能卡硬件系统为基础,通过软件的方式构造一个支持Java程序下载、安装、运行的软/硬件系统。由于引入了虚拟机技术,JavaCard具备硬件无关性,即智能卡应用程序开发与智能卡硬件系统相分离…

LeetCode算法入门- Add Two Numbers-day3

LeetCode算法入门- Add Two Numbers-day3 Add Two Numbers You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return …

Java核心篇之多线程---day1

Java面试之多线程—day1 一. 线程中sleep方法与wait方法有什么区别? 对于 sleep()方法,我们首先要知道该方法是属于 Thread 类中的。而 wait()方法,则是属于Object 类中的。 在调用 sleep()方法的过程中, 线程不会释放对象锁。而…

Java 多线程 —— 常用并发容器

引言 本博客基于常用的并发容器,简单概括其基本特性和简单使用,并不涉及较深层次的原理分析和全面的场景用法。 适合对不了解并发容器的同学,工作中遇到类似的场景,能够对文中提到的并发容器留有简单印象就好。 一、Concurrent…

Tomcat运行三种模式:http-bio|http-nio|http-apr介绍

转自《tomcat运行三种模式:http-bio|http-nio|http-apr介绍》 Tomcat是一个小型的轻量级应用服务器,也是JavaEE开发人员最常用的服务器之一。不过,许多开发人员不知道的是,Tomcat Connector(Tomcat连接器)有bio、nio、apr三种运行模式&#…

LeetCode算法入门- Reverse Integer-day6

LeetCode算法入门- Reverse Integer-day6 Given a 32-bit signed integer, reverse digits of an integer. Example 1: Input: 123 Output: 321 Example 2: Input: -123 Output: -321 Example 3: Input: 120 Output: 21 class Solution {public int reverse(int x) {long…

Java工具方法——属性拷贝方法:BeanUtils.copyProperties(Object, Object)

介绍 org.springframework.beans.BeanUtils.copyProperties(Object, Object)是spring 框架的对象工具类:BeanUtils下的一个拷贝对象属性的方法。 官方注释 把给定的源对象属性值拷贝到目标对象中。 注意:源对象类与目标对象类不一定非要完全匹配&…

Git初学札记(九)————EGit检出远程分支

引言 现在有这样一个使用场景:团队中的其他开发者提交了一个新的特性分支(如feature_1),要求我们一同开发,并将自己修改的代码也全部提交到这个分支上去。那么如何将这个分支检出,并将本地检出的分支与这个…

Spring Boot————ApplicationListener实现逃课事件监听

引言 上一篇文章转了一篇关于ApplicationListener用于在Web项目启动时做一些初始化的用法。 但是,在实际生产过程中,当一个事件产生,又是如何被onApplicationEvent()方法监听到,并执行一系列动作呢?简单搜索了一下&a…

Java核心篇之Redis--day4

Java核心篇之Redis–day4 Redis有哪些数据结构? 字符串String、字典Hash、列表List、集合Set、有序集合SortedSet。 1.String:字符串,常用命令:get,set,decr,incr,mget(查…

软件版本GA、RC、beta等含义

原文《软件版本GA、RC、beta等含义》 GA General Availability,正式发布的版本,官方开始推荐广泛使用,国外有的用GA来表示release版本。 RELEASE 正式发布版,官方推荐使用的版本,有的用GA来表示。比如spring。 Sta…

Java核心篇之泛型--day5

Java核心篇之泛型–day5 泛型是JDK5时引入的一个新特性,泛型提供了编译时类型安全检查的机制,该机制允许程序猿在编译时检测到非法的类型输入。 泛型的本质是参数化类型,也就是说操作的类型被指定为一个参数。 假定我们有一个需求&#xff…

Spring Boot————AOP入门案例及切面优先级设置

看了这篇文章,如果你还是不会用AOP来写程序,请你打我!! .||| 引言 Spring AOP是一个对AOP原理的一种实现方式,另外还有其他的AOP实现如AspectJ等。 AOP意为面向切面编程,是通过预编译方式和运行期动态代…

Spring Boot————Spring Data JPA简介

引言 JPA是Java 持久化API的缩写,是一套Java数据持久化的规范, Spring Data Spring Data项目的目的是为了简化构建基于Spring 框架应用的数据访问技术,包括对关系型数据库的访问支持。另外也包含非关系型数据库、Map-Reduce框架、云数据服…

Spring Boot————Spring Boot启动流程分析

一、引言 Spring Boot 的启动虽然仅仅是执行了一个main方法,但实际上,运行流程还是比较复杂的,其中包含几个非常重要的事件回调机制。在实际生产开发中,有时候也会利用这些启动流程中的回调机制,做一些项目初始化的工…