IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> springboot是怎么实现自动配置的? -> 正文阅读

[Java知识库]springboot是怎么实现自动配置的?

一、springboot是对spring框架做的一系列优化,减少了大量繁琐的配置,并提供了内置web服务器,让程序运行更快。

1.springboot起步依赖:简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。

2.自动配置Spring以及第三方功能:

SpringBoot是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置的话,就可以使用application.properties或者application.yml(application.yaml)进行配置。

首先打开spring boot项目在springboot的引导类有一个@SpringBootApplication注解:

@Target({ElementType.TYPE}) //修饰类或接口、枚举
@Retention(RetentionPolicy.RUNTIME)//注解在源码,class文件中存在且运行时可以通过反射机制获取到
@Documented//可以在api文档显示
@Inherited//子类可以继承该注解
@SpringBootConfiguration //配置类
@EnableAutoConfiguration//开启自动装配
@ComponentScan //扫描 (不指明包名则默认范围自己所在包及其子类下)
(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)

除了基本的元注解外,还有两个。其中:@@SpringBootConfiguration的里面核心是

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration//spring的配置类
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

表明启动类其实也是一个配置类。还有一个是@EnableAutoConfiguration,根据名称翻译就是开启自动配置。它里面包含了如下注解:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

可以看到@AutoConfigurationPackage和@Import({AutoConfigurationImportSelector.class})注解加起来就是实现了自动配置的关键。

@import:提供可以显式的从其他地方加载配置类的方式。有三种方式:

1.普通类

2.接口importSelector的实现类

3.接口importBeanDefintionRegistart的实现类

自动配置就是用来第二种方式。importSelector接口中有一个selectImports方法,返回值是一个字符串数组,数组中的每个元素就是将要被导入的配置类的全限定的类名。

@Import导入了一个AutoConfigurationImportSelector.class的选择器。那么如何根据这个选择器来实现自动配置?

spring框架在底层中使用了springfactories机制,它是Java SPI(SPI(Service Provider Interface),是JDK内置的一种服务提供发现机制,可以用来启用框架扩展和替换组件,主要是被框架的开发人员使用,比如java.sql.Driver接口,其他不同厂商可以针对同一接口做出不同的实现,MySQL和PostgreSQL都有不同的实现提供给用户,而Java的SPI机制可以为某个接口寻找服务实现。Java中SPI机制主要思想是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要,其核心思想就是解耦)的延续,可以借助它来实现自动配置的功能。他的核心逻辑是从Classpath中读取到Jar包中的配置文件META-IF/spring.factories,然后根据知道的key从配置文件中解析出对应的value值。?

回到正题:在AutoConfigurationImportSelector.class中有selectImports方法里面调用了getAutoConfigurationEntry(annotationMetadata)方法,它是自动配置的入口。

public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);//自动配置的入口
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

源码如下:

protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            //1.获取annotationMetadata的注解@EnableAutoConfiguration的属性
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
//2.从资源文件中spring.factories中获取EnableAutoConfiguration对应的所有类
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            //3.通过在注解@EnableAutoConfiguration设置exclude的相关属性,可以指定排除的自动配置类
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            //4.根据@Conditional(满足条件是触发)来判断是否排除某些自动配置类
            configurations = this.getConfigurationClassFilter().filter(configurations);
            //5.触发AutoConfiguration导入相关的事件
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

?核心是第2步:拿到所有全限定类名

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//从spring.factorie找出所有的类
        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;
    }

总结下流程:从selectimports方法开始:

1.通过ClassLoader去获取classpath中的配置文件spring.factories

?

2.在spring.factories文件里,筛选出以EnableAutoConfiguration为key的配置类(

?3.再根据@Conditional过滤掉不必要的自动配置类

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-08-19 18:50:24  更:2022-08-19 18:51:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:20:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码