栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot自动配置原理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot自动配置原理

SpringBoot自动配置原理 一、前言 二、原理

我们需要从Spring Boot项目的启动类开始跟踪,在启动类上我们一般会加入SpringBootApplication注解,

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.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 {
     ......
}

重点介绍如下三个注解:(敲黑板)

@SpringBootConfiguration :作用就相当于**@Configuration**注解,被注解的类将成为一个bean配置类
@EnableAutoConfiguration :这个注解很重要,借助@import的支持,收集和注册依赖包中相关的bean定义
@ComponentScan :作用就是自动扫描并加载符合条件的组件,最终将这些bean加载到spring容器中

②继续跟踪**@EnableAutoConfiguration**注解源码:

@SuppressWarnings("deprecation") 
@Target(ElementType.TYPE) 
@Retention(RetentionPolicy.RUNTIME)
@documented 
@Inherited
@AutoConfigurationPackage
@import(EnableAutoConfigurationimportSelector.class)  //EnableAutoConfigurationimportSelector批量导入bean
public @interface EnableAutoConfiguration { // ... } 
    

@EnableAutoConfiguration注解引入了@import这个注解。

import:导入需要自动配置的组件,此处为EnableAutoConfigurationimportSelector这个类(这块需要了解@import的相关知识)

​ 重写了selectimports方法,将返回的String[]导入到spring容器中

④EnableAutoConfigurationimportSelector类源码如下:

@Override
public String[] selectimports(Annotationmetadata annotationmetadata) {
    if (!isEnabled(annotationmetadata)) {
        return NO_importS;
    }
    
    AutoConfigurationmetadata autoConfigurationmetadata = AutoConfigurationmetadataLoader
        .loadmetadata(this.beanClassLoader);
    
    AnnotationAttributes attributes = getAttributes(annotationmetadata);
    
    List configurations = getCandidateConfigurations(annotationmetadata,attributes);
    configurations = removeDuplicates(configurations);
    
    Set exclusions = getExclusions(annotationmetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    
    configurations = filter(configurations, autoConfigurationmetadata);
    
    fireAutoConfigurationimportEvents(configurations, exclusions);
    return StringUtils.toStringArray(configurations);
}


private void fireAutoConfigurationimportEvents(List configurations,
                                               Set exclusions) {
    List listeners = getAutoConfigurationimportListeners();
    if (!listeners.isEmpty()) {
        AutoConfigurationimportEvent event = new AutoConfigurationimportEvent(this,
                                                                              configurations, exclusions);
        for (AutoConfigurationimportListener listener : listeners) {
            invokeAwareMethods(listener);
            listener.onAutoConfigurationimportEvent(event);
        }
    }
 }

继续看**getCandidateConfigurations(annotationmetadata,attributes)**方法

protected List getCandidateConfigurations(Annotationmetadata metadata, AnnotationAttributes attributes) {
        // 加载工程名称
		List 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;
	}

Spring工厂加载器加载工厂名称

扫描具有meta-INF/spring.factories文件的jar包

public static List loadFactoryNames(Class factoryType, @Nullable ClassLoader classLoader) {
		String factoryTypeName = factoryType.getName();
		return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
	}

private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
    MultiValueMap result = cache.get(classLoader);
    if (result != null) {
        return result;
    }

    try {
        Enumeration 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;
    }
    catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load factories from location [" +
                                           FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
}

spring.factories文件是Key=Value形式,多个Value时使用,隔开,该文件中定义了关于初始化,监听器等信息,而真正使自动配置生效的key是org.springframework.boot.autoconfigure.EnableAutoConfiguration,如下所示:

 # Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,
//省略

上面的EnableAutoConfiguration配置了多个类,这些都是Spring Boot中的自动配置相关类;在启动过程中会解析对应类配置信息。每个Configuation类都定义了相关bean的实例化配置。都说明了哪些bean可以被自动配置,什么条件下可以自动配置,并把这些bean实例化出来,下面的初始化数据源的部分源码:

@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@import({ Registrar.class, DataSourcePoolmetadataProvidersConfiguration.class })
public class DataSourceAutoConfiguration {

    private static final Log logger = LogFactory
            .getLog(DataSourceAutoConfiguration.class);

    @Bean
    @ConditionalOnMissingBean
    public DataSourceInitializer dataSourceInitializer(DataSourceProperties properties,
            ApplicationContext applicationContext) {
        return new DataSourceInitializer(properties, applicationContext);
    }
    //略
}

会用到很多常用的注解

三、相关注解
@Configuration:这个配置就不用多做解释了,我们一直在使用
@EnableConfigurationProperties:这是一个开启使用配置参数的注解,value值就是我们配置实体参数映射的ClassType,将配置实体作为配置来源。
以下为SpringBoot内置条件注解:
@ConditionalOnBean:当SpringIoc容器内存在指定Bean的条件
@ConditionalOnClass:当SpringIoc容器内存在指定Class的条件
@ConditionalOnexpression:基于SpEL表达式作为判断条件
@ConditionalOnJava:基于JVM版本作为判断条件
@ConditionalOnJndi:在JNDI存在时查找指定的位置
@ConditionalOnMissingBean:当SpringIoc容器内不存在指定Bean的条件
@ConditionalOnMissingClass:当SpringIoc容器内不存在指定Class的条件
@ConditionalOnNotWebApplication:当前项目不是Web项目的条件
@ConditionalOnProperty:指定的属性是否有指定的值
@ConditionalOnResource:类路径是否有指定的值
@ConditionalOnSingleCandidate:当指定Bean在SpringIoc容器内只有一个,或者虽然有多个但是指定首选的Bean
@ConditionalOnWebApplication:当前项目是Web项目的条件

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/343276.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号