如何手写一个Spring Boot Starter
何为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中默认的配置信息。
假设我们现在需要实现这样一个功能:
- 根据用户提供的Java对象,将其转换为JSON形式,并且在JSON字符串中添加指定的前辍和后辍。
- 用户可以动态改变前辍和后辍,即可在yml或properties配置文件中自定义。
举个栗子,假如用户输入下面这个类的对象person:
publicclassPerson{ privateStringname; privateintage; privateStringaddress; publicPerson(Stringname,intage,Stringaddress){ super(); this.name=name; this.age=age; this.address=address; } //省略get和set方法 }
Personperson=newPerson("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中。方便使用者了解到一些配置元信息。
4.0.0 com.nobody myjson-spring-boot-starter 0.0.1-SNAPSHOT myjson-spring-boot-starter DemoprojectforSpringBootStarter 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字符串。
packagecom.nobody.myjson.service; importcom.alibaba.fastjson.JSON; /** *@Description业务处理类 *@AuthorMr.nobody *@Date2021/2/27 *@Version1.0 */ publicclassMyJsonService{ //前缀 privateStringprefixName; //后缀 privateStringsuffixName; /** *将Java对象转为带有指定前后缀的JSON字符串 * *@paramo需要转换的Java对象 *@return转换后的字符串 */ publicStringobjectToMyJson(Objecto){ returnprefixName+JSON.toJSONString(o)+suffixName; } publicStringgetPrefixName(){ returnprefixName; } publicvoidsetPrefixName(StringprefixName){ this.prefixName=prefixName; } publicStringgetSuffixName(){ returnsuffixName; } publicvoidsetSuffixName(StringsuffixName){ this.suffixName=suffixName; } } 配置类,定义需要的配置信息和默认配置项,并指明关联配置文件的配置项前缀。它可以把相同前缀的配置信息通过配置项名称映射成实体类的属性中。 packagecom.nobody.myjson.config; importorg.springframework.boot.context.properties.ConfigurationProperties; /** *@Description配置类(类名一般为模块名+Properties)nobody.json为Starter使用者通过yml配置文件动态修改属性值的变量名前缀 *@AuthorMr.nobody *@Date2021/2/27 *@Version1.0 */ @ConfigurationProperties(prefix="nobody.json") publicclassMyJsonProperties{ //Starter使用者没在配置文件中配置prefixName属性的值时的默认值 publicstaticfinalStringDEFAULT_PREFIX_NAME="@"; //Starter使用者没在配置文件中配置suffixName属性的值时的默认值 publicstaticfinalStringDEFAULT_SUFFIX_NAME="@"; privateStringprefixName=DEFAULT_PREFIX_NAME; privateStringsuffixName=DEFAULT_SUFFIX_NAME; publicStringgetPrefixName(){ returnprefixName; } publicvoidsetPrefixName(StringprefixName){ this.prefixName=prefixName; } publicStringgetSuffixName(){ returnsuffixName; } publicvoidsetSuffixName(StringsuffixName){ this.suffixName=suffixName; } }
自动装配类,使用@Configuration和@Bean来进行自动装配,注入Spring容器中。
packagecom.nobody.myjson.config; importcom.nobody.myjson.service.MyJsonService; importorg.springframework.boot.autoconfigure.condition.ConditionalOnClass; importorg.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; importorg.springframework.boot.context.properties.EnableConfigurationProperties; importorg.springframework.context.annotation.Bean; importorg.springframework.context.annotation.Configuration; /** *@Description自动装配类 *@AuthorMr.nobody *@Date2021/2/27 *@Version1.0 */ @Configuration//标识此类是配置类 @ConditionalOnClass(MyJsonService.class)//表示只有指定的class在classpath上时才能被注册 @EnableConfigurationProperties(MyJsonProperties.class)//激活@ConfigurationProperties publicclassMyJsonConfiguration{ privateMyJsonPropertiesmyJsonProperties; //自动注入配置类 publicMyJsonConfiguration(MyJsonPropertiesmyJsonProperties){ this.myJsonProperties=myJsonProperties; } //创建MyJsonService对象,注入到Spring容器中 @Bean @ConditionalOnMissingBean(MyJsonService.class)//当容器没有此bean时,才注册 publicMyJsonServicemyJsonService(){ MyJsonServicemyJsonService=newMyJsonService(); myJsonService.setPrefixName(myJsonProperties.getPrefixName()); myJsonService.setSuffixName(myJsonProperties.getSuffixName()); returnmyJsonService; } }
在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命令进行构建打包。或者在项目的目录下,打开命令行窗口,使用mvninstall命令进行构建打包。打包后,会在工程的target目录下生成一个jar包,并且在maven本地仓库也会生成相应的jar包。
使用自定义的Starter
经过上面几个步骤,我们自定义的Starter就开发好了,以下是在其他工程进行引入使用。在需要引用此Starter的工程的pom.xml文件中引入此依赖。
com.nobody myjson-spring-boot-starter 0.0.1-SNAPSHOT
刷新依赖,就能在项目的依赖库中看到此依赖了。
展开,还能查看此Starter可以配置的属性项有哪些,如下:
然后在需要用到的类中进行注入使用即可。
packagecom.nobody.controller; importorg.springframework.beans.factory.annotation.Autowired; importorg.springframework.web.bind.annotation.GetMapping; importorg.springframework.web.bind.annotation.RequestMapping; importorg.springframework.web.bind.annotation.RestController; importcom.nobody.domain.Person; importcom.nobody.service.MyJsonService; @RestController @RequestMapping("demo") publicclassDemoController{ //注入我们Starter中的服务类 @Autowired privateMyJsonServicemyJsonService; @GetMapping() publicStringtest(){ Personp=newPerson("Mr.nobody",18,"拉斯维加斯"); //调用服务方法 returnmyJsonService.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时,才注册 publicMyJsonServicemyJsonService(){ MyJsonServicemyJsonService=newMyJsonService(); myJsonService.setPrefixName(myJsonProperties.getPrefixName()); myJsonService.setSuffixName(myJsonProperties.getSuffixName()); returnmyJsonService; }
此演示项目已上传到Github,如有需要可自行下载,欢迎Star。
https://github.com/LucioChn/myjson-spring-boot-starter
以上就是如何手写一个SpringBootStarter的详细内容,更多关于手写SpringBootStarter的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。