zoukankan      html  css  js  c++  java
  • SpringBoot自动配置原理

    自动配置原理

    使用SpringBoot之后,一个整合了SpringMVC的WEB工程开发,变的无比简单,那些繁杂的配置都消失不见了,这是如何做到的?

    一切魔力的开始,都是从我们的main函数来的,所以我们再次来看下启动类:

    我们发现特别的地方有两个:

    • 注解:@SpringBootApplication
    • run方法:SpringApplication.run()

    我们分别来研究这两个部分。

    了解@SpringBootApplication

    点击进入,查看源码:

    这里重点的注解有3个:

    • @SpringBootConfiguration
    • @EnableAutoConfiguration
    • @ComponentScan

    @SpringBootConfiguration

    我们继续点击查看源码:

    通过这段我们可以看出,在这个注解上面,又有一个@Configuration注解。通过上面的注释阅读我们知道:这个注解的作用就是声明当前类是一个配置类,然后Spring会自动扫描到添加了@Configuration的类,并且读取其中的配置信息。而@SpringBootConfiguration是来声明当前类是SpringBoot应用的配置类,项目中只能有一个。所以一般我们无需自己添加。

    @EnableAutoConfiguration

    关于这个注解,官网上有一段说明:

    The second class-level annotation is @EnableAutoConfiguration. This annotation
    tells Spring Boot to “guess” how you want to configure Spring, based on the jar
    dependencies that you have added. Since spring-boot-starter-web added Tomcat
    and Spring MVC, the auto-configuration assumes that you are developing a web
    application and sets up Spring accordingly.

    简单翻译以下:

    第二级的注解@EnableAutoConfiguration,告诉SpringBoot基于你所添加的依赖,去“猜测”你想要如何配置Spring。比如我们引入了spring-boot-starter-web,而这个启动器中帮我们添加了tomcatSpringMVC的依赖。此时自动配置就知道你是要开发一个web应用,所以就帮你完成了web及SpringMVC的默认配置了!

    总结,SpringBoot内部对大量的第三方库或Spring内部库进行了默认配置,这些配置是否生效,取决于我们是否引入了对应库所需的依赖,如果有那么默认配置就会生效。

    所以,我们使用SpringBoot构建一个项目,只需要引入所需框架的依赖,配置就可以交给SpringBoot处理了。除非你不希望使用SpringBoot的默认配置,它也提供了自定义配置的入口。

    @ComponentScan

    我们跟进源码:

    并没有看到什么特殊的地方。我们查看注释:

    大概的意思:

    配置组件扫描的指令。提供了类似与<context:component-scan>标签的作用

    通过basePackageClasses或者basePackages属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包

    而我们的@SpringBootApplication注解声明的类就是main函数所在的启动类,因此扫描的包是该类所在包及其子包。因此,一般启动类会放在一个比较前的包目录中。

    默认配置原理

    spring.factories

    在SpringApplication类构建的时候,有这样一段初始化代码:

    //默认配置
    1.SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) 
    2.getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args)
    3.loadFactoryNames
    4.FACTORIES_RESOURCE_LOCATION
    
    //静态资源访问
    1.WebMvcAutoConfiguration
    2.ResourceProperties
    
    //读取配置文件
    1.ConfigFileApplicationListener
    2.loadForFileExtension(loader, location + name
    3.断点查看processed,会看到xml,yml,properties,yaml
    

    跟进去:

    这里发现会通过loadFactoryNames尝试加载一些FactoryName,然后利用createSpringFactoriesInstances将这些加载到的类名进行实例化。

    继续跟进loadFactoryNames方法:

    发现此处会利用类加载器加载某个文件:FACTORIES_RESOURCE_LOCATION,然后解析其内容。我们找到这个变量的声明:

    可以发现,其地址是:META-INF/spring.factories,我们知道,ClassLoader默认是从classpath下读取文件,因此,SpringBoot会在初始化的时候,加载所有classpath:META-INF/spring.factories文件,包括jar包当中的。

    而在Spring的一个依赖包:spring-boot-autoconfigure中,就有这样的文件:

    以后我们引入的任何第三方启动器,只要实现自动配置,也都会有类似文件。

    默认配置类

    我们打开刚才的spring.factories文件:

    可以发现以EnableAutoConfiguration接口为key的一系列配置,key所对应的值,就是所有的自动配置类,可以在当前的jar包中找到这些自动配置类:

    还有:

    非常多,几乎涵盖了现在主流的开源框架,例如:

    • redis
    • jms
    • amqp
    • jdbc
    • jackson
    • mongodb
    • jpa
    • solr
    • elasticsearch

    ... 等等

    我们来看一个我们熟悉的,例如SpringMVC,查看mvc 的自动配置类:

    打开WebMvcAutoConfiguration:

    我们看到这个类上的4个注解:

    • @Configuration:声明这个类是一个配置类

    • @ConditionalOnWebApplication(type = Type.SERVLET)

      ConditionalOn,翻译就是在某个条件下,此处就是满足项目的类是是Type.SERVLET类型,也就是一个普通web工程,显然我们就是

    • @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })

      这里的条件是OnClass,也就是满足以下类存在:Servlet、DispatcherServlet、WebMvcConfigurer,其中Servlet只要引入了tomcat依赖自然会有,后两个需要引入SpringMVC才会有。这里就是判断你是否引入了相关依赖,引入依赖后该条件成立,当前类的配置才会生效

    • @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)

      这个条件与上面不同,OnMissingBean,是说环境中没有指定的Bean这个才生效。其实这就是自定义配置的入口,也就是说,如果我们自己配置了一个WebMVCConfigurationSupport的类,那么这个默认配置就会失效!

    接着,我们查看该类中定义了什么:

    视图解析器:

    处理器适配器(HandlerAdapter):

    还有很多,这里就不一一截图了。

    默认配置属性

    另外,这些默认配置的属性来自哪里呢?

    我们看到,这里通过@EnableAutoConfiguration注解引入了两个属性:WebMvcProperties和ResourceProperties。这不正是SpringBoot的属性注入玩法嘛。

    我们查看这两个属性类:

    找到了内部资源视图解析器的prefix和suffix属性。

    ResourceProperties中主要定义了静态资源(.js,.html,.css等)的路径:

    如果我们要覆盖这些默认属性,只需要在application.properties中定义与其前缀prefix和字段名一致的属性即可。

    总结

    SpringBoot为我们提供了默认配置,而默认配置生效的步骤:

    • @EnableAutoConfiguration注解会去寻找META-INF/spring.factories文件,读取其中以EnableAutoConfiguration为key的所有类的名称,这些类就是提前写好的自动配置类

    • 这些类都声明了@Configuration注解,并且通过@Bean注解提前配置了我们所需要的一切实例。完成自动配置

    • 但是,这些配置不一定生效,因为有@ConditionalOn注解,满足一定条件才会生效。比如条件之一:是一些相关的类要存在

    • 类要存在,我们只需要引入了相关依赖(启动器),依赖有了条件成立,自动配置生效。

    • 如果我们自己配置了相关Bean,那么会覆盖默认的自动配置的Bean

    • 我们还可以通过配置application.yml文件,来覆盖自动配置中的属性

    1)启动器

    所以,我们如果不想配置,只需要引入依赖即可,而依赖版本我们也不用操心,因为只要引入了SpringBoot提供的stater(启动器),就会自动管理依赖及版本了。

    因此,玩SpringBoot的第一件事情,就是找启动器,SpringBoot提供了大量的默认启动器

    2)全局配置

    另外,SpringBoot的默认配置,都会读取默认属性,而这些属性可以通过自定义application.properties文件来进行覆盖。这样虽然使用的还是默认配置,但是配置中的值改成了我们自定义的。

    因此,玩SpringBoot的第二件事情,就是通过application.properties来覆盖默认属性值,形成自定义配置。我们需要知道SpringBoot的默认属性key,非常多,可以再idea中自动提示

  • 相关阅读:
    PAT 甲级 1115 Counting Nodes in a BST (30 分)
    PAT 甲级 1114 Family Property (25 分)
    PAT 甲级 1114 Family Property (25 分)
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
  • 原文地址:https://www.cnblogs.com/guoyx/p/12936998.html
Copyright © 2011-2022 走看看