SpringBoot自动装配原理详解

作者:xidianhuihui 时间:2023-07-03 05:49:08 

summary

detail

传统的Spring项目会有很多的配置文件,比如我们要使用Redis,一般除了对应的依赖的jar包我们还需要在application.xml里面配置JedisConnectionFactory、JedisPoolConfig、RedisTemplate。但是如果使用SpringBoot的话,系统会根据pom.xml里面的jar包,自动生成这些类并且注入到IOC容器当中。

传统Spring项目中需要配置

<bean id="jedisConnectionFactory" class="...JedisConnectionFactory"></bean>
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"></bean>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"></bean>

而使用SpringBoot的话,除了pom.xml引入相应的jar包外,只需要在application.properties配置对应的属性值即可

以Redis举例

  • 从spring-boot-autoconfigure.jar/META-INF/spring.factories中获取120多个默认功能配置类,其中包括redis的功能配置类RedisAutoConfiguration的全限定名,一般一个功能配置类围绕该功能,负责管理创建多个相关的功能类,比如RedisAutoConfiguration负责:

JedisConnectionFactory、RedisTemplate、StringRedisTemplate这3个功能类的创建

org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
  • RedisAutoConfiguration配置类生效的一个条件是@ConditionalOnClass :JedisConnection.class, RedisOperations.class, Jedis.class,所以会去classpath下去查找对应的class文件

@Configuration
@ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class })
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {}
  • 如果pom.xml有对应的jar包,就能匹配到对应依赖class:JedisConnection.class, RedisOperations.class, Jedis.class

<dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-data-redis</artifactId>
       </dependency>
  • 匹配成功,这个功能配置类才会生效,同时会注入默认的属性配置类@EnableConfigurationProperties(RedisProperties.class)

@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
   private int database = 0;
   private String url;
   private String host = "localhost";
   private String password;
   private int port = 6379;
  • Redis功能配置里面会根据条件生成最终的JedisConnectionFactory、RedisTemplate,条件就是IOC环境里面,没有用户自定义的

@ConditionalOnMissingBean(RedisConnectionFactory.class)、RedisTemplate

@Configuration
@ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class })
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {
       @Bean
       @ConditionalOnMissingBean(RedisConnectionFactory.class)
       public JedisConnectionFactory redisConnectionFactory()
               throws UnknownHostException {
           return applyProperties(createJedisConnectionFactory());
       }

@Bean
       @ConditionalOnMissingBean(name = "redisTemplate")
       public RedisTemplate<Object, Object> redisTemplate(
               RedisConnectionFactory redisConnectionFactory)
                       throws UnknownHostException {
           RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
           template.setConnectionFactory(redisConnectionFactory);
           return template;
       }
}
  • 最终创建好的默认装配类,会通过功能配置类里面的 @Bean注解,注入到IOC当中

原理和结果分析

通过各种注解,SpringApplication.run(Application.class, args)在运行时,会读取spring-boot-autoconfigure.jar里面的spring.factories配置文件,配置文件中有所有自动装配类的配置类的className,然后生成对应功能的Configuration类,这些功能配置类要生效的话,会去classpath中找是否有该类的依赖类(也就是pom.xml必须有对应功能的jar包才行),然后配置类里再通过判断生成最后的功能类,并且配置类里面注入了默认属性值类,功能类可以引用并赋默认值。生成功能类的原则是自定义优先,没有自定义时才会使用自动装配类。

综上所述,要想自动装配一个类需要满足2个条件:

  • spring.factories里面有这个类的配置类(一个配置类可以创建多个围绕该功能的依赖类)

  • pom.xml里面需要有对应的jar包

整个过程的结果是两件事情:

  • 根据各种判断和依赖,最终生成了业务需要的类并且注入到IOC容器当中了

  • 自动装配生成的类赋予了一些默认的属性值

