一文搞懂SpringBoot自动配置原理

前言

了解了SpringBoot中的bean配置以后,我们来看看springboot最核心的注解?@SpringBootApplication
,我们知道每个SpringBoot得启动类上都会标注这个注解,代表此类为主要运行类,似乎加上了这个注解以后,我们的一些bean就能自动的配置注入进ioc容器中了,到底是如何实现的呢?我们来点开此注解,看看内部的实现:一键获取spring全家桶福利

可以看到@Import注解给我们导入了一个AutoConfigurationImportSelector 类,这个类从名字上看起来就和自动配置选择有关系,我们继续点进去看看,发现了一个很重要的方法–selectImports ,如下:

可以看到其中有一个getCandidateConfigurations 的方法,看名称我们可以猜到此方法负责获取所有的自动配置的信息,而此方法的代码如图:

可以看到SpringBoot调用了SpringFactoriesLoader.loadFactoryNames方法获取其中的所有的名称列表,而此方法中我们可以看到一个查找路径的常量:

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
1.

SpringBoot会查找当前工程包括所有依赖的jar的META-INF路径下的

spring.factories文件,似乎所有的自动配置的类都是从这里读取来的,而加载的过程代码如下:

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {		// 若缓存里有直接返回缓存的值
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		try {
            // 类加载器对象存在则用这个加载器获取上面说的常量路径里的资源,不存在则用系统类加载器去获取	
			Enumeration<URL> urls = (classLoader != null ?
			classLoader.getResources(FACTORIES_RESOURCE_LOCATION) ://当前classloader是appclassloader,getResources能获取所有依赖jar里面的META-INF/spring.factories的完整路径
			ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) { // 遍历上述返回的url集合
				URL url = urls.nextElement(); // URL类可以获取来自流,web,甚至jar包里面的资源
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) { // 解析spring.factories文件
					List<String> factoryClassNames = Arrays.asList(
					StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
// spring.facories中配置的不仅仅有自动配置相关的内容,还有其他比如ApplicationContextInitializer等等各种springboot启动的时候,初始化spring环境需要的配置,自动配置只是其中一项。这个cache也是在springboot启动阶段赋值的
                      result.addAll((String) entry.getKey(), factoryClassNames);
				}
			}
			cache.put(classLoader, result);
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}
1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.

看到这里我们进入当前项目的maven本地仓库,找到我们之前的spring-boot-starter-jdbc jar,解压以后的确有一个META-INF目录,但是目录里并没有spring.factories文件,只有一个spring.provides 文件,当我们打开此文件后以后,发现里面并没有我们想象的自动配置相关的类信息,如图:

这里的provides提供者是什么意思?难道是后面的三个名称是jar的名称?spring-boot-starter-jdbc.jar会帮我们自动的下载依赖这三个jar,所以我们想要的spring.factories文件就在这几个jar里面?当我们查看仓库的时候,的确发现了这几个jar,但是很遗憾,这几个jar仅仅就是基础jar,并不包含这些文件,那么,spring.factories文件在哪?还记得我们给SpringBoot启动类上标记了exclude = DataSourceAutoConfiguration.class ,就可以排除了jdbc数据源自动配置带来的问题了,那我们去看看这里有什么线索吧,点开DataSourceAutoConfiguration 类,我们可以看到有一个@Conditional族的组合条件注解,限制为当DataSource.class, EmbeddedDatabaseType.class被classloader加载,则这个配置类生效 ,那么当我们加入spring-boot-starter-jdbc以后,会帮我们自动依赖相关的三个jar,这个时候,这些class也会被加载进去,此条件就满足了,自然就触发了自动配置,那么,这个自动配置自然由SpringBoot提供的了,我们查看SpringBoot的star,终于找到了META-INF/spring.factories文件,打开内容如下:

至此我们的猜想已经得到验证,SpringBoot的自动配置是依靠读取META-INF/spring.factories文件的内容进行配置,并且根据**@Conditional**族的条件注解,进行限制是否自动配置,从而实现动态的配置与排除bean的功能

动手实现自己的自动配置

了解了自动配置的原理,我们不禁有了想自己实现一个自动配置的想法,首先我们来整理一下自动配置所需要的步骤:

1.编写Java Config类,使用@Configuration注解来进行bean自动配置的条件选择

2.编写META-INF/spring.factories文件,将我们需要自动配置的类编写进去,使得SpringBoot在读取的时候能将此类加载进去

首先我们创建一个自动配置的Maven工程,名称为–gank-spring-boot-autoconfigure,在此工程的pom中我们只要依赖Springboot的自动配置相关jar以及我们需要被自动配置进去的类所在的jar,pom依赖如下:

<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-autoconfigure</artifactId>
		</dependency>
        <!--将需要被自动配置进去的类所在的jar依赖进来-->
		<dependency>
			<groupId>gank.spring.hello</groupId>
			<artifactId>gank</artifactId>
			<version>0.0.1-SNAPSHOT</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>
1.2.3.4.5.6.7.8.9.10.11.12.13.

这里我们实现了一个简单的被自动配置的jar–gank,只有一个GankApplicationRunner类,代码如下:

@Slf4j
public class GankApplicationRunner implements ApplicationRunner {
    public GankApplicationRunner() {
        log.info("初始化 GankApplicationRunner.");
    }

    public void run(ApplicationArguments args) throws Exception {
        log.info("Hello Spring! ");
    }
}
1.2.3.4.5.6.7.8.9.10.

依赖和被配置的jar都做好了,我们可以开始编写java Config类了,在

gank-spring-boot-autoconfigure中,我们创建了GankAutoConfiguration配置类,代码如下:

@Configuration
@ConditionalOnClass(GankApplicationRunner.class)
public class GankAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean(GankApplicationRunner.class)
   //配置文件中gank.enabled的值为true才创建,不存在默认为true
    @ConditionalOnProperty(name = "gank.enabled", havingValue = "true", matchIfMissing = true)
    public GankApplicationRunner gankApplicationRunner() {
        return new GankApplicationRunner();
    }
}
1.2.3.4.5.6.7.8.9.10.11.

