• 什么是SpringBoot自动配置


    概述:

    现在的Java面试基本都会问到你知道什么是Springboot的自动配置。为什么面试官要问这样的问题,主要是在于看你有没有对Springboot的原理有没有深入的了解,有没有看过Springboot的源码,这是区别普通程序员与高级程序员最好的试金石。本篇就让我把什么是Springboot自动装配讲的明明白白。

    一、什么是SpringBoot自动配置

    从字面上了解,自动配置的意思是不需要我们手工写代码,所有的配置由Springboot自动完成。怎么实现的呢?

    Springboot是通过@EnableAutoConfiguration注解开启自动配置的,对spring-boot-autoconfigure.jar包下的spring.factories这个文件进行扫描,这个文件包含了可以自动装配的类,当满足@Condition注解指定的条件时,便在依赖的支持下进行实例化,注册到Spring容器中。

    在以前的Spring MVC项目中,所有的配置都在xml文件中进行,代码容易造成混乱,不易维护,浪费了开发人员大量的时间和精力,Spring Boot的最大的特点就是简化了各种xml配置内容,将配置全部放在application.yml中进行集中配置,代码采用阶梯的模式,简易明了,要使用的对象则采取注解的模式注入,省去大量的代码。

    Springboot核心配置原理:

    • 自动配置类都存放在spring-boot-autoconfigure-版本号.jar下的org.springframework.boot.autoconfigure中
    • 当我们在application.properties中配置debug=true后启动容器。可以看到服务器初始化的初始化配置
    • EmbeddedWebServerFactoryCustomizerAutoConfiguration注册容器类型
    • HttpMessageConvertersAutoConfiguration注册json或者xml处理器
    • JacksonAutoConfiguration注册json对象解析器
    • 如果加入其他功能的依赖,springBoot还会实现这些功能的自动配置

    二、装载流程

    在这里插入图片描述

    三、什么是Starter组件

    Starter组件是可被加载在应用中的Maven依赖项。只有在Maven配置中添加对应的依赖配置,即可使用对应的Starter组件。例如,添加spring-boot-starter-web依赖,就可以用于构建REST API服务,其包含了SpringMVC和Tomcat内嵌容器。

    一个完整的Starter组件包括以下两点:

    提供自动配置功能的自动配置模块
    提供依赖关系管理岗功能的组件模块,即封装了组件所有功能,开箱即用。

    spring-boot-starter-web依赖源码

    package org.springframework.boot.autoconfigure.web.servlet;
     
    @Configuration
    @ConditionalOnClass({ServletRequest.class})
    @ConditionalOnWebApplication(
        type = Type.SERVLET
    )
    @EnableConfigurationProperties({ServerProperties.class})
    @Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class})
    public class ServletWebServerFactoryAutoConfiguration {
        ......
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    四、@SpringBootApplication注解里的三大注解

    • @SpringBootConfiguration:继承自Configuration,支持JavaConfig的方式进行配置。
    • @EnableAutoConfiguration:主要用于开启自动配置。
    • @ComponentScan:自动扫描组件,默认扫描该类所在包及其子包下所有带有指定注解的类,将它们自动装配到bean容器中,会被自动装配的注解包括@Controller、@Service、@Component、@Repository等。也可以指定扫描路径。

    如图:
    在这里插入图片描述

    五、@EnableAutoConfiguration注解的作用

    这个注解是帮助我们自动加载默认配置的,它里面有两个关键注解@AutoConfigurationPackage和@Import,我们来详细了解@Import注解。

    @Override
    	public String[] selectImports(AnnotationMetadata annotationMetadata) {
    		//1、检查自动配置功能是否开启,默认开启
    		if (!isEnabled(annotationMetadata)) {
    			return NO_IMPORTS;
    		}
    		//2、加载自动配置的元信息
    		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
    				.loadMetadata(this.beanClassLoader);
    		AnnotationAttributes attributes = getAttributes(annotationMetadata);
    		//3、获取候选配置类
    		List<String> configurations = getCandidateConfigurations(annotationMetadata,
    				attributes);
    		//4、去掉重复的配置类
    		configurations = removeDuplicates(configurations);
    		//5、获得注解中被exclude和excludeName排除的类的集合
    		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    		//6、检查被排除类是否可实例化、是否被自动注册配置所使用,不符合条件则抛出异常
    		checkExcludedClasses(configurations, exclusions);
    		//7、从候选配置类中去除掉被排除的类
    		configurations.removeAll(exclusions);
    		//8、过滤
    		configurations = filter(configurations, autoConfigurationMetadata);
    		//9、将配置类和排除类通过事件传入到监听器中
    		fireAutoConfigurationImportEvents(configurations, exclusions);
    		//10、最终返回符合条件的自动配置类的全限定名数组
    		return StringUtils.toStringArray(configurations);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    @Import(AutoConfigurationImportSelector.class)注解,这里导入AutoConfigurationImportSelector类。这个类中有一个非常重要的方法:

    selectImports(),它几乎涵盖了组件自动装配的所有处理逻辑,包括获得候选配置类、配置类去重、排除不需要的配置类、过滤等,最终返回符合条件的自动配置类的全限定名数组。

    六、SpringFactoriesLoader加载器

    spring-core包里定义了SpringFactoriesLoader类, SpringFactoriesLoader工厂加载机制是Spring内部提供的一个约定俗成的加载方式,只需要在模块的META-INF/spring.factories文件,这个Properties格式的文件中的key是接口、注解、或抽象类的全名,value是以逗号 “ , “ 分隔的实现类,使用SpringFactoriesLoader来实现相应的实现类注入Spirng容器中。

    在这个类中定义了两个对外的方法:

    loadFactories:根据接口类获取其实现类的实例,这个方法返回对象的列表
    loadFactoryNames 根据接口获取其接口类的名称,这个方法返回的是类名的列表。

    上面的两个方法的关键都是从指定的ClassLoader中获取spring.factories文件,并解析得到类名列表,具体代码如下:

    public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        try {
            Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            List<String> result = new ArrayList<String>();
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                String factoryClassNames = properties.getProperty(factoryClassName);
                result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
            }
            return result;
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
                    "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    由代码可知,在这个方法中会遍历整个ClassLoader中所有jar包下的spring.factories文件。也就是说我们可以在自己的jar中配置spring.factories文件,不会影响到其它地方的配置,也不会被别人的配置覆盖。
    spring.factories的是通过Properties解析得到的,所以我们在写文件中的内容都是安装下面这种方式配置的:com.xxx.interface=com.xxx.classname

    源码地址:https://gitee.com/charlinchenlin/koo-erp

  • 相关阅读:
    鸿蒙生态融合进行时!菊风启动适配HarmonyOS NEXT,赋能原生应用实时
    (ICONIP2021)On the Unreasonable Effectiveness of Centroids in Image
    Docker搭建MySQL Workbench
    Delphi11.3FMX微信支付到个人账户源代码(手机POS机安卓源代码、手机APP收款机苹果源代码、PC源代码)
    简单5分钟,将lowcode低代码融入到你的中后台管理系统
    大数据Doris(六):编译 Doris遇到的问题
    一篇聊聊Mybatis插件开发
    记一次pdjs时安装glob出现,npm ERR! code ETARGET和npm ERR! code ELIFECYCLE
    建立复数类
    day072:UDP协议发送数据、接收数据(DatagramSocket、DatagramPacket);TCP协议发送数据、接收数据(Socket、ServerSocket)
  • 原文地址:https://blog.csdn.net/lovoo/article/details/130438287