在SpringBoot中,为什么填入pom依赖后,我们就能使用其类对象?

发布于:2023-01-04 ⋅ 阅读:(255) ⋅ 点赞:(0)

今天给大家一个腾讯的真实面试题。

面试官:“在SpringBoot中开发,为什么我们在填入pom依赖以后,就能使用其对象?”

今天这篇文章呢,我就来给大家分析这个问题。

文章导读

自动配置

引用流程

当我们在pom.xml文件中填写引入一个依赖以后,我们的包控制器(maven、gradle)会从settings.xml配置的镜像地址拉取jar到我们本地(idea中下边的刷新按钮执行拉取),这个时候我们看到的现象就是jar拉取到本地不用实例化就能直接拿来用了。

刷新引用

面试官就是问这一点,对象我们没有注入到Spring容器中,怎么就能用了?

正常的逻辑

先抛开这个问题,想想我们平常是怎样把一个bean对象(创建)交给Spring容器管理的?

很容易想到两种方式对不对?通过xml配置或者通过@Configuration注解。

xml配置创建bean

<bean id="apple" class="first.Apple"/>

注解创建bean

@Configuration
public class SwaggerConfig{
    @Bean
    public Docket createRestApi()
    {
      
    }
}

那我们就来想一想,是不是在SpringBoot启动的时候,帮我们把这个事情自动给做了?

这里也可以想到我们Spring常说到的一句话,约定大于配置

那我们去找找看看SpringBoot有没有帮我们做这件事情吧~

从启动过程分析

如果你还不熟悉SpringBoot启动做了什么,可以看一看我的上一篇文章 - SpringBoot启动都做了什么?看完就懂了!

我们上篇分析了@SpringBootApplication是一个合成注解,分为

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan

这里我们着重来看@EnableAutoConfiguration具体做了什么事情。

依次点击注解:@SpringBootApplication -> @EnableAutoConfiguration -> @Import({AutoConfigurationImportSelector.class})

点击 AutoConfigurationImportSelector.class

这里我用文字来详细描述该过程:

  1. 利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件;
  2. 调用Listconfigurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类;
  3. 利用工厂加载 Map<String, List> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件;
  4. 从META-INF/spring.factories位置来加载一个文件。默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件,spring-boot-autoconfigure-2.5.6.RELEASE.jar包里面也有META-INF/spring.factories

虽然我们127个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration 按照条件装配规则(@Conditional),最终会按需配置

mybatis实例讲解

mybatis-spring-boot-autoconfigure

@Configuration
// 按需加载:找得到 SqlSessionFactory.class SqlSessionFactoryBean.class类,我这个自动配置才生效。
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties({MybatisProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
public class MybatisAutoConfiguration implements InitializingBean {

    @Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
    }

autoconfigure从哪里引入的?

我在整个过程中,就是引入了这个依赖。

<!-- SpringBoot Web容器 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

starter的题外话:可以把starter看作是dependency的套娃。

spring-boot-starter-web包含的dependency:

<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.5.6</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-json</artifactId>
      <version>2.5.6</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <version>2.5.6</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.3.12</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.3.12</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

里边还能循环嵌套~,通过一层一层的点击,找到spring-boot-autoconfigure 是自动配置

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
    <version>2.5.6</version>
    <scope>compile</scope>
</dependency>

总结

好啦,今天这篇文章就到这里了,稍微总结下。

回到开始面试题的答案,其实有个专业名词,就是自动配置

由于我们springboot引入了spring-boot-autoconfigure的jar包,而在SpringBoot启动的时候自动配置注解会扫描jar包META-INF/spring.factories位置的文件,然后按需加载(通过注解实现)xxxxxAutoConfiguration,从而通过自动加载来实现我们看到的效果。