这里我们需要满足条件,即不存在GankApplicationRunner类实例,并且配置中的gank.enabled参数为true,我们才会进行GankApplicationRunner的bean创建,自动配置类编写完毕后,我们在resources目录下,创建META-INF资源包,并且在该目录下创建spring.factories文件,将我们刚才编写的GankAutoConfiguration配置类编写上去,如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
gank.spring.hello.GankAutoConfiguration
1.2.

至此,我们的自动配置包编写完成,接下来我们创建一个Spingboot-demo工程,pom依赖中我们将刚才的创建的两个工程进行依赖,pom配置如下:

<dependency>
			<groupId>gank.spring.hello</groupId>
			<artifactId>gank-spring-boot-autoconfigure</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>

		<dependency>
			<groupId>gank.spring.hello</groupId>
			<artifactId>gank</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
1.2.3.4.5.6.7.8.9.10.11.

在这里,我们给application.properties文件中配置一下:

复制

## 学习福利

**【Android 详细知识点思维脑图(技能树)】**

> ![SpringBoot自动配置,成功拿下大厂offer_程序员_06](https://s7.51cto.com/images/20210903/1630664438386549.jpg)

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,**现在高级工程师还是比较缺少的**,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

> 这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

![SpringBoot自动配置,成功拿下大厂offer_移动开发_07](https://s9.51cto.com/images/20210903/1630664438846681.jpg)

详细整理在腾讯文档上可以看见;

**[Android架构视频+BAT面试专题PDF+学习笔记](https://gitee.com/vip204888/android-p7)**

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

最后

spring核心笔记文档整理分享:

一文搞懂SpringBoot自动配置原理_第1张图片

另外还整理成了40多套PDF文档:全套的Java面试宝典手册,“性能调优+微服务架构+并发编程+开源框架+分布式”等七大面试专栏,包含Tomcat、JVM、MySQL、SpringCloud、SpringBoot、Dubbo、并发、Spring、SpringMVC、MyBatis、Zookeeper、Ngnix、Kafka、MQ、Redis、MongoDB、memcached等等。如果你对这个感兴趣,小编可以免费分享。

添加 博主 获取资料

你可能感兴趣的:(spring,boot,java,spring)