手撸一个SpringBoot-Starter
1. 简介
通过了解SpringBoot的原理后,我们可以手撸一个spring-boot-starter来加深理解。
1.1 什么是starter
- starters是一组方便的依赖描述符(根据功能特点将用到的依赖标记封装到同一个pom中),可以将其包含在应用程序中。
- 通过starters可以获取所需的所有Spring和相关技术的一站式服务,而无需搜索示例代码或复制粘贴加载的依赖项描述符。
1.2 命名规则
所有官方首发都遵循类似的命名模式:spring-boot-starter-*
,其中*
是特定类型的应用程序,例如: spring-boot-starter-web
。
第三方启动器不应以spring-boot
开头,因为它是为官方 Spring Boot 工件保留的,相反çç第三方启动器通常以项目名称开头,例如:ldx.spring-boot-starter
。
1.3 代码结构
如图,官方的spring-boot-starter Jar中其实没有包含代码,starter其实是就是一组依赖描述的集合,而其中主要包含的就是autoconfigure模块和一些必要的依赖模块。
spring-boot官方所有的auto-configuration-classes
springboot官方的starter中依赖如下:
当我们进入到官方autoconfiguration中查看redis配置源码如下,而我们待会儿也会模仿RedisAutoConfiguration
写一个自己的starter
2. 开撸
2.1 项目结构
结构说明:
├── redis-spring-boot-starter # 自定义的starter模块
│ ├── pom.xml
├── spring-boot-autoconfigure # 自定义的auto configure模块
│ ├── pom.xml
│ └── src
│ └── main
│ ├── java
│ │ └── com
│ │ └── ldx
│ │ └── autoconfigure
│ │ └── config
│ │ ├── RedisAutoConfiguration.java # redis 自动配置类
│ │ └── RedisProperty.java # redis property 参数绑定类
│ └── resources
│ └── META-INF
│ └── spring.factories # spring自动装配配置文件
└── test # 功能测试模块
├── pom.xml
├── src
│ └── main
│ ├── java
│ │ └── com
│ │ └── ldx
│ │ └── test
│ │ └── TestApplication.java # 启动类
│ └── resources
│ └── application.yaml # 资源文件
2.2 spring-boot-autoconfigure
正如简介中提到的一样,该模块用于提供autoconfigure核心功能,通过META-INF/spring.factories
实现对RedisAutoConfiguration.class
的扫描,然后在RedisAutoConfiguration.class
中实现Jedis
的条件化注入,从而实现springboot的自动装配功能。
2.2.1 导入依赖
spring-boot-autoconfigure-processor
是一个注释处理器,依赖用于生成META-INF/spring-autoconfigure-metadata.properties
并且被包含在项目 jar 中,其文件记录了当前classpath下所有的autoconfigure的元信息,在项目启动时会先扫描此文件(如果存在),此文件有助于缩短启动时间,但不是程序正常运行所必需的。
<?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 https://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.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ldx</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-autoconfigure</name>
<description>自定义的 spring-boot-autoconfigure</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--引入redis客户端 jedis依赖-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<!-- 防止当前依赖被传递引用 -->
<optional>true</optional>
</dependency>
<!--自动配置注解注释处理器,
用于生成META-INF/spring-autoconfigure-metadata.properties包含在项目中-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
2.2.2 RedisProperty
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* redis 属性注入类
*
* @author ludangxin
* @date 2021/8/1
*/
@Data
// 用于读取配置文件中的链接信息
@ConfigurationProperties(prefix = "redis")
public class RedisProperty {
private String host = "localhost";
private int port = 6379;
}
2.2.3 RedisAutoConfiguration
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 redis.clients.jedis.Jedis;
/**
* redis 自动化配置类
*
* @author ludangxin
* @date 2021/8/1
*/
@ConditionalOnClass(Jedis.class)
@EnableConfigurationProperties(RedisProperty.class)
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(Jedis.class)
public Jedis jedis(RedisProperty redisProperty) {
return new Jedis(redisProperty.getHost(), redisProperty.getPort());
}
}
2.2.4 spring.factories
在resources
下创建META-INF/spring.factories
,EnableAutoConfiguration
指向RedisAutoConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration = \
com.ldx.autoconfigure.config.RedisAutoConfiguration
2.2.5 安装依赖
将当前模块打成Jar安装到本地仓库。
2.3 redis-spring-boot-starter
2.3.1 导入依赖
在其pom中添加我们刚才创建的spring-boot-autoconfigure
模块,并且添加jedis
模块(autoconfigure模块中jedis不允许传递依赖因为将来autoconfigure文件中的会有各种各样的第三方自动化配置,不可能全部传递依赖,只能是用到哪个的时候就自行在starter中添加哪个即可)
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ldx</groupId>
<artifactId>redis-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>redis-spring-boot-starter</name>
<description>customize starter</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--引用自己创建的spring-boot-autoconfigure model-->
<dependency>
<groupId>com.ldx</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- 引用jedis客户端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.6.3</version>
</dependency>
</dependencies>
</project>
2.3.2 安装依赖
将当前模块打成Jar安装到本地仓库。
2.4 test
test模块为测试模块,测试starter功能。
2.4.1 导入依赖
<?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 https://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.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ldx</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>test</name>
<description>测试springboot-starter</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 引用自己创建的redis-starter -->
<dependency>
<groupId>com.ldx</groupId>
<artifactId>redis-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.4.2 修改启动类
package com.ldx.test;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import redis.clients.jedis.Jedis;
@Slf4j
@SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(TestApplication.class, args);
// 获取jedis bean
Jedis jedis = applicationContext.getBean(Jedis.class);
// add
jedis.set("name", "张三");
log.info(jedis.get("name"));
}
}
2.4.3 启动测试
启动项目成功获取到了设置的数据。
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.3)
2021-08-03 23:08:44.531 INFO 13930 --- [ main] com.ldx.test.TestApplication : Starting TestApplication using Java 1.8.0_261 on ludangxindeMacBook-Pro.local with PID 13930 (/Users/ludangxin/workspace/idea/redis-starter/test/target/classes started by ludangxin in /Users/ludangxin/workspace/idea/redis-starter)
2021-08-03 23:08:44.532 INFO 13930 --- [ main] com.ldx.test.TestApplication : No active profile set, falling back to default profiles: default
2021-08-03 23:08:45.062 INFO 13930 --- [ main] com.ldx.test.TestApplication : Started TestApplication in 0.901 seconds (JVM running for 1.384)
2021-08-03 23:08:45.072 INFO 13930 --- [ main] com.ldx.test.TestApplication : 张三
这时我们在test模块的application.yaml
文配置redis.port=123
测试autoconfigure模块能不能正常的获取配置信息。
启动项目报错如下:
说明配置类正确的获取到了错误的配置信息,符合预期,打完收工。
这时我们再回头看下spring-boot-autoconfigure-processor
依赖生产的元信息文件如下:
3. 小结
spring-boot-starter
的出现,大大的提升了我们项目的搭建速度和质量(我们仅需导入依赖坐标,然后在配置文件中进行简单的配置即可。再也不用因为依赖找不全,版本对不上,依赖冲突...而烦恼了),并且官方和第三方的starter简化了我们对中间操作(提供了通用的template,整合了对数据库比如jpa或者amqp等操作接口),简直不要太爽。
当我们学习了如何创建自己的starter后,也可以封装我们自己的starter用于项目的建设和使用。
SpringBoot内置Starter
名称 | 描述 |
---|---|
spring-boot-starter |
核心启动器,包括自动配置支持、日志记录和 YAML |
spring-boot-starter-activemq |
使用 Apache ActiveMQ 的 JMS 消息传递入门 |
spring-boot-starter-amqp |
使用 Spring AMQP 和 Rabbit MQ 的入门者 |
spring-boot-starter-aop |
使用 Spring AOP 和 AspectJ 进行面向方面编程的入门者 |
spring-boot-starter-artemis |
使用 Apache Artemis 进行 JMS 消息传递的入门者 |
spring-boot-starter-batch |
使用 Spring Batch 的启动器 |
spring-boot-starter-cache |
使用 Spring Framework 的缓存支持的 Starter |
spring-boot-starter-data-cassandra |
Starter 使用 Cassandra 分布式数据库和 Spring Data Cassandra |
spring-boot-starter-data-cassandra-reactive |
Starter 使用 Cassandra 分布式数据库和 Spring Data Cassandra Reactive |
spring-boot-starter-data-couchbase |
使用 Couchbase 面向文档的数据库和 Spring Data Couchbase 的入门者 |
spring-boot-starter-data-couchbase-reactive |
Starter 使用 Couchbase 面向文档的数据库和 Spring Data Couchbase Reactive |
spring-boot-starter-data-elasticsearch |
使用 Elasticsearch 搜索和分析引擎以及 Spring Data Elasticsearch 的入门者 |
spring-boot-starter-data-jdbc |
使用 Spring Data JDBC 的入门者 |
spring-boot-starter-data-jpa |
将 Spring Data JPA 与 Hibernate 结合使用的入门者 |
spring-boot-starter-data-ldap |
使用 Spring Data LDAP 的入门者 |
spring-boot-starter-data-mongodb |
使用 MongoDB 面向文档的数据库和 Spring Data MongoDB 的入门者 |
spring-boot-starter-data-mongodb-reactive |
Starter 使用 MongoDB 面向文档的数据库和 Spring Data MongoDB Reactive |
spring-boot-starter-data-neo4j |
使用 Neo4j 图形数据库和 Spring Data Neo4j 的入门者 |
spring-boot-starter-data-r2dbc |
使用 Spring Data R2DBC 的启动器 |
spring-boot-starter-data-redis |
将 Redis 键值数据存储与 Spring Data Redis 和 Lettuce 客户端一起使用的入门者 |
spring-boot-starter-data-redis-reactive |
将 Redis 键值数据存储与 Spring Data Redis 反应式和 Lettuce 客户端一起使用的入门者 |
spring-boot-starter-data-rest |
使用 Spring Data REST 在 REST 上公开 Spring Data 存储库的启动器 |
spring-boot-starter-freemarker |
使用 FreeMarker 视图构建 MVC Web 应用程序的入门者 |
spring-boot-starter-groovy-templates |
使用 Groovy 模板视图构建 MVC Web 应用程序的入门者 |
spring-boot-starter-hateoas |
使用 Spring MVC 和 Spring HATEOAS 构建基于超媒体的 RESTful Web 应用程序的入门者 |
spring-boot-starter-integration |
使用 Spring Integration 的入门者 |
spring-boot-starter-jdbc |
将 JDBC 与 HikariCP 连接池一起使用的 Starter |
spring-boot-starter-jersey |
使用 JAX-RS 和 Jersey 构建 RESTful Web 应用程序的初学者。替代方案spring-boot-starter-web |
spring-boot-starter-jooq |
使用 jOOQ 访问 SQL 数据库的入门者。spring-boot-starter-data-jpa或的替代品spring-boot-starter-jdbc |
spring-boot-starter-json |
读写json的Starter |
spring-boot-starter-jta-atomikos |
使用 Atomikos 的 JTA 事务入门 |
spring-boot-starter-mail |
使用 Java Mail 的 Starter 和 Spring Framework 的电子邮件发送支持 |
spring-boot-starter-mustache |
使用 Mustache 视图构建 Web 应用程序的入门者 |
spring-boot-starter-oauth2-client |
使用 Spring Security 的 OAuth2/OpenID Connect 客户端功能的入门者 |
spring-boot-starter-oauth2-resource-server |
使用 Spring Security 的 OAuth2 资源服务器功能的入门者 |
spring-boot-starter-quartz |
使用 Quartz 调度器的启动器 |
spring-boot-starter-rsocket |
用于构建 RSocket 客户端和服务器的 Starter |
spring-boot-starter-security |
使用 Spring Security 的入门者 |
spring-boot-starter-test |
Starter 用于使用包括 JUnit Jupiter、Hamcrest 和 Mockito 在内的库测试 Spring Boot 应用程序 |
spring-boot-starter-thymeleaf |
使用 Thymeleaf 视图构建 MVC Web 应用程序的初学者 |
spring-boot-starter-validation |
将 Java Bean 验证与 Hibernate Validator 结合使用的入门工具 |
spring-boot-starter-web |
使用 Spring MVC 构建 Web(包括 RESTful)应用程序的入门者。使用 Tomcat 作为默认的嵌入式容器 |
spring-boot-starter-web-services |
使用 Spring Web 服务的入门者 |
spring-boot-starter-webflux |
使用 Spring Framework 的 Reactive Web 支持构建 WebFlux 应用程序的 Starter |
spring-boot-starter-websocket |
使用 Spring Framework 的 WebSocket 支持构建 WebSocket 应用程序的 Starter |
除了应用程序启动器之外,以下启动器还可用于添加生产就绪功能:
名称 | 描述 |
---|---|
spring-boot-starter-actuator |
使用 Spring Boot 的 Actuator 的 Starter,它提供了生产就绪的特性来帮助你监控和管理你的应用程序 |
最后,Spring Boot 还包括以下启动器,如果您想排除或交换特定的技术方面,可以使用它们:
名称 | 描述 |
---|---|
spring-boot-starter-jetty |
使用 Jetty 作为嵌入式 servlet 容器的启动器。替代方案spring-boot-starter-tomcat |
spring-boot-starter-log4j2 |
使用 Log4j2 进行日志记录的启动器。替代方案spring-boot-starter-logging |
spring-boot-starter-logging |
使用 Logback 进行日志记录的启动器。默认日志记录启动器 |
spring-boot-starter-reactor-netty |
使用 Reactor Netty 作为嵌入式响应式 HTTP 服务器的启动器。 |
spring-boot-starter-tomcat |
使用 Tomcat 作为嵌入式 servlet 容器的启动器。使用的默认 servlet 容器启动器spring-boot-starter-web |
spring-boot-starter-undertow |
使用 Undertow 作为嵌入式 servlet 容器的启动器。替代方案spring-boot-starter-tomcat |
手撸一个SpringBoot-Starter的更多相关文章
- 手撸一个SpringBoot的Starter,简单易上手
前言:今天介绍一SpringBoot的Starter,并手写一个自己的Starter,在SpringBoot项目中,有各种的Starter提供给开发者使用,Starter则提供各种API,这样使开发S ...
- 手写一个springboot starter
springboot的starter的作用就是自动装配.将配置类自动装配好放入ioc容器里.作为一个组件,提供给springboot的程序使用. 今天手写一个starter.功能很简单,调用start ...
- 从头带你撸一个Springboot Starter
我们知道 SpringBoot 提供了很多的 Starter 用于引用各种封装好的功能: 名称 功能 spring-boot-starter-web 支持 Web 开发,包括 Tomcat 和 spr ...
- 看了 Spring 官网脚手架真香,也撸一个 SpringBoot DDD 微服务的脚手架!
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 为什么我们要去造轮子? 造轮子的核心目的,是为了解决通用共性问题的凝练和复用. 虽然 ...
- 手撸一个springsecurity,了解一下security原理
手撸一个springsecurity,了解一下security原理 转载自:www.javaman.cn 手撸一个springsecurity,了解一下security原理 今天手撸一个简易版本的sp ...
- 使用Java Socket手撸一个http服务器
原文连接:使用Java Socket手撸一个http服务器 作为一个java后端,提供http服务可以说是基本技能之一了,但是你真的了解http协议么?你知道知道如何手撸一个http服务器么?tomc ...
- 【手撸一个ORM】MyOrm的使用说明
[手撸一个ORM]第一步.约定和实体描述 [手撸一个ORM]第二步.封装实体描述和实体属性描述 [手撸一个ORM]第三步.SQL语句构造器和SqlParameter封装 [手撸一个ORM]第四步.Ex ...
- 第二篇-用Flutter手撸一个抖音国内版,看看有多炫
前言 继上一篇使用Flutter开发的抖音国际版 后再次撸一个国内版抖音,大部分功能已完成,主要是Flutter开发APP速度很爽, 先看下图 项目主要结构介绍 这次主要的改动在api.dart 及 ...
- 通过 Netty、ZooKeeper 手撸一个 RPC 服务
说明 项目链接 微服务框架都包括什么? 如何实现 RPC 远程调用? 开源 RPC 框架 限定语言 跨语言 RPC 框架 本地 Docker 搭建 ZooKeeper 下载镜像 启动容器 查看容器日志 ...
随机推荐
- Unity 添加,修改默认创建脚本模板
Unity 默认创建的脚本可以添加也可以修改,不需要修改Editor. 一.找到模板目录 \Editor\Data\Resources\ScriptTemplates 二.如果要修改模板,直接打开修改 ...
- 解决CentOS下service 功能 不能使用 bash: service: command not found
首先检查自己是否 使用的是root用户 在centos系统中,如果/sbin目录下没有service这个命令,就会出现 bash: service: command not found 解决步骤如下: ...
- 99、centos下安装teamviewer
99.1.teamviewer简介: TeamViewer是一个能在任何防火墙和NAT代理的后台用于远程控制的应用程序,桌面共享和文件传输的简单且快速的解决方案. 为了连接到另一台计算机,只需要在两台 ...
- Camunda工作流引擎简单入门
官网:https://camunda.com/ 官方文档:https://docs.camunda.org/get-started/spring-boot/project-setup/ 阅读新体验:h ...
- Reactive Spring实战 -- 响应式MySql交互
本文与大家探讨Spring中如何实现MySql响应式交互. Spring Data R2DBC项目是Spring提供的数据库响应式编程框架. R2DBC是Reactive Relational Dat ...
- php混淆加密解密实战
在查看别人的php源码的时候,我们经常会看到加密后的php代码.那么php加密原理是什么呢?怎么解密呢? 混淆加密 我们从百度随便搜索一个加密网站,例如:http://dezend.qiling.or ...
- linux学习之路第三天(vim和vi使用)
vi和vim编辑器 vi和vim的三种常见模式 1.正常模式 在正常模式下,我们可以使用快捷键 以vim打开一个档案就直接进入一般模式了(这是默认的模式).在这个模式中,你可以使用 上下左右按键来移动 ...
- linux学习之路第五天(文件目录类第一部分)
文件目录类 pwd 指令 基本语法 pwd (显示当前目录的绝对路径) Ls 指令 cd 指令 -代表的是上一级目录 mkdir指令 用于创建目录 基本语法 mkdir [选项] 要创建的目录 常用选 ...
- IDA 动态调试
感谢南邮,让我把ida动态调试,给搞定了,困扰了很久,之前下的ubuntu的源,好像有问题,ifconfig这个命令一直装不上,突然想起来了我的服务器很久没用了,重装了下系统,换成ubuntu,这里记 ...
- 官宣.NET 6 预览版4
我们很高兴发布 .NET 6 Preview 4.我们现在大约完成了 .NET 6 发布的一半.现在是一个很好的时机,可以再次查看.NET6的完整范围.许多功能都接近最终形式,而其他功能将很快推出,因 ...