Springboot的自动装配原理

本文将从三个问题出发,详解springboot的自动装配原理

1.Springboot的自动装配是什么?

SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot 在启动时会扫描外部引用 jar 包中的META-INF/spring.factories文件,将文件中配置的类型信息加载到 Spring 容器,并执行类中定义的各种操作。自动装配帮助我们简化了外部jar包使用的配置操作,在spring中,如果我们引入一个第三方依赖,需要手动对其进行配置,如Redis,则需要在Spring中为其编写一个特定的bean,但是在springboot中,我们只需简单的引入Redis对应的的starter依赖即可。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.Springboot自动装配的实现原理?

我们在idea中新建一个springboot项目,点击主启动类的 @SpringBootApplication。
在这里插入图片描述
点击之后发现,@SpringBootApplication注解主要由以下几个注解组成,
在这里插入图片描述
我们只需重点关注其中的三个注解:

  1. SpringBootConfiguration 的内部是 Configuration: 允许在上下文中注册bean或引入其他的配置;
  2. ComponentScan: 扫描被@Component注解的 bean,注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描的bean,如图中的TypeExcludeFilter.class 和 AutoConfigurationExcludeFilter.class;
  3. EnableAutoConfiguration: 自动装配实现的核心注解。

我们继续查看 EnableAutoConfiguration 其中到底是如何实现的,点击进去查看源码。
在这里插入图片描述
可以看到,红框标出的部分,通过@Import注解引入了 AutoConfigurationImportSelector.class,这个类就是自动装配的关键。
在这里插入图片描述
在这里插入图片描述
通过这两张图,可以看出AutoConfigurationImportSelector 实现了 ImprotSelector接口,并实现该接口中的 selectImports 方法。该方法的功能是: 获取所有符合条件的类的全限定类名,将这些类加载到IOC容器中去。
在这里插入图片描述
在selectImports方法中,可以看到另一个关键方法: getAutoConfigurationEntry ,该方法的源码如下,执行过程请看注释:

    protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        // 判断自动装配开关是否打开
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            // 获取 exclude 和 excludeName
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            // 读取META-INF/spring.factories,获取需要自动装配的所有配置类
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            // 获取@ConditionalOnXXX 中的所有条件
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

spring.factories中这么多配置,每次启动并不是全部加载。需要一遍筛选,@ConditionalOnXXX 中的所有条件都满足,该类才会生效。
Spring Boot 提供的条件注解如下

  1. @ConditionalOnBean:当容器里有指定 Bean 的条件下
  2. @ConditionalOnMissingBean:当容器里没有指定 Bean 的情况下
  3. @ConditionalOnSingleCandidate:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean
  4. @ConditionalOnClass:当类路径下有指定类的条件下
  5. @ConditionalOnMissingClass:当类路径下没有指定类的条件下
  6. @ConditionalOnProperty:指定的属性是否有指定的值
  7. @ConditionalOnResource:类路径是否有指定的值

到此,原理部分就结束了,那么如何自定义一个starter呢?

3.自定义一个starter

首先,我们创建一个Maven项目,在pom文件中引入依赖:

 <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <version>2.1.7.RELEASE</version>
  </dependency>

在resources目录下创建一个spring.factories文件
在这里插入图片描述

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.ThreadPoolConfiguration  

编写模块类:

@Configuration
public class ThreadPoolConfiguration {
    @Bean
    @ConditionalOnClass(ThreadPoolExecutor.class)
    public ThreadPoolExecutor getExecutor() {
        return new ThreadPoolExecutor(10,10,10, TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(100));
    }
}

到此,基本模块已经构建,安装maven到本地:
在这里插入图片描述
新创建一个springboot项目,引入我们刚才编写好的依赖:

   <dependency>
       <groupId>org.example</groupId>
       <artifactId>threadpool-spring-boot-starter</artifactId>
       <version>1.0-SNAPSHOT</version>
   </dependency>

在测试类中,测试是否引入生效。

@SpringBootTest
class TestspringApplicationTests {
    
    @Autowired
    ThreadPoolConfiguration threadPoolExecutorTest;
    
    @Test
    void contextLoads() {
        System.out.println("threadPoolExecutorTest.getExecutor().getCorePoolSize() = " + threadPoolExecutorTest.getExecutor().getCorePoolSize());
    }
}

在这里插入图片描述
正常输出! 至此Springboot的自动装配原理讲述完毕,觉得还可以的麻烦动动小手点点赞。

本文参考链接:https://github.com/Snailclimb/JavaGuide

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值