如何在 Spring Boot 中自定义启动器 Starter

前言

Spring Boot 最大的特性可以说就是开箱即用,内部提供的默认自动配置功能,让我们可以在 "零配置" 的情况下,就能够很方便地集成第三方框架。

这一切都要归功于启动器 starter, 比如说,想搭建一个 Spring Boot Web 项目,我们只需要添加 spring-boot-starter-web依赖即可,可以在不做一行配置的情况下,启动一个 Tomcat 应用。

下面是我们常用的 starter 启动器:

  • 单元测试: spring-boot-starter-web;

  • 数据库持久层框架 JPA: spring-boot-starter-data-jpa

  • 安全框架: spring-boot-starter-security;

  • Redis 缓存: spring-boot-starter-data-redis

  • ....

640?wx_fmt=jpeg

用起来是爽了,但是也有人抱怨不如以前的 SSM 框架那样透明化,虽然配置是烦了点,但是我至少知道我开启了哪些功能,如今用了 Spring Boot 后,出了问题,压根不知道问题根源在哪里,蛋疼!

所以说,了解启动器 starter 默认地自动化配置是如何工作的,还是非常有必要的!本文以手写一个自定义的入门级 starter, 带你了解其工作原理。

实践

需求描述

假设我们有这样一个需求:需要自定义一个女盆友 starter, 她带有一个问候的功能,要如何来实现呢?

新建 maven 项目

640?wx_fmt=png

为其取名为: girl-friend-spring-boot-starter.

Spring 官方对 starter 的命名是有规范的,只有官方提供的 starter, 才能命名为 spring-boot-starter-{name}, 比如 spring-boot-starter-web; 而对于非官方的,需以 {name}-spring-boot-starter 的格式命名。

添加 spring-boot-autoconfigure 依赖

pom.xml 文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>	
<project xmlns="http://maven.apache.org/POM/4.0.0"	
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"	
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">	
    <modelVersion>4.0.0</modelVersion>	
    <parent>	
        <groupId>org.springframework.boot</groupId>	
        <artifactId>spring-boot-starter-parent</artifactId>	
        <version>2.1.2.RELEASE</version>	
        <relativePath/> <!-- lookup parent from repository -->	
    </parent>	
    <groupId>site.exception</groupId>	
    <artifactId>girl-friend-spring-boot-starter</artifactId>	
    <version>1.0-SNAPSHOT</version>	
    <properties>	
        <java.version>1.8</java.version>	
    </properties>	
    <dependencies>	
        <!-- 自动化配置依赖,自定义 starter 核心依赖包 -->	
        <dependency>	
            <groupId>org.springframework.boot</groupId>	
            <artifactId>spring-boot-autoconfigure</artifactId>	
        </dependency>	
    </dependencies>	
</project>

新增功能类

新增下面三个类:

  • GirlFriendServiceProperties(配置类);

  • GirlFriendService (女盆友接口);

  • GirlFriendServiceImpl(女盆友接口实现);

上源码:

GirlFriendServiceProperties.java:

package site.exception;	
import org.springframework.boot.context.properties.ConfigurationProperties;	
/**	
 * @author www.excpetion.site(exception 教程网)	
 * @date 2019/1/30	
 * @time 11:22	
 * @discription	
 **/	
@ConfigurationProperties(prefix = "spring.girlfriend")	
public class GirlFriendServiceProperties {	
    /** 默认输出 */	
    private String message = "Hi, good morning !";	
    public String getMessage() {	
        return message;	
    }	
    public void setMessage(String message) {	
        this.message = message;	
    }	
}

@ConfigurationProperties注解能够自动获取 application.properties 配置文件中前缀为 spring.girlfriend 节点下 message属性的内容,这里我们给了它一个默认值: Hi,good morning!

GirlFriendService.java:

package site.exception;	
/**	
 * @author www.excpetion.site(exception 教程网)	
 * @date 2019/1/30	
 * @time 11:07	
 * @discription	
 **/	
public interface GirlFriendService {	
    /**	
     * 打招呼	
     * @return	
     */	
    void say();	
}

GirlFriendServiceImpl.java:

package site.exception;	
import org.springframework.beans.factory.annotation.Autowired;	
/**	
 * @author www.excpetion.site(exception 教程网)	
 * @date 2019/1/30	
 * @time 11:07	
 * @discription	
 **/	
public class GirlFriendServiceImpl implements GirlFriendService {	
    @Autowired	
    private GirlFriendServiceProperties girlFriendServiceProperties;	
    /**	
     * 打招呼	
     *	
     */	
    @Override	
    public void say() {	
        String message = girlFriendServiceProperties.getMessage();	
        System.out.println("Girl Friend: " + message);	
    }	
}

GirlFriendServiceImpl 实现了 GirlFriendService 接口的 say() 方法,它会获取 GirlFriendServiceProperties 配置类 message 内容,并打印到控制台。

硬菜:新增自动配置类

