SpringBoot中的自动配置原理详解

 更新时间:2024年01月09日 10:08:54   作者:玄月沐影  
这篇文章主要介绍了SpringBoot中的自动配置原理详解,springboot的自动配置类直观的表现就是通过一系列的注解,使得springboot项目在启动的时候从配置文件中加载需要自动配置的类,注入容器中,需要的朋友可以参考下

引言

springboot的自动配置类直观的表现就是:通过一系列的注解,使得springboot项目在启动的时候从配置文件中加载需要自动配置的类。

如果该配置类有引入相关的jar的文件的时候,springboot便会让对应的类实例化,注入容器中。

即做到在没有任何配置的情况下就可直接使用。当没有引入对应的jar文件的时候springboot便不会自动实例化配置类。

@SpringBootApplication原理

要想理解其中的原因核心便是围绕一个注解@SpringBootApplication

@SpringBootApplication注解

直接上源码:

@Target(ElementType.TYPE)//表示@SpringBootApplication的使用位置,表示用在类上
//1.CONSTRUCTOR:用于描述构造器
//2.FIELD:用于描述域
//3.LOCAL_VARIABLE:用于描述局部变量
//4.METHOD:用于描述方法
//5.PACKAGE:用于描述包
//6.PARAMETER:用于描述参数
//7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
@Retention(RetentionPolicy.RUNTIME)//表示@SpringBootApplication的存在阶段。
//1.RetentionPolicy.SOURCE —— 这种类型的Annotations只在源代码级别保留,编译时就会被忽略
//2.RetentionPolicy.CLASS —— 这种类型的Annotations编译时被保留,在class文件中存在,但JVM将 会忽略
//3.RetentionPolicy.RUNTIME —— 这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用.
@Documented// “文档” 注解表明这个注解应该被 javadoc工具记录
@Inherited//“继承” 修饰@SpringBootApplication后,那么@SpringBootApplication用在哪个类上,且该类有子类的话,子类是可以继承父类中的@SpringBootApplication
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

可以看到其是一个复合注解前面的几个是元注解并不是核心自动配置的原因重点在@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan这三个注解。

@SpringBootConfiguration注解

源码:

@Configuration
public @interface SpringBootConfiguration {...}

再一层

@Configuration注解

@Component
public @interface Configuration {...}

可以看到本质是个@Component,这个注解很熟悉了吧,再SSM阶段直接在spring的xml配置<context:component-scan /> 或者 @ComponentScan,容器启动的时候会扫描所有含有@Component的类,通过反射机制将类的信息加载到内存中给IOC使用。

补充@Configuration的使用

1.@Configuration告诉springboot其修饰的类是一个配置类

@Configuration和@Bean联合使用其等价<bean id='xxx' class='xxx.xxx'>。。。</bean>

@Configuration
public class Configuration {
    // 任何标志了@Bean的方法,其返回值将作为一个bean注册到Spring的IOC容器中
    // 方法名默认成为该bean定义的id
    @Bean
    public UserBean user() {
        return new UserBean();
    }
}

故再退一步@SpringBootConfiguration注解会标注一个类是javaConfig,在spring或者springboot启动的时候会被扫描。

可以根据@Bean注解实例化对象,作用等于在spring的xml文中定义一个< bean > < /bean> 。

@EnableAutoConfiguration注解

@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {...}

@Import(EnableAutoConfigurationImportSelector.class)

可以看到其使用了@Import注解:本质是为了引入类EnableAutoConfigurationImportSelector类,进入其父类AutoConfigurationImportSelector的selectImports()方法,核心代码如下:

// 从配置文件"META-INF/spring-autoconfigure-metadata.properties"中加载 AutoConfigurationMetadata
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
    .loadMetadata(this.beanClassLoader);
//从注解中加载exclude和excludeName
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//从所有jar包下的/META-INF/spring.factories的文件中获取到候选的自动配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);//重中之重
configurations = removeDuplicates(configurations);
configurations = sort(configurations, autoConfigurationMetadata);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return configurations.toArray(new String[configurations.size()]);

在这里插入图片描述

关于META-INF/spring.factories其再spring-boot-autoconfigure-1.5.9.RELEASE.jar下

在这里插入图片描述

@AutoConfigurationPackage注解

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

@Import(AutoConfigurationPackages.Registrar.class)

它通过将Registrar类导入到容器中,而Registrar类作用是扫描主配置类同级目录以及子包,并将相应的组件导入到springboot创建管理的容器中;

我们实际上将我们自己的包下的组件注入容器依赖的还是@AutoConfigurationPackage注解

