关于springboot的自动配置原理理解

现在企业后端很多都是用springboot。
springboot比传统我们使用的SSM框架开发便捷很多。
我们在理解springboot的时候,不要把它当成一个新的框架,它其实是默认了很多框架的使用方式,就像Maven整合了所有的Jar包,springboot整合了所有的框架。我们需要使用哪一个框架,只需要在Maven中导入相应的starter(启动器)即可。

所以我们得出springboot的优点在于:
(1)它为所有spring开发者更快的入门
(2)开箱即用,提供各种默认配置来简化项目配置
(3)内嵌式服务容器简化WEB项目
(4)没有冗余代码生成和XML配置要求

springboot开发简单最注重要的一个原因就是它的自动配置原理!!!
在这里,我们重点来根据源码来理解一下这个过程。

(1) pom.xml(Maven)

我们直到,一个项目的了解,我们要从它的Maven,也就是pom.xml中去看它导入了什么包。
打开pom.xml,我们首先可以看到:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
        <relativePath/>
</parent>

点进去,我们会发现:

 <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.3.0.RELEASE</version>
  </parent>

这里才是真正管理springboot里面所有依赖版本的地方,是springboot的整个大脑。
除此之外,在这个pom.xml配置文件下,我们会发现很多springboot-boot-starter-xxx这些配置我们叫做启动器,有很多这样的启动器。其实是springboot把很多场景都提取出来,比如,mybatis,web,…,你的项目需要什么场景,你就导入什么starter(启动器)即可。

(2)主启动类

启动一个springboot项目,我们通常要在主动类底下启动,即:

package com.lpd;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//说明这是一个springboot的项目
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
    	//通过反射机制,加载.class文件。
    	//注意:这里其实是启动了一个服务。
        SpringApplication.run(DemoApplication.class, args);
    }
}

我们接下来点开@SpringbootApplication注解,我们会发现三个很重要的注解**(面试常问)**:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

(1)@springbootConfiguration
标注在某个类上说明这个类是主配置类,springboot就应该运行这个类的main方法来启动springboot应用,我们可以继续点开它的源码,会发现@Configuration,我们直到,这注解是实现配置文件的功能。
(2)@ComponentScan
这个也是比较重要的一个注解,它对应xml配置中的元素,主要作用是自动扫描并加载符合条件的组件(bean),将这个bean定义加载到IOC容器中。
(3)@EnableAutoConfiguration
这是开启自动配置功能的主要组件。我们家下来详细看下这个配置!

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//自动配置包
@AutoConfigurationPackage
//给容器导入一个组件:导入AutoConfigurationImportSelector.class
//AutoConfigurationImportSelector.class:自动配置导入选择器
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 * @return the classes to exclude
	 */
	Class<?>[] exclude() default {};

	/**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	String[] excludeName() default {};

}

在这个源码中,最重要的就是这个AutoConfigurationImportSelector.class,中文名是自动配置导入选择器,那么到底会导入哪些配置的选择器呢?我们进入这个源码来看下:
这个类底下有这么一个方法:

//获取候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//在这里我们调用了springFactoriesLoader类的静态方法loadFactoryNames
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

我们点击springFactoriesLoader的源码进去,我们会看到:

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

我们会发现有这么一个常量,它对应的是一个地址
我们再返回点击看下loadFactoryNames()方法底下的源码,我们会看到:

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.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
						result.add(factoryTypeName, factoryImplementationName.trim());
					}
				}
			}
			cache.put(classLoader, result);
			return result;
		}

我们看到:
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
这两行代码,我们要从后面这个地方加载文件,我们点开FACTORIES_RESOURCE_LOCATION,我们会看到:

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

还是指向这个地址!!!
我们会发现,自动配置类一直加载的都是META-INF/spring.factories这个类,我们全局搜索它,会发现这个文件位于这里:
在这里插入图片描述
原来自动配置类中自动配置到项目中的文件都是在这里啊!
springboot启动的时候会从类路径META-INF/SPRING.FACTORIES中获取EnableAutoConfiguration指定的值。
接下来,我们去看下这个文件底下到底是什么?

(3)spring.factories

我截取了一小段,大家看下:
在这里插入图片描述
我们会发现,这个包底下全是XXXXAutoConfiguration这些类,springboot会将所有我们在项目中出现的场景全部集中到这里,如果需要使用哪一个场景,在pom.xml文件中导入相应的starter即可,那么我们知道spring.factories这个包底下的文件并不是都会生效的,我们怎么查看这个类是否生效呢?我们可以点开进去看:
比如,我们启动一个项目,里面没有开启RSocketRequesterAutoConfiguration这个场景:`

/*
 * Copyright 2012-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.autoconfigure.rsocket;

import io.rsocket.RSocketFactory;
import io.rsocket.transport.netty.server.TcpServerTransport;
import reactor.netty.http.server.HttpServer;

import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.messaging.rsocket.RSocketRequester;
import org.springframework.messaging.rsocket.RSocketStrategies;

/**
 * {@link EnableAutoConfiguration Auto-configuration} for
 * {@link org.springframework.messaging.rsocket.RSocketRequester}. This auto-configuration
 * creates {@link org.springframework.messaging.rsocket.RSocketRequester.Builder}
 * prototype beans, as the builders are stateful and should not be reused to build
 * requester instances with different configurations.
 *
 * @author Brian Clozel
 * @since 2.2.0
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ RSocketRequester.class, RSocketFactory.class, HttpServer.class, TcpServerTransport.class })
@AutoConfigureAfter(RSocketStrategiesAutoConfiguration.class)
public class RSocketRequesterAutoConfiguration {

	@Bean
	@Scope("prototype")
	@ConditionalOnMissingBean
	public RSocketRequester.Builder rSocketRequesterBuilder(RSocketStrategies strategies) {
		return RSocketRequester.builder().rsocketStrategies(strategies);
	}

}

我们会发现**@conditionalOnClass**这个注解底下的文件都是报红的,这代表没有这个场景。‘
所以我们了解到@conditionalOnClass这个注解,用来判断是否导入了某个场景!

这时候,我突然想到一个问题,我们通常会在application.aml/和application.properties这个配置文件下配置我们项目的一下配置,那么这和这个自动导入类有什么关联吗?

在这里,我们了解到还有一个很重要的注解,我们开启一个导入了WEB的项目,我们在spring.factories这个包下点开WebMvcAutoConfiguration这个类:

@Configuration(proxyBeanMethods = false)
	@Import(EnableWebMvcConfiguration.class)
	@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
	@Order(0)

我们会发现一个注解叫做**@EnableConfigurationProperties**,这个类底下的.class文件就是和application.aml/和application.properties进行交互,进行我们项目的自定义配置。

以上就是我对spriingboot自动装配一些简单的理解,希望有朋友看到我的文章后,如果发现有错,请与我交流下,谢谢!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值