1.开始

首先肯定要说一下SpringBoot的四大核心了:

  • 自动装配:简单配置甚至零配置即可运行项目
  • 起步依赖:场景启动器
  • Actuator:指标监控
  • 命令行界面 :命令行

关于四大核心中的自动装配,可以看下这篇文章:SpringBoot——四大核心之自动装配(源码解析)_张起灵-小哥的博客-CSDN博客

这篇文章呢,我来和大家聊聊起步依赖这个东西。


2.聊聊起步依赖

首先呢,我们来看一个SpringBoot项目中最常见的依赖项。

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

这个我们都知道,一般称为 SpringBoot框架web项目的起步依赖,那么为什么我们添加这个依赖之后,之前在SpringMVC中的一些依赖就不需要再添加了呢?点进入这个依赖看看。

可以看到这个依赖中,还管理着其他依赖,其中就有tomcat、spring-webmvc这些,这不都是之前学SpringMVC需要配置tomcat以及其他依赖项吗?而spring-boot-starter-web这个起步依赖已经帮我们做好了,你就不需要再添加很多其他依赖了,是不是很方便呢?

在我们创建一个SpringBoot项目之后,向其中的pom文件添加依赖的时候,我们会发现,添加的很多依赖都是以 spring-boot-start-XXX 这样的形式,我当时就按照字面意思去理解:springboot-开始-XXX的依赖。

那么,我们现在说的规范一点:spring-boot-start-XXX就是spring-boot的场景启动器。

spring-boot-starter-web:帮我们导入了web模块正常运行所依赖的组件;

spring-boot-starter-thymeleaf:帮我们导入了thymeleaf模板引擎正常运行所依赖的组件;

SpringBoot就是将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;我们未来也可以自己自定义 starter。

说的形象一点,我们之前学SSM的时候,在pom文件中加入依赖,是不是有spring-context、spring-core、spring-webmvc等等。而现在不需要了,你就可以直接写一个spring-boot-start-XXX完事了。之前SSM那种方式就是点了一份又一份的菜,而现在SpringBoot直接就是点了一个套餐,这个套餐中有很多你需要的菜名。

我们可以在spring.factories配置文件中,随便找一个自动配置类点进去看看。

可以看到,在SpringBoot官方的starter中,先是定义了一个XXXAutoConfiguration自动配置类,然后这个类上标注的一些注解:是个配置类、什么条件下生效,导入了哪些类,以及开启对@ConfigurationProperties 注解的支持,在这个@EnableConfigurationProperties注解中,还有一个XXXProperties的属性配置类,在这个类中,上面有一个配置前缀信息的注解,而这个类中有一些属性、set/get方法,而这个前缀 + 属性 就是我们在application.properties配置文件中所写的属性名。


3.自定义starter

上面说的是SpringBoot官方的starter,那么我们也可以自定义starter。

starter的命名有一种习惯,官方的starter一般都是spring-boot-starter-xxx,而我们自定义的starter一般都是xxx-spring-boot-starter。

先来看一下,完成整个自定义starter需要哪几个项目

  • hello-spring-boot-starter:在项目开发中真正要引入的场景启动器。场景启动器引入了自动配置包模块hello-spring-boot-autoconfigure。
  • hello-spring-boot-autoconfigure:真正的自动配置包模块,它实现的才是springboot的自动装配原理。
  • boot-hello-test:测试模块。

3.1 hello-spring-boot-autoconfigure(普通SpringBoot项目)

我们自定义starter就是为了将某些热门的业务功能给抽取出来,做成一个个的场景启动器,为开发做准备。

所以这里先写一个service。

package com.szh.boot.service;

import com.szh.boot.bean.HelloProperties;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * 默认不要放在IoC容器中
 */
public class HelloService {

    @Autowired
    private HelloProperties helloProperties;

    public String sayHello() {
        return "盗墓者姓名: " + helloProperties.getName() + ", 盗墓者年龄: " + helloProperties.getAge();
    }
}

