热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

如何手写一个SpringBootStarter

这篇文章主要介绍了如何手写一个SpringBootStarter,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下

何为 Starter ?

想必大家都使用过 SpringBoot,在 SpringBoot 项目中,使用最多的无非就是各种各样的 Starter 了。那何为 Starter 呢?你可以理解为一个可拔插式的插件(组件)。或者理解为场景启动器。

通过 Starter,能够简化以前繁杂的配置,无需过多的配置和依赖,它会帮你合并依赖,并且将其统一集成到一个 Starter 中,我们只需在 Maven 或 Gradle 中引入 Starter 依赖即可。SpringBoot 会自动扫描需要加载的信息并启动相应的默认配置。例如,如果你想使用 jdbc 插件,你只需引入 spring-boot-starter-jdbc 即可;如果你想使用 mongodb,你只需引入 spring-boot-starter-data-mongodb 依赖即可。

SpringBoot 官方提供了大量日常企业应用研发各种场景的 spring-boot-starter 依赖模块。这些依赖模块都遵循着约定成俗的默认配置,并允许我们根据自身情况调整这些配置。

总而言之,Starter 提供了以下功能:

  • 整合了模块需要的所有依赖,统一集合到 Starter 中。
  • 提供了默认配置,并允许我们调整这些默认配置。
  • 提供了自动配置类对模块内的 Bean 进行自动装配,注入 Spring 容器中。

Starter 命名规则

Spring 官方定义的 Starter 通常命名遵循的格式为 spring-boot-starter-{name},例如 spring-boot-starter-data-mongodb。Spring 官方建议,非官方 Starter 命名应遵循 {name}-spring-boot-starter 的格式,例如,myjson-spring-boot-starter。

自定义一个 Starter

了解了 Starter 的含义以及应用场景后,我们可以尝试手写一个 Starter,加深对它的了解以及能在实际工作中,开发出自己的 Starter,提高我们的开发效率。

可能有人会问 Starter 能干嘛呢?其实在我们的日常开发工作中,总有一些独立于业务系统之外的配置模块,它是可以在不同项目中进行复用的。如果在每个项目中都编写重复的模块代码,不仅浪费时间和人力,而且还和项目耦合。所以我们将这些可独立于业务代码之外的功能配置模块封装成一个 Starter,在需要用到此功能模块的项目中,只需要在其 pom.xml 文件中引用依赖即可,SpringBoot 帮我们完成自动装配,而且我们还可以在配置文件中调整 Starter 中默认的配置信息。

假设我们现在需要实现这样一个功能:

  1. 根据用户提供的 Java 对象,将其转换为 JSON 形式,并且在 JSON 字符串中添加指定的前辍和后辍。
  2. 用户可以动态改变前辍和后辍,即可在 yml 或 properties 配置文件中自定义。

举个栗子,假如用户输入下面这个类的对象 person:

public class Person {
 private String name;
 private int age;
 private String address;
 public Person(String name, int age, String address) {
  super();
  this.name = name;
  this.age = age;
  this.address = address;
 }
 // 省略get和set方法
}

Person person = new Person("Mr.nobody", 18, "拉斯维加斯");

并假设用户在 application.yml 配置文件中配置的前辍为 @,后辍为 %,则最终生成的字符串为:

@{"address":"拉斯维加斯","age":18,"name":"Mr.nobody"}%

首先新建一个 Maven 工程(当然也可以其他类型例如 Gradle 工程),在 pom.xml 文件中引入如下依赖。fastjson 依赖是我们业务用到将 Java 对象转换为 JSON 字符串;spring-boot-configuration-processor 依赖是可选的,加入此依赖主要是打包时,自动生成配置元信息文件 META-INF/spring-configuration-metadata.json,并放入到 jar 中。方便使用者了解到一些配置元信息。

<&#63;xml version="1.0" encoding="UTF-8"&#63;>

	4.0.0
	com.nobody
	myjson-spring-boot-starter
	0.0.1-SNAPSHOT
	myjson-spring-boot-starter
	Demo project for Spring Boot Starter
	
		1.8
	
	
		
			org.springframework.boot
			spring-boot-starter
			2.3.8.RELEASE
		
		
			org.springframework.boot
			spring-boot-configuration-processor
			2.3.8.RELEASE
			true
		
		
			com.alibaba
			fastjson
			1.2.73
		
		
			org.springframework.boot
			spring-boot-autoconfigure
			2.3.8.RELEASE
		
	

业务处理类,实现 Java 对象转换为带有指定前后缀的 JSON 字符串。

package com.nobody.myjson.service;

import com.alibaba.fastjson.JSON;

/**
 * @Description 业务处理类
 * @Author Mr.nobody
 * @Date 2021/2/27
 * @Version 1.0
 */
