首页 > 编程语言 > 详细

SpringBoot是如何自动配置的-源码探索

时间:2020-12-30 16:23:25      阅读:39      评论:0      收藏:0      [点我收藏+]

前言:当我们创建一个SpringBoot项目的时候,我们只需要在启动类加一个@SpringBootApplication就可以启动项目,那么这个注解为我们做了哪些事呢?下面,我们来探索下源码。

一、@SpringBootApplication

一个这个注解相当于@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan()这三个注解

1、@SpringBootConfiguration

这个注解告诉我们是个配置类,当然,springboot2.0增加了proxyBeanMethods(),他的意思是是否需要代理,我们后面再讲,你现在只需要知道这是一个配置类。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    //代理方法,默认true
    boolean proxyBeanMethods() default true;
}
2、@ComponentScan()

默认扫描启动类所在包以及所有子包

3、@EnableAutoConfiguration

这个才是最核心的一个注解,开启自动装配。我们点进这个注解,发现有两个核心的注解配置,

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

(1)那么@AutoConfigurationPackage是怎么自动配置包的呢,继续点进这个注解

@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

原来是利用Registrar导入一系列组件,我们把源码拎出来单独分析下

/**
	 * {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
	 * configuration.
	 */
	static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

		@Override
		public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
			//根据注解的元数据metadata,将指定的包下的组件全部导入进来
			register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
		}

		@Override
		public Set<Object> determineImports(AnnotationMetadata metadata) {
			return Collections.singleton(new PackageImports(metadata));
		}

	}

(2)@Import(AutoConfigurationImportSelector.class)
点进这个AutoConfigurationImportSelector,我们发现有这么一个方法:

@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		//批量导入,我们拎出来这个方法继续看 getAutoConfigurationEntry
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		
		//获取到所有需要导入到容器中的配置类
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

技术分享图片
然后一直跟发现是这个方法,帮我们加载到了所有的组件

 private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
// 扫描当前系统所有位于META-INF/spring.factories这个位置的组件,就是上面那图的127个文件
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryTypeName = ((String)entry.getKey()).trim();
                        String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        int var10 = var9.length;

                        for(int var11 = 0; var11 < var10; ++var11) {
                            String factoryImplementationName = var9[var11];
                            result.add(factoryTypeName, factoryImplementationName.trim());
                        }
                    }
                }

                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
            }
        }

二、总结下:

SpringBoot先加载所有的自动配置类,每个自动配置类按照条件生效,默认都会绑定配置文件指定的值,在xxxProperties中,生效的配置就会给容器中装很多组件,只要容器中有这些组件,相当于这些功能就有了。如果你想用自己的定制化配置,可以加注解@Bean定制自己的配置,加载的时候就会去获取指定的值的。

三、作者说:写博客是记录我的学习过程以及笔记心得,如果不对的地方还请不吝赐教,不胜感激!

SpringBoot是如何自动配置的-源码探索

原文:https://www.cnblogs.com/summerSun-tech/p/14211515.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!