公司动态

阿里二面:详细讲讲SpringBoot自动装配

可以从以下几个方面回答,先看看能不能回答出来

1. 什么是 SpringBoot 自动装配?

2. SpringBoot 是如何实现自动装配的?如何实现按需加载?

3. 如何实现一个 Starter?

下面来详细讲讲

没有 Spring Boot 的时候,我们写一个 RestFul Web 服务,还首先需要进行如下配置。

阿里二面:详细讲讲SpringBoot自动装配(图1)

spring-servlet.xml

阿里二面:详细讲讲SpringBoot自动装配(图2)

Spring Boot 项目,我们只需要添加相关依赖,无需配置

阿里二面:详细讲讲SpringBoot自动装配(图3)

并且,我们通过 Spring Boot 的全局配置文件 application.propertiesapplication.yml即可对项目进行设置比如更换端口号,配置 JPA 属性等等。为什么 Spring Boot 使用起来这么酸爽呢? 这得益于其自动装配。自动装配可以说是 Spring Boot 的核心,那究竟什么是自动装配呢?

在提到自动装配的时候,一般会和 Spring Boot 联系在一起。但是,实际上 Spring Framework 早就实现了这个功能。Spring Boot 只是在其基础上,通过 SPI 的方式,做了进一步优化。

SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot 在启动时会扫描外部引用 jar 包中的 META-INF/spring.factories 文件,将文件中配置的类型信息加载到 Spring 容器(此处涉及到 JVM 类加载机制与 Spring 的容器知识),并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 SpringBoot 定义的标准,就能将自己的功能装置进 SpringBoot。

没有 Spring Boot 的情况下,如果我们需要引入第三方依赖,需要手动配置,非常麻烦。但是,Spring Boot 中,我们直接引入一个 starter 即可(你可以数数最近的springboot项目引用了多少starter)。比如你想要在项目中使用 redis 的话,直接在项目中引入对应的 starter 即可。

阿里二面:详细讲讲SpringBoot自动装配(图4)

引入 starter 之后,我们通过少量注解和一些简单的配置就能使用第三方组件提供的功能了。自动装配可以简单理解为:通过注解或者一些简单的配置就能在 Spring Boot 的帮助下实现某块功能。

先看一下 SpringBoot 的核心注解 SpringBootApplication

阿里二面:详细讲讲SpringBoot自动装配(图5)

阿里二面:详细讲讲SpringBoot自动装配(图6)

可以把@SpringBootApplication看作是 @Configuration@EnableAutoConfiguration@ComponentScan 注解的集合。根据 SpringBoot 官网,这三个注解的作用分别是:

@EnableAutoConfiguration:启用 SpringBoot 的自动配置机制

@Configuration:允许在上下文中注册额外的 bean 或导入其他配置类

@ComponentScan: 扫描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean。如下图所示,容器中将排除TypeExcludeFilter和
AutoConfigurationExcludeFilter。

@EnableAutoConfiguration 是实现自动装配的重要注解,我们以这个注解入手。

阿里二面:详细讲讲SpringBoot自动装配(图7)

我们现在重点分析下 jnty有限公司
AutoConfigurationImportSelector
类到底做了什么?

阿里二面:详细讲讲SpringBoot自动装配(图8)


AutoConfigurationImportSelector
类实现了 ImportSelector接口,也就实现了这个接口中的 selectImports方法,该方法主要用于获取所有符合条件的类的全限定类名,这些类需要被加载到 IOC 容器中。

阿里二面:详细讲讲SpringBoot自动装配(图9)

重点关注一下 getAutoConfigurationEntry()方法,这个方法主要负责加载自动配置类的。

阿里二面:详细讲讲SpringBoot自动装配(图10)

  1. 判断自动装配开关是否打开。默认spring.boot.enableautoconfiguration=true,可在 application.properties 或 application.yml 中设置
  2. 用于获取EnableAutoConfiguration注解中的 exclude 和 excludeName
  3. 获取需要自动装配的所有配置类,读取META-INF/spring.factories所有 Spring Boot Starter 下的META-INF/spring.factories都会被读取到。
  4. 只加载ConditionalOnXXX的依赖

这里关注介绍一下SpringBoot提供的条件注解

@ConditionalOnBean:当容器里有指定 Bean 的条件下

@ConditionalOnMissingBean:当容器里没有指定 Bean 的情况下

@
ConditionalOnSingleCandidate:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean

@ConditionalOnClass:当类路径下有指定类的条件下

@ConditionalOnMissingClass:当类路径下没有指定类的条件下

@ConditionalOnProperty:指定的属性是否有指定的值

@ConditionalOnResource:类路径是否有指定的值

@ConditionalOnExpression:基于 SpEL 表达式作为判断条件

@ConditionalOnJava:基于 Java 版本作为判断条件

@ConditionalOnJndi:在 JNDI 存在的条件下差在指定的位置

@
ConditionalOnNotWebApplication:当前项目不是 Web 项目的条件下

@
ConditionalOnWebApplication:当前项目是 Web 项 目的条件下

上面的没看懂没关系,我们来一起实现一个例子

第一步,创建
threadpool-spring-boot-starter工程

阿里二面:详细讲讲SpringBoot自动装配(图11)

第二步,完善工程依赖,引入 Spring Boot 相关依赖

第三步,创建
ThreadPoolAutoConfiguration

阿里二面:详细讲讲SpringBoot自动装配(图12)

第四步,在
threadpool-spring-boot-starter工程的 resources 包下创建META-INF/spring.factories文件

阿里二面:详细讲讲SpringBoot自动装配(图13)

第五步,新建工程引入
threadpool-spring-boot-starter

阿里二面:详细讲讲SpringBoot自动装配(图14)

第六步,进行测试启动

阿里二面:详细讲讲SpringBoot自动装配(图15)

(如果前面的原理不清楚,能够把这个例子实现过程一步不漏的讲出来,也能够得不少分)

简言之,Spring Boot 通过@EnableAutoConfiguration开启自动装配,通过 SpringFactoriesLoader 最终加载META-INF/spring.factories中的自动配置类实现自动装配,自动配置类其实就是通过@Conditional按需加载的配置类,想要其生效必须引入spring-boot-starter-xxx包实现起步依赖。


换个角度,要答好这道题,可以记住下述关键词,尝试熟练阐述其作用。这种题目每个人的关注侧重点是不一样的,一定要形成自己的理解。

  • @EnableAutoConfiguration
  • AutoConfigurationImportSelector.selectImports
  • SpringFactoriesLoader
  • ConditionalOnXXX

阿里二面:详细讲讲SpringBoot自动装配(图16)


JNTY jnty