public class MyJsonService {
 // 前缀
 private String prefixName;
 // 后缀
 private String suffixName;

 /**
  * 将Java对象转为带有指定前后缀的JSON字符串
  * 
  * @param o 需要转换的Java对象
  * @return 转换后的字符串
  */
 public String objectToMyJson(Object o) {
  return prefixName + JSON.toJSONString(o) + suffixName;
 }

 public String getPrefixName() {
  return prefixName;
 }

 public void setPrefixName(String prefixName) {
  this.prefixName = prefixName;
 }

 public String getSuffixName() {
  return suffixName;
 }

 public void setSuffixName(String suffixName) {
  this.suffixName = suffixName;
 }
}
配置类,定义需要的配置信息和默认配置项,并指明关联配置文件的配置项前缀。它可以把相同前缀的配置信息通过配置项名称映射成实体类的属性中。

package com.nobody.myjson.config;

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

/**
 * @Description 配置类(类名一般为模块名+Properties) nobody.json为Starter使用者通过yml配置文件动态修改属性值的变量名前缀
 * @Author Mr.nobody
 * @Date 2021/2/27
 * @Version 1.0
 */
@ConfigurationProperties(prefix = "nobody.json")
public class MyJsonProperties {

 // Starter使用者没在配置文件中配置prefixName属性的值时的默认值
 public static final String DEFAULT_PREFIX_NAME = "@";

 // Starter使用者没在配置文件中配置suffixName属性的值时的默认值
 public static final String DEFAULT_SUFFIX_NAME = "@";

 private String prefixName = DEFAULT_PREFIX_NAME;

 private String suffixName = DEFAULT_SUFFIX_NAME;

 public String getPrefixName() {
  return prefixName;
 }

 public void setPrefixName(String prefixName) {
  this.prefixName = prefixName;
 }

 public String getSuffixName() {
  return suffixName;
 }

 public void setSuffixName(String suffixName) {
  this.suffixName = suffixName;
 }
}

自动装配类,使用 @Configuration 和 @Bean 来进行自动装配,注入 Spring 容器中。

package com.nobody.myjson.config;

import com.nobody.myjson.service.MyJsonService;
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;

/**
 * @Description 自动装配类
 * @Author Mr.nobody
 * @Date 2021/2/27
 * @Version 1.0
 */
@Configuration // 标识此类是配置类
@ConditionalOnClass(MyJsonService.class) // 表示只有指定的class在classpath上时才能被注册
@EnableConfigurationProperties(MyJsonProperties.class) // 激活@ConfigurationProperties
public class MyJsonConfiguration {

 private MyJsonProperties myJsonProperties;

 // 自动注入配置类
 public MyJsonConfiguration(MyJsonProperties myJsonProperties) {
  this.myJsOnProperties= myJsonProperties;
 }

 // 创建MyJsonService对象,注入到Spring容器中
 @Bean
 @ConditionalOnMissingBean(MyJsonService.class) // 当容器没有此bean时,才注册
 public MyJsonService myJsonService() {
  MyJsonService myJsOnService= new MyJsonService();
  myJsonService.setPrefixName(myJsonProperties.getPrefixName());
  myJsonService.setSuffixName(myJsonProperties.getSuffixName());
  return myJsonService;
 }
}

src/main/resources/META-INF目录下新建 spring.factories 文件,输入以下内容:

org.springframework.boot.autoconfigure.EnableAutoCOnfiguration=\
com.nobody.myjson.config.MyJsonConfiguration

SpringBoot 项目启动时,类加载器会从 META-INF / spring.factories 加载给定类型的工厂实现的完全限定类名。也就是说类加载器得到工程中所有 jar 包中的 META-INF/spring.factories 文件资源,从而得到了一些包括自动配置相关的类的集合,然后将它们实例化,放入 Spring 容器中。

最终项目结构如下:

在开发工具 IDEA 通过 Maven 的 install 命令进行构建打包。或者在项目的目录下,打开命令行窗口,使用mvn install命令进行构建打包。打包后,会在工程的 target 目录下生成一个 jar 包,并且在 maven 本地仓库也会生成相应的 jar 包。

使用自定义的 Starter

经过上面几个步骤,我们自定义的 Starter 就开发好了,以下是在其他工程进行引入使用。在需要引用此 Starter 的工程的 pom.xml 文件中引入此依赖。


 com.nobody
 myjson-spring-boot-starter
 0.0.1-SNAPSHOT

刷新依赖,就能在项目的依赖库中看到此依赖了。

展开,还能查看此 Starter 可以配置的属性项有哪些,如下:

然后在需要用到的类中进行注入使用即可。

package com.nobody.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.nobody.domain.Person;
import com.nobody.service.MyJsonService;

@RestController
@RequestMapping("demo")
public class DemoController {
 
 // 注入我们Starter中的服务类
 @Autowired
 private MyJsonService myJsonService;
 
 @GetMapping()
 public String test() {
  Person p = new Person("Mr.nobody", 18, "拉斯维加斯");
  // 调用服务方法
  return myJsonService.objectToMyJson(p);
 }
}

启动项目,在浏览器中访问此接口,得到如下结果:

如果我们在 application.yml 文件中添加以下配置信息,然后再访问接口的结果如下,也验证了我们可以自定义 Starter 中默认的配置项。

nobody: 
 json:
 prefixName: HH
 suffixName: KK

当我们引入此 Starter 时,SpringBoot 会自动装配,将实例化的 bean 放入 Spring 容器。但我们是否可控制 bean 要不要实例化并放入容器呢?答案是可以做到的。

我们只需要在自动装配类或者类内的方法,通过 @ConditionalOnXXX 注解就能控制。例如如下所示,使用 Starter 使用者在他的项目的配置文件中填写 nobody.json.enable 的值为 false,则就不会自动生成 MyJsonService 实例了。默认不填或者 nobody.json.enable 的值为 true 时,能自动生成 bean 放入容器。这样用户就能自己控制 bean 的实例化了。

// 创建MyJsonService对象,注入到Spring容器中
@Bean
@ConditionalOnProperty(name = "nobody.json.enable", matchIfMissing = true)
@ConditionalOnMissingBean(MyJsonService.class) // 当容器没有此bean时,才注册
public MyJsonService myJsonService() {
 MyJsonService myJsOnService= new MyJsonService();
 myJsonService.setPrefixName(myJsonProperties.getPrefixName());
 myJsonService.setSuffixName(myJsonProperties.getSuffixName());
 return myJsonService;
}

此演示项目已上传到Github,如有需要可自行下载,欢迎 Star 。

https://github.com/LucioChn/myjson-spring-boot-starter

以上就是如何手写一个Spring Boot Starter的详细内容,更多关于手写Spring Boot Starter的资料请关注其它相关文章!


推荐阅读
  • 本文探讨了在通过 API 端点调用时,使用猫鼬(Mongoose)的 findOne 方法总是返回 null 的问题,并提供了详细的解决方案和建议。 ... [详细]
  • 基于Node.js、Express、MongoDB和Socket.io的实时聊天应用开发
    本文详细介绍了使用Node.js、Express、MongoDB和Socket.io构建的实时聊天应用程序。涵盖项目结构、技术栈选择及关键依赖项的配置。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • Composer Registry Manager:PHP的源切换管理工具
    本文介绍了一个用于Composer的源切换管理工具——Composer Registry Manager。该项目旨在简化Composer包源的管理和切换,避免与常见的CRM系统混淆,并提供了详细的安装和使用指南。 ... [详细]
  • 本文详细介绍了Git分布式版本控制系统中远程仓库的概念和操作方法。通过具体案例,帮助读者更好地理解和掌握如何高效管理代码库。 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 探讨如何真正掌握Java EE,包括所需技能、工具和实践经验。资深软件教学总监李刚分享了对毕业生简历中常见问题的看法,并提供了详尽的标准。 ... [详细]
  • Startup 类配置服务和应用的请求管道。Startup类ASP.NETCore应用使用 Startup 类,按照约定命名为 Startup。 Startup 类:可选择性地包括 ... [详细]
  • 作为一名 Ember.js 新手,了解如何在路由和模型中正确加载 JSON 数据是至关重要的。本文将探讨两者之间的差异,并提供实用的建议。 ... [详细]
  • 本文将深入探讨如何在不依赖第三方库的情况下,使用 React 处理表单输入和验证。我们将介绍一种高效且灵活的方法,涵盖表单提交、输入验证及错误处理等关键功能。 ... [详细]
  • 本文详细介绍了在企业级项目中如何优化 Webpack 配置,特别是在 React 移动端项目中的最佳实践。涵盖资源压缩、代码分割、构建范围缩小、缓存机制以及性能优化等多个方面。 ... [详细]
  • 科研单位信息系统中的DevOps实践与优化
    本文探讨了某科研单位通过引入云原生平台实现DevOps开发和运维一体化,显著提升了项目交付效率和产品质量。详细介绍了如何在实际项目中应用DevOps理念,解决了传统开发模式下的诸多痛点。 ... [详细]
  • 本文详细介绍了 Flink 和 YARN 的交互机制。YARN 是 Hadoop 生态系统中的资源管理组件,类似于 Spark on YARN 的配置方式。我们将基于官方文档,深入探讨如何在 YARN 上部署和运行 Flink 任务。 ... [详细]
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • 本文详细介绍了如何使用Spring Boot进行高效开发,涵盖了配置、实例化容器以及核心注解的使用方法。 ... [详细]
author-avatar
哗锅_348
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有