SpringBoot03自动配置的源码分析

自动包配置规则(为什么会默认执行扫描主类所在以及该包所有子包下的我们写的组件)

我们在主程序类的注解是由什么组成的呢?

 核心的为下面三个,我们逐个来分析

 @SpringBootConfiguration

这是一个@Configuration的配置类注解,说明我们的主程序类注解实际上也是一个配置类注解

@CompnentScan

是一个spring里面的包扫描注解,指定对哪些包进行扫描

@EnableAutoConfiguration(核心)

点击进来看看

这玩意也是一个合成注解

1.@AutoConfigurationPackage——翻译为自动配置包?点击查看

 

原来这个注解的本质是导入组件,那导入的这个Registrar组件是干什么的?点击查看

 

AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));

调用了rgistry方法给容器批量注册了组件,注册了哪些?

这个方法传入了参数

 这个参数翻译为注解源信息——也就是传入了我们主程序类这个注解标记在了哪里

 

 但是这个方法自动导入了哪些组件呢?

 (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));

new AutoConfigurationPackages.PackageImports(metadata))为把注解源信息拿到,获取当前主程序类所在的包名。

 .toArray(new String[0]));最后把这个包名封装到数组里面

最后用这个包名,把这个包名下的所有组件Registrar注册到容器之中

这就解释了为什么会有默认的包结构(见该专栏01)

2.@Import({AutoConfigurationImportSelector.class})给容器中批量导入组件,为什么还有?这个又是导入了什么?

点击进来查看里面有这个方法

public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

 selectImpotr为搜索导哪些包,根据下面的语句查找要导的包,最后返回一个字符串类型的数组,进行包导入

我们发现这个方法调用的是getAutoConfigurationEntry(annotationMetadata);这个方法进行搜索查找的,找到这个方法

protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);为获取所有候选的配置,如果获取到了,下面的操作就是对这个configurations进行删除呀,挑选的操作,最后封装返回AutoConfigurationEntry对象供给selectImpotr方法使用,这个configurations里有127个,说明这127个都是需要导入的组件 

所以现在看看这个configurations是从哪里来的,我们点击查看这个方法

得到了

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
    }

List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());

这行代码利用了工厂加载器,加载了什么?点击查看

 

加载了一些什么奇奇怪怪的名字,看看返回的时候调用的方法是什么?

 终于找到了,它最后返回了一个Map类型的对象,应该就是我们要加载的组件

看看这个方法内都干了什么?

我们看到这个方法从,META-INF/spring.factories,这个位置加载了一些东西

现在看看我们导入的jar包里面,有的有META-INF/spring.factories文件夹,有的没有,那么我们springboot核心的jar包

 正好有,而且这个文件里写的是

 里面的结尾都是啥啥啥的自动配置,说明现在接入了各个场景的自动配置,从22行一直到148行,正正好好127个组件,与前文对应上了

总结:

所以其实springboot一启动就加载的所有全场景的组件已经在配置文件中写死了

但是我们启动之后容器中真的有这么多组件吗?

测试

//查看容器中现在有多少个组件
        int beanDefinitionCount = run.getBeanDefinitionCount();
        System.out.println(beanDefinitionCount);

 

只有135个还要算上我们自己写的一些组件,原本的127个根本不够,这是为啥?

 查看核心jar包配置的场景

 

老师的aop包实际上并不能生效,而且有条件装配注解,只有 存在Advice我们下面的代码才能生效,如何才能存在这个类?需要对应的包

但是也没有这个包,不仅仅是aop的功能,包括批处理什么的也不能生效,这是为什么?

 

自动配置的流程

其实自动配置流程的核心就是用条件装配注解判断当前项目需不需要自动配置的组件,如果需要就加,如果不需要就不加,底层源码也需要这样进行判断

那么如果用户想写一些自动配置有的,但是想稍微修改一下自己写怎么办?(修改默认配置)

 @Bean
		@ConditionalOnBean(MultipartResolver.class)  //容器中有这个类型组件
		@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) 
        //容器中没有这个名字 multipartResolver 的组件
		public MultipartResolver multipartResolver(MultipartResolver resolver) {
            //给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。
            //SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范
			// Detect if the user has created a MultipartResolver but named it incorrectly
			return resolver;
		}
        给容器中加入了文件上传解析器;

譬如现在我们想写一个文件上传解析器要修改内容但是不按照规范写名字,我们就可以自己用@Bean注解进行书写,源码会帮助我们判断,当前容器内有文件上传解析器组件,但是名字不规范时(使用条件配置注解判断),让后sqpringboot会从容器中找到文件上传解析器组件,修改好名字再返回

SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先

总结:

所以以后我们想要修改自动配置的一些参数(例如tomcat),只需要在外面定义的配置文件中通过加对应的前置(可以查询文档)再加修改参数就可以了

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值