springboot 自动装配

﹏ヽ暗。殇╰゛Y 2021-09-25 13:40 532阅读 0赞

一、回顾在普通的Spring项目中的做法

在没有使用Spring Boot之前,我们需要在xml文件中进行需要用到的Bean的配置(以最常用的mybatis的使用为例)。

在使用到mybatis时,除了引入依赖外,我们需要配置相关的Bean(DataSource的bean、SqlSessionFactory的bean)

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTc2NDc2NQ_size_16_color_FFFFFF_t_70

而在用到Spring Boot后,我们只需要引入依赖,再加上少量的配置就可以完成自动装配。

20201127235206204.png

在properties文件中配置:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTc2NDc2NQ_size_16_color_FFFFFF_t_70 1

这得益于Spring Boot的自动装配。

二、Spring Boot的自动装配原理

1、从程序的入口,main方法开始

在启动类的main方法中我们可以看到,使用调用了类SpringApplication中的一个run()方法,这个run()方法的主要作用是去加载启动类(例如,类HelloBoot)。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTc2NDc2NQ_size_16_color_FFFFFF_t_70 2

下面就来看看这个run()方法是如何去加载启动类的:

(1)在类SpringApplication中的第一个run()方法,把参数传了进去。

20201128113843445.png

实际上,它是调用了下面这个run()方法。

(2)而下面这个run()方法,创建了一个SpringApplication对象,然后又调用了另外一个run方法。

20201128113917813.png

(3)而这第三个run()方法refreshContext(ConfigurableApplicationContext context)拿到配置类,然后去解析配置类,主要是解析配置类上的注解@SpringBootApplication

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTc2NDc2NQ_size_16_color_FFFFFF_t_70 3

(也就是这个启动类 )

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTc2NDc2NQ_size_16_color_FFFFFF_t_70 4

那么,这个注解 @SpringBootApplication有什么呢?


2、注解@SpringBootApplication

包含了很多个注解,其中有@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTc2NDc2NQ_size_16_color_FFFFFF_t_70 5

(1)注解@SpringBootConfiguration

本质上,它是一个配置类

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTc2NDc2NQ_size_16_color_FFFFFF_t_70 6

(2)注解@ComponentScan

它的作用是扫描当前包及其子包(这也是为什么有时我们把启动类放错位置,而导致无法扫描到某些包的原因)

2020112800235764.png


(3)注解@EnableAutoConfiguration

它是自动装配的注解

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTc2NDc2NQ_size_16_color_FFFFFF_t_70 7

@EnableAutoConfiguration上面加载了一个类,AutoConfigurationImportSelector类,该类会调方法getCandidateConfigurations()拿到配置

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTc2NDc2NQ_size_16_color_FFFFFF_t_70 8

进入loadFactoryNames()方法,获取资源,并且完成资源文件spring-factories的读取

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTc2NDc2NQ_size_16_color_FFFFFF_t_70 9

也就是说通过类加载classLoader,去加载META-INF下的spring-factories文件

20201128004125629.png

并且加载系统中“META-INF/spring-factories”

20201128004204937.png

那么, FACTORIES_RESOURCE_LOCATION 中主要有什么呢?


以上面的 DataSource 为例

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTc2NDc2NQ_size_16_color_FFFFFF_t_70 10

20201128005700760.png

可以看到,在spring-factories中配置了自动装配类

20201128005724342.png

这个自动装配类会被读取到内存中

20201202220159203.png

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTc2NDc2NQ_size_16_color_FFFFFF_t_70 11

这个类本质上就是配置类,贴了注解@bean,也就是说这里会创建Datasource。

这个方法,返回的是一个DruidDataSoureWrapper

20201202221818207.png

注解@ConfigurationProperties,作用是把配置文件中,前缀是Spring.datasource.druid的,注入到该对象。最后,框架拿到数据库的连接信息(账号密码等四要素),才能帮我们创建出Datasource。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTc2NDc2NQ_size_16_color_FFFFFF_t_70 12

特别地,贴了注解@ConditionalOnMissingBean(条件注解),代表着当前上下文中不存在该对象时,才会实例化一个Bean

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTc2NDc2NQ_size_16_color_FFFFFF_t_70 13

@ConditionalOnBean(仅仅在当前上下文中存在某个对象时,才会实例化一个Bean)

@ConditionalOnClass(某个class位于类路径上,才会实例化一个Bean)

@ConditionalOnExpression(当表达式为true的时候,才会实例化一个Bean)

@ConditionalOnMissingBean(仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean)

@ConditionalOnMissingClass(某个class类路径上不存在的时候,才会实例化一个Bean) @ConditionalOnNotWebApplication(不是web应用)


三、小结:自动装配的流程(原理)

1、main方法中SpringApplication.run(HelloBoot.class,args)的执行流程中有refreshContext(context)。

2、而这个refreshContext(context)内部会解析,配置类上自动装配功能的注解@EnableAutoConfiguration中的,@EnableAutoConfiguration中的,引入类AutoConfigurationImportSelector。

3、AutoConfigurationImportSelector这个类中的方法SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()会读取jar包中的/项目中的META-INF/spring.factories文件。

4、spring.factories配置了自动装配的类,最后根据配置类的条件,自动装配Bean。

发表评论

表情:
评论列表 (有 0 条评论,532人围观)

还没有评论,来说两句吧...

相关阅读