SpringBoot:认认真真梳理一遍自动装配原理(下)

看到这里,可能有些同学会存在疑问,spring.factories中存在那么多的配置,每次启动时都是把它们全量加载吗?这显然是不现实的。


这其实也是我在看源码的时候存在疑问的地方,因为其中有一个注解并不常用,我们点开一个配置类就可以看到。



@ConditionalOnXXX:如果其中的条件都满足,该类才会生效。


所以在加载自动配置类的时候,并不是将spring.factories的配置全量加载进来,而是通过这个注解的判断,如果注解中的类都存在,才会进行加载。


所以就实现了:我们在pom.xml文件中加入stater启动器,SpringBoot自动进行配置。完成开箱即用。


结论


SpringBoot所有自动配置类都是在启动的时候进行扫描并加载,通过spring.factories可以找到自动配置类的路径,但是不是所有存在于spring,factories中的配置都进行加载,而是通过@ConditionalOnClass注解进行判断条件是否成立(只要导入相应的stater,条件就能成立),如果条件成立则加载配置类,否则不加载该配置类。


在这里贴一个我认为的比较容易理解的过程:


  • SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值
  • 将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;
  • 以前我们需要自己配置的东西 , 自动配置类都帮我们解决了
  • 整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;
  • 它将所有需要导入的组件以全类名的方式返回 , 这些组件就会被添加到容器中 ;
  • 它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件 ;
  • 有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;


摘自https://blog.kuangstudy.com/index.php/archives/630/


SpringBoot:认认真真梳理一遍自动装配原理(下)


约定大于配置


开箱即用的原理说完了,约定大于配置就比较好理解了。其实约定大于配置就是开箱即用中那些自动配置的细节。说的具体点就是:我们的配置文件(.yml)应该放在哪个目录下,配置文件的命名规范,项目启动时扫描的Bean,组件的默认配置是什么样的(比如SpringMVC的视图解析器)等等等等这一系列的东西,都可以被称为约定,下面就来一点一点地说一下SpringBoot中的“约定”。


maven目录结构的约定


我们可以去Spring的官网查看一下官方文档,看看文档中描述的目录结构是怎样的。


Config locations are searched in reverse order. By default, the configured locations are classpath:/,classpath:/config/,file:./,file:./config/. The resulting search order is the following:


  • file:./config/
  • file:./
  • classpath:/config/
  • classpath:/


也就是说,spring的配置文件目录可以放在


  • /config
  • /(根目录)
  • resource/config/
  • resource/


这四个路径从上到下存在优先级关系。


SpringBoot默认配置文件的约定


SpringBoot默认可以加载以下三种配置文件:


  • application.yml
  • application.yaml
  • application.properties


建议使用前两种作为项目的配置文件。


项目启动时扫描包范围的约定


SpringBoot的注解扫描的默认规则是SpringBoot的入口类所在包及其子包。


若入口类所在的包是cn.objectspace.demo那么自动扫描包的范围是cn.objectspace.demo包及其下面的子包,如果service包和dao包不在此范围,则不会自动扫描。


SpringBoot自动配置类如何读取yml配置


从更细节的角度去理解自动配置


上文中我们阐述了一些SpringBoot自动配置的原理,我们是从全局的角度去看自动配置的整个过程。比如从哪个地方开始进行装配流程、如何找到装配的包等。


那么现在将自己的视角贴近SpringBoot,来聊聊application.yml中我们配置的东西,是如何配置到一个个的配置类中的。


yml配置文件中可以配置那些东西


首先要知道这个问题的答案,我们应该习惯springboot的配置方式。在上文中我们阐述了SpringBoot总是将所有的配置都用JavaConfig的形式去呈现出来,这样能够使代码更加优雅。


那么yml中配置的东西,必然是要和这种配置模式去进行联系的,我们在application.yml中配置的东西,通常是一些存在与自动配置类中的属性,那么这些自动配置类,在启动的时候是怎么找到的呢?


如果你还记得上文的描述,那么你可以很明确地知道:spring.factories!没错,就是它,所以这个问题我们似乎得到了答案——只要存在与spring.factories中的,我们都可以在application.yml中进行配置。


当然,这并不意味着不存在其中的我们就不能配置,这些配置类我们是可以进行自定义的,只要我们写了配置类,我们就可以在yml中配置我们需要的属性值,然后在配置类中直接读取这个配置文件,将其映射到配置类的属性上。那么就牵扯出我们的问题了:配置类是如何去读取yml配置文件中的信息的呢?


@ConfigurationProperties


要明白这个问题。我们就首先要去了解这个注解有什么作用。


我们可以自己尝试在application.yml中去定义一些属性,如下:


object: 
  name: Object
  blogurl: blog.objectspace.cn


我们现在自己定义一个类去读取这个文件:


@Component
@ConfigurationProperties(prefix = "object")
public class TestConfig {
    private String name;
    private String blogUrl;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getBlogUrl() {
        return blogUrl;
    }
    public void setBlogUrl(String blogUrl) {
        this.blogUrl = blogUrl;
    }
}


然后我们在测试类中输出一下这个对象:


@SpringBootTest
class SpringbootdemoApplicationTests {
    @Autowired
    TestConfig testConfig;
    @Test
    void contextLoads() {
        System.out.println(testConfig.getName());
        System.out.println(testConfig.getBlogUrl());
    }
}


测试结果:


SpringBoot:认认真真梳理一遍自动装配原理(下)


我们可以看到,在控制台中输出了我们在yml中配置的属性值,但是这些值我们没有在任何地方显式地对这个对象进行注入。


所以@ConfigurationProperties这个注解,可以将yml文件中写好的值注入到我们类的属性中。


明白了它的作用,就能明白自动配置类工作的原理了。


我们依旧是选取SpringMVC的自动配置类,我们来看看其中有些什么东西。


SpringBoot:认认真真梳理一遍自动装配原理(下)


点击任意一个*Properties类中,look一下其中的内容


SpringBoot:认认真真梳理一遍自动装配原理(下)


我们在yml中配置的date-format,就可以通过@ConfigurationProperties映射到类中的dateFormat中,然后在通过自动配置类,将这些属性配置到配置类中。



最后,欢迎访问博客:


http://blog.objectspace.cn/


END

上一篇:Excel 数据导入SQL XML 自动生成表头


下一篇:WebAssembly 对比 JavaScript 及其使用场景