由于service中的业务,是我们未来开发中要调用的,从中获取一些属性、执行一定的业务逻辑,所以我们要在service中注入XxxProeprties属性类。

下面来编写这个属性类。

package com.szh.boot.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 *
 */
@ConfigurationProperties(prefix = "szh.info")
public class HelloProperties {

    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

又因为springboot的自动装配原理是:读取 META-INF\spring.factories 文件,加载这其中的所有组件,之后再根据 XXXAutoConfiguration 自动配置类中的注解属性来决定哪些自动配置类生效、哪些不生效,生效之后再根据某些注解属性条件来决定向容器中添加哪些组件(@Bean),同时将 自动配置类与属性类 进行绑定,这样我们就可以通过service完成对XxxProeprties属性类的注入和使用。

所以,下面来编写核心的 XXXAutoConfiguration 自动配置类。

package com.szh.boot.auto;

import com.szh.boot.bean.HelloProperties;
import com.szh.boot.service.HelloService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Configuration: 声明该类为配置类
 * @ConditionalOnMissingBean: 当容器中没有HelloService这个Bean时, 这个自动配置类才生效
 * @EnableConfigurationProperties: 与相应的XxxProperties属性类进行绑定, 并放入容器中
 */
@Configuration
@ConditionalOnMissingBean(HelloService.class)
@EnableConfigurationProperties(HelloProperties.class)
public class HelloAutoConfiguration {

    @Bean
    public HelloService helloService() {
        return new HelloService();
    }
}

因为要读取 META-INF\spring.factories 文件,所以这里来创建好 META-INF\spring.factories 文件,位于 resources 目录下。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.szh.boot.auto.HelloAutoConfiguration

这个模块的代码编写已经完成,下面将这个模块进行 clean、install 打包到maven本地仓库,以便我们在 starter 场景启动器中可以引入。

3.2 hello-spring-boot-starter(普通maven项目)

因为上面已经完成对 自动装配 模块的编写,同时也已经 maven install 了,所以在场景启动器模块中直接引入就行。

<dependencies>
    <dependency>
        <groupId>com.szh.boot</groupId>
        <artifactId>hello-spring-boot-autoconfigure</artifactId>
        <version>1.0.0</version>
    </dependency>
</dependencies>

依赖添加之后,将我们的starter场景启动器同样 maven clean、install 打包到本地仓库中,以便测试模块中进行依赖的导入。

3.3 boot-hello-test(SpringBoot Web项目)

最后来写我们的测试模块,根据以往学习springboot的经历,我们引入依赖肯定大部分都是引入了官方定义好的starter(spring-boot-starter-xxx),在这些场景启动器中有相关的 autoconfigure 自动配置依赖。

所以我们自定义starter也是一样的,将相关的 autoconfigure 自动配置依赖打包,然后在 starter 中进行引入,最后在开发测试的模块中只需要将starter引入就可以了。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>com.szh.boot</groupId>
        <artifactId>hello-spring-boot-starter</artifactId>
        <version>1.0.0</version>
    </dependency>
</dependencies>

在测试模块中,先写一个 controller。在其中注入了我们在自动装配模块中写好的服务类HelloService,在HelloService中已经注入了XXXProperties属性类,所以这里我们一旦注入HelloService,也就有了相应的自动配置类、属性类。

package com.szh.boot.controller;

import com.szh.boot.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 *
 */
@RestController
public class HelloController {

    @Autowired
    private HelloService helloService;

    @GetMapping(value = "/hello")
    public String getInfo() {
        return helloService.sayHello();
    }
}

下面,就可以在核心配置文件中定义XXXProperties属性类中的配置项的值了。

szh.info.name=张起灵
szh.info.age=18

最后,启动测试。

package com.szh.boot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class BootHelloTestApplication {

    public static void main(String[] args) {
        SpringApplication.run(BootHelloTestApplication.class, args);
    }

}

可以看到,成功的获取到了配置文件中的属性值。

至此,我们的自定义starter的所有步骤已经全部完成了。

更多推荐

SpringBoot——四大核心之起步依赖(自定义starter)