创建类 GirlFriendAutoConfiguration.java 来实现自动配置化功能:

package site.exception;	
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;	
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;	
/**	
 * @author www.excpetion.site(exception 教程网)	
 * @date 2019/1/30	
 * @time 11:11	
 * @discription	
 **/	
@Configuration	
@ConditionalOnClass(GirlFriendService.class)	
@EnableConfigurationProperties(GirlFriendServiceProperties.class)	
public class GirlFriendAutoConfiguration {	
    @Bean	
    @ConditionalOnMissingBean	
    public GirlFriendService girlFriendService() {	
        return new GirlFriendServiceImpl();	
    }	
}

接下来,对上面相关注解说明一下:

  • @Configuration: 标注类为一个配置类,让 spring 去扫描它;

  • @ConditionalOnClass:条件注解,只有在 classpath 路径下存在指定 class 文件时,才会实例化 Bean;

  • @EnableConfigurationProperties:使指定配置类生效;

  • @Bean: 创建一个实例类注入到 Spring Ioc 容器中;

  • @ConditionalOnMissingBean:条件注解,意思是,仅当 Ioc 容器不存在指定类型的 Bean 时,才会创建 Bean。

新增 spring.factories 文件

resources 目录下创建名为 META-INF 的目录,并新建文件 spring.factories,内容如下:

# 指定刚刚创建的 GirlFriendAutoConfiguration 的全路径名	
org.springframework.boot.autoconfigure.EnableAutoConfiguration=site.exception.GirlFriendAutoConfiguration

Spring Boot 会在启动时,自动会去查找指定文件 /META-INF/spring.factories,若有,就会根据配置的类的全路径去自动化配置。

完成这一步后,一个入门级的 spring-boot-starter 已经开发完成了,看下整体的目录结构:

640?wx_fmt=png

打包 jar

接下来,就是将 girl-friend-spring-boot-starter 打成 jar 包,放到本地的 maven 仓库中去,在项目根路径下执行 maven 命令: mvn clean install.