public static void register(BeanDefinitionRegistry registry, String... packageNames) {
		if (registry.containsBeanDefinition(BEAN)) {
			BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
			ConstructorArgumentValues constructorArguments = beanDefinition
					.getConstructorArgumentValues();
			constructorArguments.addIndexedArgumentValue(0,
					addBasePackages(constructorArguments, packageNames));
		}
		else {
			GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
			beanDefinition.setBeanClass(BasePackages.class);
			beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,
					packageNames);
			beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            //ioc
			registry.registerBeanDefinition(BEAN, beanDefinition);
		}
	}

去调用DefaultListableBeanFactory.java里的registerBeanDefinition()方法

// Cannot modify startup-time collection elements anymore (for stable iteration)
//无法再修改启动时集合元素(用于稳定的迭代)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
    。。。。。
}

将已经创建好的Bean对象注入beanDefinitionMap中

在这里插入图片描述

@ComponentScan注解

是暂时将这些符合类型的组件先排除。

@ComponentScan(excludeFilters = {
      @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

basePackages、value:指定扫描路径,如果为空则以@ComponentScan注解的类所在的包为基本的扫描路径 basePackageClasses:指定具体扫描的类 includeFilters:指定满足Filter条件的类 excludeFilters:指定排除Filter条件的类

注意:@ComponentScan是可以指定包的扫描, 但是在@SpringBootApplication这个注解里的@ComponentScan是用来排除主键的。

@Conditional注解原理

引入相关的jar的文件的时候,springboot便会让对应的类实例化

@Conditional注解

条件装配:满足Conditional指定的条件,则进行组件注入

在这里插入图片描述

@ConditionalOnBean()

当其内配置的Bean已经在容器里的时候其修饰的类才会被加载。如何和@Bean合用只有IOC容器里有指定的类的时候@Bean修饰的方法所创建的实例才会被注入IOC容器。

@ConditionalOnMissingBean()

仅当指定的Bean类和/或名称尚未包含在BeanFactory中时,此条件才匹配。如何和@Bean合用只有ioc容器里没有指定的类的时候@Bean修饰的方法所创建的实例才会被注入IOC容器。

@ConditionalOnMissingClass()

仅当指定的类不在类路径上时才匹配的条件。

@ConditionalOnWebApplication()

仅当应用程序上下文是Web应用程序上下文时才匹配的条件。

到此这篇关于SpringBoot中的自动配置原理详解的文章就介绍到这了,更多相关SpringBoot自动配置原理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MyBatis的9种动态标签详解

    MyBatis的9种动态标签详解

    大家好,本篇文章主要讲的是MyBatis的9种动态标签详解,感兴趣的同学赶快来看一看吧,感兴趣的同学赶快来看一看吧
    2021-12-12
  • Java 8 Stream 的终极技巧——Collectors 功能与操作方法详解

    Java 8 Stream 的终极技巧——Collectors 功能与操作方法详解

    这篇文章主要介绍了Java 8 Stream Collectors 功能与操作方法,结合实例形式详细分析了Java 8 Stream Collectors 功能、操作方法及相关注意事项,需要的朋友可以参考下
    2020-05-05
  • netty服务端辅助类ServerBootstrap创建逻辑分析

    netty服务端辅助类ServerBootstrap创建逻辑分析

    这篇文章主要介绍了netty服务端辅助类ServerBootstrap创建逻辑分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-03-03
  • 关于Java for循环的正确用法介绍

    关于Java for循环的正确用法介绍

    Java里的循环结构我们可以通过while、do-while、for、foreach等方式实现循环,这篇文章会把这几种循环方式都给大家讲解到,但本文主要介绍for循环的使用,感兴趣的同学可以参考阅读
    2023-05-05
  • SpringBoot中定制异常页面的实现方法

    SpringBoot中定制异常页面的实现方法

    这篇文章主要介绍了SpringBoot中定制异常页面的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • Springboot使用jsp具体案例解析

    Springboot使用jsp具体案例解析

    这篇文章主要介绍了Springboot使用jsp具体案例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • BootStrap Jstree 树形菜单的增删改查的实现源码

    BootStrap Jstree 树形菜单的增删改查的实现源码

    这篇文章主要介绍了BootStrap Jstree 树形菜单的增删改查的实现源码,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-02-02
  • springboot集成nacos无法动态获取nacos配置的问题

    springboot集成nacos无法动态获取nacos配置的问题

    这篇文章主要介绍了springboot集成nacos无法动态获取nacos配置的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • Eclipse智能提示及快捷键

    Eclipse智能提示及快捷键

    本文主要介绍了Eclipse智能提示及快捷键的相关知识,具有很好的参考价值。下面跟着小编一起来看下吧
    2017-03-03
  • Java IO网络模型实现解析

    Java IO网络模型实现解析

    这篇文章主要为大家介绍了Java IO网络模型实现解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03

最新评论