Skip to content

实现一个简单的SpringBoot-Starter #13

@bitfishxyz

Description

@bitfishxyz

实现一个简单的SpringBoot-Starter

我们使用 Spring Boot,基本上都是沉醉在它 Stater 的方便之中。Starter 为我们带来了众多的自动化配置,有了这些自动化配置,我们可以不费吹灰之力就能搭建一个生产级开发环境,有的小伙伴会觉得这个 Starter 好神奇呀!其实 Starter 也都是 Spring 中的基础知识点实现的,今天codeman就来带大家自己来实现一个 Starter ,慢慢揭开 Starter 的神秘面纱!

核心知识

一个starter一般包含下面的内容:

  • 一个被@ConfigurationProperties注解的配置类

    这个类用来动态的读取用户的配置信息

  • 一个开启自动配置的类

    SpringBoot将会通过这个配置类开启自动配置。
    具体的方法后面再说。然后我们一般都会给自动配置类添加一个@conditional注解,这样在符合某些条件时,开启自动配置,在某些情况下不开启自动配置。

  • 一个完成特定功能的类

    我们的starter最终还是要提供某些服务的。所以我们还要编写真正的提供服务的类,通常这个类会被注册为一个bean。

然后,如果你对我之前提到的几个注解不属性,可以看这里

https://github.com/codeman-cs/SpringBoot/wiki/An-overview-of-25-Spring-Boot-core-annotations

阅读下面的文章之前,你需要掌握这几个注解的用法。

实践

所谓的 Starter ,其实就是一个普通的 Maven 项目,因此我们自定义 Starter ,需要首先创建一个普通的 Maven 项目,创建完成后,添加 Starter 的自动化配置类即可,如下:

创建一个普通maven项目,添加下面的依赖。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
    <version>2.1.4.RELEASE</version>
</dependency>

20190628163106

这就是我们项目的基本骨架。

创建我们的配置类

package com.github.codeman.mystarter;

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

@ConfigurationProperties(prefix = "codeman")
public class CodemanProperties {
    private static final String DEFAULT_NAME = "codeman";
    private static final String DEFAULT_MSG = "learn program in a better way";

    private String name = DEFAULT_NAME;
    private String msg = DEFAULT_MSG;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
}

这个配置类很简单,@ConfigurationProperties(prefix = "codeman")会自动读取application.properties里面的以codeman开头的配置属性。将来我们在applicaton.properties中配置的codeman.namecodeman.msg就会被读取进来并赋值给相应的属性。

创建我们的功能类

一个starter总是要完成特定的事情的,这里我就写一个最简单的服务类,实际的项目中这个可能非常复杂。

public class CodemanService {
    private String msg;
    private String name;
    public String sayHello() {
        return name + " say " + msg + " !";
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

这个服务类也没有做什么特别的事情,等会我们在自动配置时,把它注册为一个bean就行了。

自动配置类

这里就是重点了,我们的自动配置类是这样的。

@Configuration
@EnableConfigurationProperties(CodemanProperties.class)
@ConditionalOnClass(CodemanService.class)
public class CodemanServiceAutoConfiguration {
    @Autowired
    CodemanProperties codemanProperties;

    @Bean
    CodemanService codemanService() {
        CodemanService codemanService = new CodemanService();
        codemanService.setMsg(codemanProperties.getMsg());
        codemanService.setName(codemanProperties.getName());
        return codemanService;
    }
}

20190628163712

  • @Configuration表明这是一个配置类

  • @EnableConfigurationProperties(CodemanProperties.class)

    因为我之前在CodemanProperties这个类中使用了ConfigurationProperties,所以我们这里要有一个配套的@EnableConfigurationProperties

  • 具体实现

    然后我们在配置类中将我们的CodemanService注册成了一个Bean,这样其他模块在使用我们这个模块是时候,就可以直接使用我们的CodemanService了。

不过你可能注意到了,我还写了这个注解
@ConditionalOnClass(CodemanService.class)

它的语义就是存在CodemanService.class这个类的时候,开启自动配置,否则这个类不发生作用。

当然你也可以添加下面这些注解:

  • @ConditionalOnProperty

    Combine @conditional annotations to enable configuration when the specified property has a specified value.

  • @ConditionalOnExpression

    Combine @conditional annotations to enable configuration when the SpEL expression is true.

当然,你可以不写任何的@conditional注解,如果这样的话,你的配置类总是会开启的。

注册配置类

最后一步,为了能让我们的自动配置类发挥作用,我们需要把它按照特定的方式注册。

SpringBoot约定:springboot会先检查META-INF这个文件夹里面的spring.factories文件,并读取下面这个字段。总之按照下面这样写就行了。

20190628164028

实践

编写完我们的配置类后,我们测试一下。

  1. 安装到本地
    直接在当前项目的根目录下执行这个命令,就可以将当前的模块打包成jar文件并安装到本地了
$ mvn install
  1. 创建一个新的项目,用来测试
    然后创建一个新的SpringBoot项目,然后添加这个依赖。
        <dependency>
            <groupId>com.github.codeman</groupId>
            <artifactId>mystarter</artifactId>
            <version>0.0.1</version>
        </dependency>
  1. 编写一个简单的服务。

20190628170603

  1. 再添加一些配置信息。

20190628171158

  1. 最后启动下我们的服务器

20190628162759

可以看到,我们的starter确实起到的作用,codemanService被自动注册到我们的项目中。

总结

然后对于如果你想编写自己的starter,你就应给修改:

  • CodemanService

    这是将是你真正工作的类。

  • CodemanProerties

    你将通过这个配置类读取用户的配置信息。

  • @Conditanal

    取决于你希望在什么情况下开启自动配置。

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions