SpringBoot第十六篇:自定义starter
作者:追梦1819
原文:https://www.cnblogs.com/yanfei1819/p/11058502.html
版权声明:本文为博主原创文章,转载请附上博文链接!
前言
这一段时间项目赶进度,故该系列博客更新没有之前那么频繁,望谅解。
SpringBoot 用起来方便,它默认集成了 Java 的主流框架。这也是 SpringBoot 的一大特色,使用方便,需要什么框架或者技术,只需要引入对应的 starter 即可。目前官方已经集成的各大技术的启动器,可以查看 文档。
作者最开始考虑该话题的是曾经的一个面试题:如何自定义一个自定义启动器?
本文将围绕该面试题进行讲解。
自定义starter
在自定义 starter 之前,我们先回顾 SpringBoot 官方已经集成的 starter 。我们使用时,只需引入对应的 spring-boot-starter-xxx
即可使用(即我们常说的开箱即用)。
同时,还预先设置了默认值,如果需要修改这些默认值,只需要在 application.properties 或 application.yml 配置文件中修改。例如:SpringBoot 默认的端口号是 8080,如果需要修改该端口号,只需要在 application.properties 中添加属性 server.port=9090
即可。
创建自定义启动器,需要创建以下两个组件:
- 自动配置类以及自定义配置的属性类;
- 对应的 maven 依赖。
首先,创建自定义starter工程,并引入maven依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.0.0.RELEASE</version>
<optional>true</optional>
</dependency>
然后,创建实体类。前缀加上字段名称可以在application.properties文件中创建属性的名称。
package com.yanfei1819.springbootstarter.entity;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Created by 追梦1819 on 2019-05-10.
*/
@ConfigurationProperties(prefix = "spring.person")
public class PersonProperties {
private String name;
private int age;
private double salary;
// set/get 省略
}
第三步,定义核心服务类,该类主要定义了 starter 的核心功能。
package com.yanfei1819.springbootstarter.service;
import com.yanfei1819.springbootstarter.entity.PersonProperties;
/**
* Created by 追梦1819 on 2019-05-10.
*/
public class PersonService {
private PersonProperties properties;
public PersonService(PersonProperties properties) {
this.properties = properties;
}
public PersonService() {
}
public void say() {
System.out.println("hello,I am " + properties.getName() + ",and I am " + properties.getAge() +
",and My salary " + properties.getSalary());
}
}
第四步,自定义配置类。通常情况每个 starter 至少有一个配置类。命名规则也很明显,一般命名规则使用XxxAutoConfiguration, 例如 RedisAutoConfiguration 等。该类将核心功能注入到 SpringBoot 上下文中。
package com.yanfei1819.springbootstarter.configuration;
import com.yanfei1819.springbootstarter.entity.PersonProperties;
import com.yanfei1819.springbootstarter.service.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Created by 追梦1819 on 2019-05-10.
*/
@Configuration
@EnableConfigurationProperties(PersonProperties.class)
@ConditionalOnClass(PersonService.class)
@ConditionalOnProperty(prefix = "spring.person", value = "enabled", matchIfMissing = true)
public class PersonServiceAutoConfiguration {
@Autowired
private PersonProperties properties;
@Bean
@ConditionalOnMissingBean(PersonService.class) // 当容器中没有指定Bean的情况下,自动配置PersonService类
public PersonService personService() {
PersonService personService = new PersonService(properties);
return personService;
}
}
最后,创建 spring.factories 文件:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.yanfei1819.springbootstarter.configuration.PersonServiceAutoConfiguration
当 SpringBoot 启动的时候,它会在类路径中查找 spring.factories 文件,此条件初始化由@ConditionalOnClass注释启用。此文件将名称映射到Spring Boot将尝试运行的不同配置类。因此,根据这个片段,Spring Boot将尝试运行RabbitMQ,Cassandra,MongoDB和Hibernate的所有配置类。
@EnableAutoConfiguration 的关键功能是使用 SpringFactoriesLoader.loadFactoryNames 方法来扫描具有 META-INF/spring.factories 文件的 jar 包,这样我们的自动配置类才能生效,所以我们在 autoconfigure 模块的 resources 下创建 META-INF/spring.factories 文件。
使用自定义starter
新创建一个工程,引入自定义启动器的 maven 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.yanfei1819</groupId>
<artifactId>customize-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
此处我们要注意一下命名规则,官方命名是spring-boot-starter-xxx
, 自定义命名是 xxx-spring-boot-starter
。
然后再配置文件中写入测试数据:
spring.person.name=starter
spring.person.age=26
下面我们修改启动类做个简单的测试:
package com.yanfei1819.customizestartertest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CustomizeStarterTestApplication implements CommandLineRunner {
@Value("${spring.person.name}")
private String name;
@Value("${spring.person.age}")
private int age;
public static void main(String[] args) {
SpringApplication.run(CustomizeStarterTestApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
System.out.println("姓名是:"+name+",年龄是:"+age);
}
}
上面的启动类实现了 CommandLineRunner 接口,并重写了 run 方法。Spring boot的CommandLineRunner
接口主要用于实现在应用初始化后,去执行一段代码块逻辑,这段初始化代码在整个应用生命周期内只会执行一次。(该接口的作用可以参照官网说明)。
此处是为了省去写测试类才实现了该接口。
最后,启动项目,可以看到如下结果:
总结
根据以上的分析和示例,可以大概总结出 starter 的工作流程:
SpringBoot 启动时寻找含 spring.factories 文件的JAR包;
读取spring.factories文件获取配置的自动配置类AutoConfiguration;
将自动配置类下满足条件(@ConditionalOnXxx)的@Bean放入到 Springoot 上下文中;
开发者直接使用。
感悟
SpringBoot 的自定义启动器极大的方便了独立功能 jar 的开发,消除了大量的配置工作。
依葫芦画瓢,要写一个自定义的starter,其实很简单,注意几个注解就可以了。但是,我们真正要做的,是通过源码来理解自动配置原理,原理是灵魂,知其然,知其所以然,这样去自定义 starter 才会得心应手。后续我们将继续分享 SpringBoot 的自动配置原理。
参考

SpringBoot第十六篇:自定义starter的更多相关文章
- Python之路【第十六篇】:Django【基础篇】
Python之路[第十六篇]:Django[基础篇] Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了O ...
- 跟我学SpringCloud | 第十六篇:微服务利剑之APM平台(二)Pinpoint
目录 SpringCloud系列教程 | 第十六篇:微服务利剑之APM平台(二)Pinpoint 1. Pinpoint概述 2. Pinpoint主要特性 3. Pinpoint优势 4. Pinp ...
- 解剖SQLSERVER 第十六篇 OrcaMDF RawDatabase --MDF文件的瑞士军刀(译)
解剖SQLSERVER 第十六篇 OrcaMDF RawDatabase --MDF文件的瑞士军刀(译) http://improve.dk/orcamdf-rawdatabase-a-swiss-a ...
- SpringBoot第二十四篇:应用监控之Admin
作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/11457867.html 版权声明:本文为博主原创文章,转载请附上博文链接! 引言 前一章(S ...
- Egret入门学习日记 --- 第十六篇(书中 6.10~7.3节 内容)
第十六篇(书中 6.10~7.3节 内容) 昨天搞定了6.9节,今天就从6.10节开始. 其实这个蛮简单的. 这是程序员模式. 这是设计师模式. 至此,6.10节 完毕. 开始 6.11节. 有点没营 ...
- SpringBoot | 第二十六章:邮件发送
前言 讲解了日志相关的知识点后.今天来点相对简单的,一般上,我们在开发一些注册功能.发送验证码或者订单服务时,都会通过短信或者邮件的方式通知消费者,注册或者订单的相关信息.而且基本上邮件的内容都是模版 ...
- java框架之SpringBoot(10)-启动流程及自定义starter
启动流程 直接从 SpringBoot 程序入口的 run 方法看起: public static ConfigurableApplicationContext run(Object source, ...
- SpringBoot第十五篇:swagger构建优雅文档
作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/11007470.html 版权声明:本文为博主原创文章,转载请附上博文链接! 引言 前面的十四 ...
- SpringBoot启动源码及自定义starter
为什么springboot工程能够在mian方法中完成启动呢?需要大家掌握的有几个点:1.SPISPI在springboot中是去读取META-INF/spring.factories目录的配置文件内 ...
随机推荐
- 【转】Hive安装及使用攻略
Posted: Jul 16, 2013 Tags: HadoophiveHiveQLsql分区表 Comments: 18 Comments Hive安装及使用攻略 让Hadoop跑在云端系列文章, ...
- [BZOJ3531] Peaks加强版
Peaks Peaks 加强版 Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越 ...
- [ZOJ1610]Count the Colors
Description 画一些颜色段在一行上,一些较早的颜色就会被后来的颜色覆盖了. 你的任务就是要数出你随后能看到的不同颜色的段的数目. Input 每组测试数据第一行只有一个整数n, 1 < ...
- [Usaco2006 Jan] Dollar Dayz 奶牛商店
Description 约翰到奶牛商场里买工具.商场里有K(1≤K≤100).种工具,价格分别为1,2,-,K美元.约翰手里有N(1≤N≤1000)美元,必须花完.那他有多少种购买的组合呢? Inpu ...
- UVA 10462 Is There A Second Way Left? (次小生成树+kruskal)
题目大意: Nasa应邻居们的要求,决定用一个网络把大家链接在一起.给出v个点,e条可行路线,每条路线分别是x连接到y需要花费w. 1:如果不存在最小生成树,输出“No way”. 2:如果不存在次小 ...
- Linux磁盘分区、格式化和挂载
一.查看磁盘使用 [root@iZ88rvassw1Z ~]# df -h Filesystem Size Used Avail Use% Mounted on /dev/vda1 40G .3G 3 ...
- 455 Assign Cookies 分发饼干
假设你是一位很棒的家长,想要给你的孩子们一些小饼干.但是,每个孩子最多只能给一块饼干.对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸:并且每块饼干 j ,都有一个尺寸 ...
- $ ssh -T git@github.com ssh: connect to host ssh.github.com port 22: Connection timed out
在C:/用户/用户名/.ssh中添加几个文件 之前的电脑生成都是四个文件,分别是 id_rsa id_rsa.pub config known_hosts 不知道为什么在另一台电脑上却生成两个文件 ...
- R in action读书笔记(3)-第六章:基本图形
第六章 基本图形 6.1条形图 条形图通过垂直的或水平的条形展示了类别型变量的分布(频数).函数:barplot(height) 6.1.1简单的条形图 6.1.2推砌条形图和分组条形图 如果hei ...
- 计算器Pro应用项目源码
本计算器实现了一些简单的功能,可能本身还存在一些缺陷,希望大家提建议,能够改进一下. 源码项目我已经上传到源码天堂那里了:http://code.662p.com/list/11_1.html < ...