依赖的注解

  • @SpringBootApplication:sb项目应用启动类的注解,其实是3个注解的组合:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan,其中在自动装配中起作用的是第二个

  • @EnableAutoConfiguration:表示SB应用启动自动装配的功能(包括加载对应的Bean到IOC容器中,且根据默认配置对属性赋值)

  • @Import(EnableAutoConfigurationImportSelector.class):这个注解比较厉害,可以把没有注册到IOC中的Bean强行注册到IOC中,表示启动自动配置功能需要引入EnableAutoConfigurationImportSelector.class才行

  • @Configuration

  • @ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class }):表示让RedisAutoConfiguration配置类起作用的话,必须有包含这些类的jar包才行

  • @EnableConfigurationProperties(RedisProperties.class):表示默认引用RedisProperties.class里面的配置

  • @ConditionalOnMissingBean(RedisConnectionFactory.class):这是个很厉害的注解,实现自动装配时自定义优先。表示如果用户没有自定义注入RedisConnectionFactory.class类,才会使用默认的JedisConnectionFactory。

自动装配的过程

  • 通过各种注解实现了类与类之间的依赖关系,容器在启动的时候Application.run,会调用EnableAutoConfigurationImportSelector.class的selectImports方法(其实是其父类的方法)

  • selectImports方法最终会调用SpringFactoriesLoader.loadFactoryNames方法来获取一个全面的常用BeanConfiguration列表

  • loadFactoryNames方法会读取FACTORIES_RESOURCE_LOCATION(也就是spring-boot-autoconfigure.jar 下面的spring.factories),获取到所有的Spring相关的Bean的全限定名ClassName,大概120多个

  • selectImports方法继续调用filter(configurations, autoConfigurationMetadata);这个时候会根据这些BeanConfiguration里面的条件,来一一筛选,最关键的是@ConditionalOnClass,这个条件注解会去classpath下查找,jar包里面是否有这个条件依赖类,所以必须有了相应的jar包,才有这些依赖类,才会生成IOC环境需要的一些默认配置Bean

  • 最后把符合条件的BeanConfiguration注入默认的EnableConfigurationPropertie类里面的属性值,并且注入到IOC环境当中

来源:https://blog.csdn.net/xidianhuihui/article/details/117469974

标签:Java,SpringBoot,自动装配
0
投稿

猜你喜欢

  • 用C#将图片保存至Oracle BLOB字段中的方法

    2023-06-12 01:29:16
  • Java 反射(Reflect)详解

    2022-09-27 08:34:44
  • Zookeeper连接超时问题与拒绝连接的解决方案

    2023-11-20 03:41:29
  • 在.net应用程序中运行其它EXE文件的方法

    2023-11-08 08:34:43
  • c# 单例模式的实现

    2023-06-12 01:16:44
  • Java值传递之swap()方法不能交换的解决

    2023-11-12 20:54:50
  • SpringBoot使用Jackson配置全局时间日期格式

    2021-10-04 12:45:06
  • MybatisPlus代码生成器含XML文件详解

    2023-10-25 21:51:26
  • JAVA 字符串加密、密码加密实现方法

    2023-11-28 04:08:09
  • Spring实现默认标签解析流程

    2021-07-29 10:07:55
  • 如何在C#中集成Lua脚本

    2021-12-24 23:24:35
  • Maven项目修改JDK版本全过程

    2021-07-19 12:13:29
  • java线程池ThreadPoolExecutor的八种拒绝策略示例详解

    2021-06-24 11:31:10
  • MyBatis中${} 和 #{} 有什么区别小结

    2021-09-21 14:42:35
  • java弹幕小游戏1.0版本

    2021-12-06 04:42:48
  • Android实现视频播放--腾讯浏览服务(TBS)功能

    2021-09-06 20:13:10
  • 如何使用Jenkins编译并打包SpringCloud微服务目录

    2021-09-25 07:07:01
  • Java ArrayList.toArray(T[]) 方法的参数类型是 T 而不是 E的原因分析

    2023-01-07 04:22:29
  • springboot中项目启动时实现初始化方法加载参数

    2023-08-31 06:00:40
  • C#实现常见加密算法的示例代码

    2023-05-08 12:44:43
  • asp之家 软件编程 m.aspxhome.com