Spring 开发系列-springboot自动配置

SpringBoot能简化spring应用开发,其中最核心的就是自动配置和起步依赖,起步依赖主要是由Maven插件实现,减少了繁杂的jar包管理;而自动配置针对很多Spring应用程序常见的功能,能自动的配置相关配置,同时允许开发人员修改配置。我们只需要简单引入starter,就能很快搭建出一个应用构架,极大的提升了开发效率。下面讲一下自动配置的实现原理。

 

1spring扩展机制:springfactories

spring-core包里定义了SpringFactoriesLoader类,这个类实现了检索META-INF/spring.factories文件,并获取指定接口的配置的功能。在这个类中定义了两个对外的方法:

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

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

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

很多包中都能够找到spring.factories文件,我们也可以在自己的jar中配置spring.factories文件,不会影响到其它地方的配置,也不会被别人的配置覆盖,按照properties的格式编写来实现相应的实现类注入Spirng容器中。在springboot中使用factories机制可以让starter的使用只需要很少或者不需要进行配置,只需要在服务中引入我们的jar包即可。

 

接下来我们看看spring-boot和spring-boot-autoconfigure包中的spring.factories文件.

spring-boot

 

这个spring.factories文件主要配置的是spring本身启动需要的处理类,里面包含了许多类型的接口实现类,在spring启动的时候会读取里面的配置用作启动初始化。如PropertySourceLoader处理properties、yml配置文件的、ApplicationListener用于spring容器启动到某个阶段时触发执行的事件、ApplicationContextInitializer初始化spring容器。

spring-boot-autoconfigure

Spring 开发系列-springboot自动配置

这spring.factories文件和上面的文件包含了相同的键,它们会被spring合并,形成多个实现类,它们都是spring启动时默认加载的配置信息。这里涉及到spring是何时加载、实例话这些配置类的对象,以及它们的执行逻辑、实现的具体功能。本次主要讲解springboot自动配置相关的实现,其他的大家可以自行查看SpringApplication类的run方法是如何运用这些参数。

 

我们在应用中引用一些starter,再在spring.properties中简单配置几个参数就能使用对应的第三方插件了,是因为每个starter都包含一个factories文件并且配置了自动配置的实现类,即org.springframework.boot.autoconfigure.EnableAutoConfiguration键值对。在spring-boot-autoconfigure包中的键值包含很多实现类(上面的配置信息我删除了一些),比如常用的数据源、事务管理、springmvc、aop、内嵌web容器等。由于我们在应用主类上添加了@SpringBootApplication注解。@SpringBootApplication注解又基于spring的@Import注解功能,在@Import上配置了EnableAutoConfigurationImportSelector.class,这个类会使用SpringFactoriesLoader.loadFactoryNames()方法将自动配置的实现类全部导入,导入过程在EnableAutoConfigurationImportSelector类的selectImports()方法中。

 

2Import注解

@Import是spring中常见的注解,可以用来动态创建bean,很多地方都使用到了,因此值得我们学习,在开发中也能用类似方式来对bean实例做控制;

在@Import注解的参数中可以传入类名,根据类Test的不同类型,spring容器有以下四种处理方式:

1. 如果Test类实现了ImportSelector接口,spring容器就会实例化Test类,并且调用其selectImports方法;

2. DeferredImportSelector是ImportSelector的子类,如果Test类实现了DeferredImportSelector接口,spring容器就会实例化Test类,并且调用其selectImports方法,和ImportSelector的实例不同的是,DeferredImportSelector的实例的selectImports方法调用时机晚于ImportSelector的实例,要等到@Configuration注解中相关的业务全部都处理完了才会调用;

3. 如果Test类实现了ImportBeanDefinitionRegistrar接口,spring容器就会实例化Test类,并且调用其registerBeanDefinitions方法;

4. 如果Test是普通类,即POJO,spring容器就会实例化Test类;

 

通过查看源代码可以发现@Import注解的实现主要在ConfigurationClassPostProcessor、ConfigurationClassParser 、ConfigurationClassBeanDefinitionReader这三个类上。下图是它们的调用关系:

Spring 开发系列-springboot自动配置

ConfigurationClassPostProcessor类的processConfigBeanDefinitions方法:

Spring 开发系列-springboot自动配置 

ConfigurationClassParser类的doProcessConfigurationClass方法:

 

ConfigurationClassParser类的processImports方法:

 

