Skip to content


起步依赖

在 SpringBoot 给我们提供的这些起步依赖当中,已提供了当前程序开发所需要的所有的常见依赖(官网地址:https://docs.spring.io/spring-boot/docs/2.7.7/reference/htmlsingle/#using.build-systems.starters)

比如:springboot-starter-web,这是 web 开发的起步依赖,在 web 开发的起步依赖当中,就集成了 web 开发中常见的依赖:json、web、webmvc、tomcat 等。我们只需要引入这一个起步依赖,其他的依赖都会自动的通过 Maven 的依赖传递进来

假如我们没有使用 SpringBoot,用的是 Spring 框架进行 web 程序的开发,此时我们就需要引入 web 程序开发所需要的一些依赖


当我们引入了 spring-boot-starter-web 之后,maven 会通过依赖传递特性,将 web 开发所需的常见依赖都传递下来


所以,起步依赖的原理就是 Maven 的依赖传递

自动装配

基本介绍

SpringBoot 的自动配置就是当 spring 容器启动后,一些配置类、bean 对象就自动存入到了 IOC 容器中,不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作

问题引入

准备工作:在 Idea 中导入"资料\03. 自动配置原理" 下的 itheima-utils 工程

在 SpringBoot 项目 spring-boot-web-config 工程中,通过坐标引入 itheima-utils 依赖

(1)引入的 itheima-utils 中配置如下

java
@Component
public class TokenParser {
    public void parse(){
        System.out.println("TokenParser ... parse ...");
    }
}

(2)在测试类中,添加测试方法

java
@SpringBootTest
public class AutoConfigurationTests {
    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void testTokenParse(){
        System.out.println(applicationContext.getBean(TokenParser.class));
    }

    //省略其他代码...
}

(3)执行测试方法

异常信息描述: 没有 com.example.TokenParse 类型的 bean

说明:在 Spring 容器中没有找到 com.example.TokenParse 类型的 bean 对象

思考:引入进来的第三方依赖当中的 bean 以及配置类为什么没有生效?

(1)原因在我们之前讲解 IOC 的时候有提到过,在类上添加 @Component 注解来声明 bean 对象时,还需要保证@Component 注解能被 Spring 的组件扫描到

(2)SpringBoot 项目中的 @SpringBootApplication 注解,具有包扫描的作用,但是它只会扫描启动类所在的当前包以及子包

(3)当前包:com.itheima, 第三方依赖中提供的包:com.example(扫描不到)

那么如何解决以上问题的呢?

方案 1:@ComponentScan 组件扫描

方案 2:@Import 导入(使用@Import 导入的类会被 Spring 加载到 IOC 容器中)

方案一:组件扫描

相关注解

@ComponentScan 组件扫描,需要在 Springboot 项目中的启动类中声明,传递的是一个数组,每个元素都是一个包名,可以通过指定包名来指定需要扫描的类

代码实现

java
@SpringBootApplication
@ComponentScan({"com.itheima","com.example"}) //指定要扫描的包
public class SpringbootWebConfigApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebConfigApplication.class, args);
    }
}

缺点分析

可以想象一下,如果采用以上这种方式来完成自动配置,那我们进行项目开发时,当需要引入大量的第三方的依赖,就需要在启动类上配置 N 多要扫描的包,这种方式会很繁琐。而且这种大面积的扫描性能也比较低

缺点:(1)使用繁琐(2)性能低

结论:SpringBoot 中并没有采用以上这种方案

方案二:导入

相关注解

@Import注解,需要传递类的 class 对象(类名.class),需要在 Springboot 项目中的启动类中声明

导入形式

(1)导入普通类

(2)导入配置类

(3)导入 ImportSelector 接口实现类

导入普通类示例

java
@Import(TokenParser.class) // 导入的类会被Spring加载到IOC容器中
@SpringBootApplication
public class SpringbootWebConfigApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebConfigApplication.class, args);
    }
}

导入配置类示例

(1)配置类

java
@Configuration
public class HeaderConfig {
    @Bean
    public HeaderParser headerParser(){
        return new HeaderParser();
    }

    @Bean
    public HeaderGenerator headerGenerator(){
        return new HeaderGenerator();
    }
}

(2)启动类

java
@Import(HeaderConfig.class) //导入配置类
@SpringBootApplication
public class SpringbootWebConfig2Application {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebConfig2Application.class, args);
    }
}

(3)测试类

java
@SpringBootTest
public class AutoConfigurationTests {
    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void testHeaderParser(){
        System.out.println(applicationContext.getBean(HeaderParser.class));
    }

    @Test
    public void testHeaderGenerator(){
        System.out.println(applicationContext.getBean(HeaderGenerator.class));
    }

    //省略其他代码...
}

ImportSelector 接口

数组中需要传入类的全限定名

(1) ImportSelector 接口实现类

java
public class MyImportSelector implements ImportSelector {
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //返回值字符串数组(数组中封装了全限定名称的类)
        return new String[]{"com.example.HeaderConfig"};
    }
}

(2)启动类

java
@Import(MyImportSelector.class) //导入ImportSelector接口实现类
@SpringBootApplication
public class SpringbootWebConfig2Application {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebConfig2Application.class, args);
    }
}

导入优化

问题分析

(1)思考:如果基于以上方式完成自动配置,当要引入一个第三方依赖时,是不是还要知道第三方依赖中有哪些配置类和哪些 Bean 对象?

答案:是的。 (对程序员来讲,很不友好,而且比较繁琐)

(2)思考:当我们要使用第三方依赖,依赖中到底有哪些 bean 和配置类,谁最清楚?

答案:第三方依赖自身最清楚,我们不用自己指定要导入哪些 bean 对象和配置类了,让第三方依赖它自己来指定

(3)怎么让第三方依赖自己指定 bean 对象和配置类?

比较常见的方案就是第三方依赖给我们提供一个注解,这个注解一般都以 @EnableXxxx 开头的注解,注解中封装的就是 @Import 注解

优化实现

第三方提供的注解

java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MyImportSelector.class) // 指定要导入哪些bean对象或配置类
public @interface EnableHeaderConfig {
}

在使用时只需在启动类上加上@EnableXxxxx 注解即可

java
@EnableHeaderConfig  //使用第三方依赖提供的Enable开头的注解
@SpringBootApplication
public class SpringbootWebConfig2Application {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebConfig2Application.class, args);
    }
}
···

注意事项

以上四种方式都可以完成导入操作,但是第 4 种方式会更方便更优雅,而这种方式也是 SpringBoot 当中所采用的方式