C:\dev\idea_workspace_personal\spring-boot-tutorial\girl-friend-spring-boot-starter>mvn clean install	
[INFO] Scanning for projects...	
[INFO]	
[INFO] -----------< site.exception:girl-friend-spring-boot-starter >-----------	
[INFO] Building girl-friend-spring-boot-starter 1.0-SNAPSHOT	
[INFO] --------------------------------[ jar ]---------------------------------	
[INFO]	
[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ girl-friend-spring-boot-starter ---	
[INFO] Deleting C:\dev\idea_workspace_personal\spring-boot-tutorial\girl-friend-spring-boot-starter\target	
[INFO]	
[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ girl-friend-spring-boot-starter ---	
[INFO] Using 'UTF-8' encoding to copy filtered resources.	
[INFO] Copying 0 resource	
[INFO] Copying 1 resource	
[INFO]	
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ girl-friend-spring-boot-starter ---	
[INFO] Changes detected - recompiling the module!	
[INFO] Compiling 4 source files to C:\dev\idea_workspace_personal\spring-boot-tutorial\girl-friend-spring-boot-starter\target\classes	
[INFO]	
[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ girl-friend-spring-boot-starter ---	
[INFO] Using 'UTF-8' encoding to copy filtered resources.	
[INFO] skip non existing resourceDirectory C:\dev\idea_workspace_personal\spring-boot-tutorial\girl-friend-spring-boot-starter\src\test\resources	
[INFO]	
[INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ girl-friend-spring-boot-starter ---	
[INFO] Nothing to compile - all classes are up to date	
[INFO]	
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ girl-friend-spring-boot-starter ---	
[INFO] No tests to run.	
[INFO]	
[INFO] --- maven-jar-plugin:3.1.1:jar (default-jar) @ girl-friend-spring-boot-starter ---	
[INFO] Building jar: C:\dev\idea_workspace_personal\spring-boot-tutorial\girl-friend-spring-boot-starter\target\girl-friend-spring-boot-starter-1.0-SNAPSHOT.jar	
[INFO]	
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ girl-friend-spring-boot-starter ---	
[INFO] Installing C:\dev\idea_workspace_personal\spring-boot-tutorial\girl-friend-spring-boot-starter\target\girl-friend-spring-boot-starter-1.0-SNAPSHOT.jar to C:\User	
s\allen\.m2\repository\site\exception\girl-friend-spring-boot-starter\1.0-SNAPSHOT\girl-friend-spring-boot-starter-1.0-SNAPSHOT.jar	
[INFO] Installing C:\dev\idea_workspace_personal\spring-boot-tutorial\girl-friend-spring-boot-starter\pom.xml to C:\Users\allen\.m2\repository\site\exception\girl-frien	
d-spring-boot-starter\1.0-SNAPSHOT\girl-friend-spring-boot-starter-1.0-SNAPSHOT.pom	
[INFO] ------------------------------------------------------------------------	
[INFO] BUILD SUCCESS	
[INFO] ------------------------------------------------------------------------	
[INFO] Total time:  6.247 s	
[INFO] Finished at: 2019-01-30T15:31:03+08:00	
[INFO] ------------------------------------------------------------------------

新建一个 Spring Boot Web 项目,引用自定 starter

新创建一个 Spring Boot Web 项目,在 pom.xml 文件中加入自定义的 starter 依赖:

<!-- Girl Friend starter -->	
<dependency>	
    <groupId>site.exception</groupId>	
    <artifactId>girl-friend-spring-boot-starter</artifactId>	
    <version>1.0-SNAPSHOT</version>	
</dependency>

Applicaiton 启动类中,自动注入 GirlFriendService 实例,并调用 say() 方法:

package site.exception.springboothello;	
import org.springframework.beans.factory.annotation.Autowired;	
import org.springframework.boot.CommandLineRunner;	
import org.springframework.boot.SpringApplication;	
import org.springframework.boot.autoconfigure.SpringBootApplication;	
import site.exception.GirlFriendService;	
@SpringBootApplication	
public class SpringBootHelloApplication implements CommandLineRunner {	
    public static void main(String[] args) {	
        SpringApplication.run(SpringBootHelloApplication.class, args);	
    }	
    @Autowired	
    private GirlFriendService girlFriendService;	
    @Override	
    public void run(String... args) throws Exception {	
        // 调用打招呼方法	
        girlFriendService.say();	
    }	
}

启动项目,看看在零配置的情况下,它的输出:

  .   ____          _            __ _ _	
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \	
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \	
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )	
  '  |____| .__|_| |_|_| |_\__, | / / / /	
 =========|_|==============|___/=/_/_/_/	
 :: Spring Boot ::        (v2.1.2.RELEASE)	
2019-01-30 15:40:48.308  INFO 25320 --- [  restartedMain] s.e.s.SpringBootHelloApplication         : Starting SpringBootHelloApplication on DESKTOP-RL6P6LA with PID 25320 (C:\dev\idea_workspace_personal\spring-boot-tutorial\spring-boot-hello\target\classes started by allen in C:\dev\idea_workspace_personal\spring-boot-tutorial)	
2019-01-30 15:40:48.314  INFO 25320 --- [  restartedMain] s.e.s.SpringBootHelloApplication         : No active profile set, falling back to default profiles: default	
2019-01-30 15:40:48.457  INFO 25320 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable	
2019-01-30 15:40:48.458  INFO 25320 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'	
2019-01-30 15:40:51.299  INFO 25320 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)	
2019-01-30 15:40:51.372  INFO 25320 --- [  restartedMain] o.apache.catalina.core.StandardService   : Starting service [Tomcat]	
2019-01-30 15:40:51.373  INFO 25320 --- [  restartedMain] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.14]	
2019-01-30 15:40:51.387  INFO 25320 --- [  restartedMain] o.a.catalina.core.AprLifecycleListener   : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [C:\dev\java\jdk1.8\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\dev\java\jdk1.8\bin;C:\dev\java\jdk1.8\jre\bin;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files (x86)\pycSafefile\x64;C:\dev\java\apache-maven-3.6.0\bin;D:\dev\redis\;C:\dev\git\cmd;C:\Users\allen\AppData\Local\Microsoft\WindowsApps;;C:\Program Files\Docker Toolbox;.]	
2019-01-30 15:40:51.628  INFO 25320 --- [  restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext	
2019-01-30 15:40:51.629  INFO 25320 --- [  restartedMain] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3171 ms	
2019-01-30 15:40:51.921  INFO 25320 --- [  restartedMain] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'	
2019-01-30 15:40:52.142  INFO 25320 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729	
2019-01-30 15:40:52.204  INFO 25320 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''	
2019-01-30 15:40:52.207  INFO 25320 --- [  restartedMain] s.e.s.SpringBootHelloApplication         : Started SpringBootHelloApplication in 4.56 seconds (JVM running for 6.523)	
Girl Friend: Hi, good morning !

640?wx_fmt=png

可以看到,在没做任何配置的情况下,输出的是默认打招呼信息:Hi, good morning !,接下来,我们手动配置一下新的打招呼内容,看看是否能自动获取到。

application.properties 文件中配置如下:

spring.girlfriend.message=I LOVE YOU

重启项目,验证一下,是否输出的还是默认信息:

640?wx_fmt=png

正确打印我们自己配置的:I LOVE YOU

GitHub 源码地址

https://github.com/weiwosuoai/spring-boot-tutorial

总结

此文中,我们学习了如何自定义入门级 spring-boot-starter,这仅仅是个开始,能做的远不止于此,这里也只是抛砖引玉而已,希望您阅读愉快!

·END·


 近期热文:

如果你喜欢本文

请长按二维码,关注小哈学Java

640?wx_fmt=jpeg

转发朋友圈,是对我最大的支持。


看完,赶紧点个“好看”鸭

点鸭点鸭

↓↓↓↓

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值