由于ConfigurationClassPostProcessor类实现了BeanDefinitionRegistryPostProcessor接口,spring在启动时会调用postProcessBeanDefinitionRegistry()方法,这个方法负责处理@Configuration注解相关的逻辑;往下看这个方法里又调用了ConfigurationClassParser类的parse()方法,顺着这个方法一直下去,直到doProcessConfigurationClass()方法,这个方法里面处理了@PropertySource、@ComponentScan、@Import、@ImportResource注解,@PropertySource注解将properties配置文件中的值存储到Spring的 Environment中;@ComponentScan 注解扫描对应类包下更多的配置类,并根据需要递归;@ImportResource注解主要导入xml方式配置的文件;@Import注解实现逻辑对应了processImports()方法,processImports()方法中包含了对ImportSelector实现类、ImportBeanDefinitionRegistrar实现类、普通类和DeferredImportSelector实现类的处理。processImports方法中对ImportSelector实现类的处理,涉及到对processImports方法的递归调用。DeferredImportSelector实现类处理时机比起ImportSelector实现类晚,是在处理完所有@Configuration注解类后。

最后多种方式导入的bean都被保存在ConfigurationClassParser实例中,再回到ConfigurationClassPostProcessor类的processConfigBeanDefinitions方法,ConfigurationClassBeanDefinitionReader类的loadBeanDefinitions()方法处理了保存再ConfigurationClassParser实例中的bean定义并注册到spring容器。

 

到此springboot自动配置的主要原理就讲的差不多了。

 

另外,我们举个例子来分析一下内嵌的tomcat中间件是如何自动配置的。

首先,大家都非常熟悉java程序启动入口是从main方法开始运行,而web应用的程序运行在web容器中,我们写的servlet类或相关业务处理类,能够运行是因为我们把类放入到了web容器中,其实web容器同样是从main方法开始运行,只是这个main方法主要是启动容器并加载容器自身的配置等信息,等容器启动好了才通过java类加载机制将我们的程序代码加载到JVM中再运执行。

 

在springboot应用中默认引入的是tomcat嵌入式web容器,应用的启动方式也是从main方法开始的,这和上面说的观点是一致的。这种方式的实现是由EmbeddedServletContainerAutoConfiguration和ServerPropertiesAutoConfiguration自动配置类实现。

在EmbeddedServletContainerAutoConfiguration中配置了多种嵌入式容器,包括tomcat和jetty,又根据上面讲的Import原理可以看到源码中,最后在容器中添加了一个spring的后置处理器EmbeddedServletContainerCustomizerBeanPostProcessor,也就是说再获取内嵌容器Bean时,会根据spring.properties中的参数设置容器的参数值,如IP,端口,线程池大小等。web容器初始化的地方在AbstractApplicationContext的onRefresh方法中。

原创文章,作者:EBCloud,如若转载,请注明出处:https://www.sudun.com/ask/33192.html

(0)
EBCloud's avatarEBCloud
上一篇 2024年4月2日 下午3:28
下一篇 2024年4月2日 下午3:28

相关推荐

  • 达飞官方信息公布群,达飞app怎么打不开了

    近日,互联网行业知名网站达飞集团(CMA CGM)发生一起令人震惊的事件。该消息很快在网络上引起广泛关注,不少人好奇“达飞轮船网站为何遭到攻击?”谁干的?攻击手段有哪些?更重要的是…

    行业资讯 2024年5月16日
    0
  • 租用美国服务器多少钱

    想要拥有一个高性能的服务器,美国服务器将是你不可错过的选择。它不仅具备先进的技术特点,还拥有最优惠的价格标准。那么,你是否好奇租用美国服务器到底需要多少钱?今天我就为大家揭秘这个网…

    行业资讯 2024年4月11日
    0
  • Web3.0时代下的安全思考

    WEB 3.0 Web3.0 的时代已经到来,其去中心化的特殊性使其有着独特的安全能力,然而许多在Web2.0时期的安全问题依旧困扰着Web3.0。同时,这两种技术之间的差异也会产…

    2024年4月2日
    0
  • 如何选择适合自己的德迅云服务器?

    云服务器行业近年来发展迅速,德迅云服务器作为其中的佼佼者备受瞩目。它的高性能、稳定性以及灵活的付费方式都吸引着众多用户的关注。但是面对如此多的选择,如何选择适合自己的德迅云服务器却…

    行业资讯 2024年3月26日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注