您当前的位置:首页 > 电脑百科 > 程序开发 > 框架

手把手教你自定义自己SpringBoot Starter组件源码剖析

时间:2023-07-07 16:01:39  来源:今日头条  作者:架构师之道

我们知道SpringBoot Starter也就是启动器。是SpringBoot组件化的一大优点。基于这个思想,基于这个思想SpringBoot 才变得非常强大,官方给我们提供很多开箱即用的启动器。

Spring Boot Starter 是 Spring Boot 的一个重要特性,它有以下优点:

  1. 依赖管理:Starter 自动处理项目的依赖关系,使得开发者无需手动添加和管理每个依赖。
  2. 自动配置:Starter 提供了一种自动配置的方式,可以根据你的 classpath 和你定义的属性自动配置 Spring 应用。
  3. 简化开发:通过提供各种服务的 Starter(如数据库、安全、缓存等),极大地简化了开发过程。
  4. 减少样板代码:由于 Starter 的自动配置和依赖管理,开发者可以专注于业务逻辑,而不是配置和基础设施代码。
  5. 快速原型开发:使用 Starter 可以快速创建可运行的原型。
  6. 易于理解和使用:Spring Boot Starter 的设计目标之一就是让非专业的开发者也能快速上手。
  7. 社区支持:除了官方提供的 Starter,还有大量的社区提供的 Starter,可以满足各种特定需求。

我现在手把手教大家如何封装自己的starter 做自己的springboot组件,当然你也可以发布自己的starter 到maven中央仓库供大家使用

剖析SpringBoot自带Starter

我们以WebMvcAutoConfiguration这个自动加载为例

自动配置类要能加载,有一个要求,源码分析结果是,需要在META-INFspring.factories中做如下配置

JAVA复制代码# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,

这样SpringBoot在启动完成时候,会找到我们引入,的starter 找到META-INFspring.factories 属性文件,找到需要自动加载配置的类路径,然后帮我们自动注入到Spring IOC 容器,我们在项目中就可以直接使用了。

这里实现自动加载还要依赖一些注解如:

js复制代码@Configuration // 指定这个类是个配置类
@ConditionalOnXXX // 在指定条件成立的情况下自动配置类生效
@AutoConfigureOrder //配置类顺序
@AutoConfigureAfter // 在哪个配置类之后
@Bean //给容器中添加组件

@ConfigurationProperties //结合相关的XXXProperties类 来绑定相关的配置
@EnableConfigurationProperties // 让XXXProperties加入到容器中,别人就可以自动装配

自定义自己的starter

剖析了SpringBoot 官方的starter 我们自定义自己的starter,(我们仿照着写)

命名规范

 

配置提示

如果自定义属性文件中,需要IDEA智能提示需要引入

pom复制代码       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

定义starter

这里我以自己封装总结我工作以来总结项目封装的一个SpringBoot starter为例

java复制代码 <dependency>
            <groupId>cn.soboys</groupId>
            <artifactId>rest-api-spring-boot-starter</artifactId>
            <version>1.2.0</version>
        </dependency>

就是我自己封装的start。已经发布中央仓库。

目前更新版本1.3.0 功能如下

  1. 支持一键配置自定义RestFull API 统一格式返回
  2. 支持RestFull API 错误国际化
  3. 支持全局异常处理,全局参数验证处理
  4. 业务错误断言工具封装,遵循错误优先返回原则
  5. redis工作封装。支持所有key操作工具
  6. RestTemplate 封装 POST,GET 请求工具
  7. 日志集成。自定义日志路径,按照日志等级分类,支持压缩和文件大小分割。按时间显示
  8. 工具库集成 集成了lombok,hutool,commons-lang3,guava。不需要自己单个引入
  9. 集成MyBatisPlus一键代码生成


rest-api-spring-boot-starter 仓库地址 Github

  1. 自定义配置属性文件
yml复制代码rest-api:
  enabled: false
  logging:
    path: ./logs
  i18n:
    # 若前端无header传参则返回中文信息
    i18n-header: Lang
    default-lang: cn
    message:
      # admin
      internal_server_error:
        en: Internal Server Error
        cn: 系统错误
      not_found:
        en: Not Found
        cn: 请求资源不存在

  1. 定义属性配置类
java复制代码package cn.soboys.restapispringbootstarter.i18n;


import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;


import java.util.Map;
import java.util.Optional;

/**
 * @author 公众号 程序员三时
 * @version 1.0
 * @date 2023/6/26 11:55
 * @webSite https://github.com/coder-amiao
 */
//@PropertySource(value = "classpath:i18n.yaml", factory = YamlPropertySourceFactory.class)
@Configuration
@ConfigurationProperties(prefix = "rest-api.i18n")
@Data
public class I18NMessage {
    /**
     * message-key:<lang:message>
     */
    private Map<String, Map<String, String>> message;
    /**
     * Default language setting (Default "cn").
     */
    private String defaultLang = "cn";


    private String i18nHeader = "Lang";


    /**
     * get i18n message
     *
     * @param key
     * @param language
     * @return
     */
    public String message(I18NKey key, String language) {
        return Optional.ofNullable(message.get(key.key()))
                .map(map -> map.get(language == null ? defaultLang : language))
                .orElse(key.key());
    }

    /**
     * get i18n message
     *
     * @param key
     * @param language
     * @return
     */
    public String message(String key, String language) {
        return Optional.ofNullable(message.get(key))
                .map(map -> map.get(language == null ? defaultLang : language))
                .orElse(key);
    }

}

  1. 定义BeanAutoConfiguration自动加载配置类
java复制代码package cn.soboys.restapispringbootstarter.config;

import cn.soboys.restapispringbootstarter.ApplicationRunner;
import cn.soboys.restapispringbootstarter.ExceptionHandler;
import cn.soboys.restapispringbootstarter.ResultHandler;
import cn.soboys.restapispringbootstarter.aop.LimitAspect;
import cn.soboys.restapispringbootstarter.i18n.I18NMessage;
import cn.soboys.restapispringbootstarter.utils.RedisTempUtil;
import cn.soboys.restapispringbootstarter.utils.RestFulTemp;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.Charset;
import java.util.List;

/**
 * @author 公众号 程序员三时
 * @version 1.0
 * @date 2023/6/27 11:36
 * @webSite https://github.com/coder-amiao
 */
@Configuration
@ConditionalOnProperty(name = "rest-api.enabled", havingValue = "true")
public class BeanAutoConfiguration {


    @Bean
    public I18NMessage i18NMessage() {
        return new I18NMessage();
    }

    @Bean
    public ResultHandler resultHandler() {
        return new ResultHandler();
    }

    @Bean
    public ExceptionHandler exceptionHandler() {
        return new ExceptionHandler();
    }

    @Bean
    public StartupApplicationListener startupApplicationListener() {
        return new StartupApplicationListener();
    }


    @Bean
    public RestApiProperties restApiProperties() {
        return new RestApiProperties();
    }

    @Bean
    public RestApiProperties.LoggingProperties loggingProperties(RestApiProperties restApiProperties) {
        return restApiProperties.new LoggingProperties();
    }

    @Bean
    public ApplicationRunner applicationRunner() {
        return new ApplicationRunner();
    }




    /**
     * restTemplate 自动注入
     */
    @Configuration
    @ConditionalOnProperty(name = "rest-api.enabled", havingValue = "true")
    class RestTemplateConfig {
        /**
         * 第三方请求要求的默认编码
         */
        private final Charset thirdRequest = Charset.forName("utf-8");

        @Bean
        public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
            RestTemplate restTemplate = new RestTemplate(factory);
            // 处理请求中文乱码问题
            List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
            for (HttpMessageConverter<?> messageConverter : messageConverters) {
                if (messageConverter instanceof StringHttpMessageConverter) {
                    ((StringHttpMessageConverter) messageConverter).setDefaultCharset(thirdRequest);
                }
                if (messageConverter instanceof MappingJackson2HttpMessageConverter) {
                    ((MappingJackson2HttpMessageConverter) messageConverter).setDefaultCharset(thirdRequest);
                }
                if (messageConverter instanceof AllEncompassingFormHttpMessageConverter) {
                    ((AllEncompassingFormHttpMessageConverter) messageConverter).setCharset(thirdRequest);
                }
            }
            return restTemplate;
        }

        @Bean
        public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
            SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
            factory.setConnectTimeout(15000);
            factory.setReadTimeout(5000);
            return factory;
        }


        @Bean
        public RestFulTemp restFulTemp() {
            return new RestFulTemp();
        }

    }

}
  1. 自动装配 在项目

 

spring.factories 配置自己加载配置类

xml复制代码org.springframework.boot.autoconfigure.EnableAutoConfiguration=
cn.soboys.restapispringbootstarter.config.BeanAutoConfiguration,
cn.soboys.restapispringbootstarter.config.BeanAutoConfiguration.RestTemplateConfig,
cn.soboys.restapispringbootstarter.utils.RedisTempUtil

扩展思考,我们可以看到SpringBoot官方stater 很多启用都类似@Enablexxx注解 这个怎么实现。我的
rest-api-spring-boot-starter 1.3.0已经实现不需要在application.properties配置一行 直接在启动类或者配置类使用EnableRestFullApi就可以使用全部功能


作者:程序员三时
链接:
https://juejin.cn/post/7252712159561711674



Tags:SpringBoot   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
公司用了六年的 SpringBoot 项目部署方案,稳得一批!
本篇和大家分享的是springboot打包并结合shell脚本命令部署,重点在分享一个shell程序启动工具,希望能便利工作。 profiles指定不同环境的配置 maven-assembly-plugin打发布压...【详细内容】
2024-01-10  Search: SpringBoot  点击:(163)  评论:(0)  加入收藏
SpringBoot 中的热部署和热加载
在Spring Boot开发调试中,如果我们每修改一行代码都需要重启调试,可能会比较耗时。Spring Boot团队针对这个问题提供了spring-boot-devtools(简称:Devtools)插件,试图提高开发和调...【详细内容】
2023-11-06  Search: SpringBoot  点击:(250)  评论:(0)  加入收藏
SpringBoot 调用外部接口的四种方式
1、简介在Spring-Boot项目开发中,当本模块的代码需要访问外面模块接口,或外部url链接的需求的时候, 需要使用网络连接调用,下面提供了四种方式(排除dubbo的方式)供大家选择。方式...【详细内容】
2023-11-06  Search: SpringBoot  点击:(315)  评论:(0)  加入收藏
Springboot 框架中事件监听和发布机制详细介绍
事件监听和发布是Spring Framework中的一种机制,用于实现松散耦合的组件之间的通信。下面是事件监听和发布的详细过程:事件发布的过程: 创建事件对象:首先,您需要创建一个事件类,...【详细内容】
2023-11-02  Search: SpringBoot  点击:(264)  评论:(0)  加入收藏
Springboot 中的 PropertySource 管理配置属性的机制
Spring Framework 中的 PropertySource 是一种用于管理配置属性的机制,它允许你将配置信息从各种来源(如属性文件、环境变量、数据库等)加载到应用程序中。在 Spring 中,Propert...【详细内容】
2023-10-29  Search: SpringBoot  点击:(228)  评论:(0)  加入收藏
如何将本地jar文件打包到 springboot 执行jar文件中
这一系列课程将包含Spring Boot 许多关键的技术和工具,包括 Mybatis-Plus、Redis、Mongodb、MinIO、Kafka、MySQL、消息队列(MQ)、OAuth2 等相关内容。如何将本地jar文件打包到...【详细内容】
2023-10-27  Search: SpringBoot  点击:(271)  评论:(0)  加入收藏
Java面试题之SpringBoot 框架
谈谈怎么理解 SpringBoot 框架 Spring Boot 是 Spring 开源组织下的子项目, 是 Spring 组件一站式解决方案, 主要是 简化了使用 Spring 的难度, 简省了繁重的配置, 提供了各种启...【详细内容】
2023-09-28  Search: SpringBoot  点击:(212)  评论:(0)  加入收藏
SpringBoot 并发编程学习历程
本教程大概目录: 模拟单线程情节 用Callable实现 并发编程 用DeferedResult实现异步处理###模拟单线程情节。/** * Created by Fant.J. */@RestController@Slf4jpublic class...【详细内容】
2023-09-27  Search: SpringBoot  点击:(207)  评论:(0)  加入收藏
Springboot — 用更优雅的方式发HTTP请求(RestTemplate详解)
RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。我之前的HTTP开发是用apache的Htt...【详细内容】
2023-09-14  Search: SpringBoot  点击:(317)  评论:(0)  加入收藏
16个SpringBoot 扩展接口
1.背景Spring的核心思想就是容器,当容器refresh的时候,外部看上去风平浪静,其实内部则是一片惊涛骇浪,汪洋一片。Springboot更是封装了Spring,遵循约定大于配置,加上自动装配的机...【详细内容】
2023-08-28  Search: SpringBoot  点击:(134)  评论:(0)  加入收藏
▌简易百科推荐
Web Components实践:如何搭建一个框架无关的AI组件库
一、让人又爱又恨的Web ComponentsWeb Components是一种用于构建可重用的Web元素的技术。它允许开发者创建自定义的HTML元素,这些元素可以在不同的Web应用程序中重复使用,并且...【详细内容】
2024-04-03  京东云开发者    Tags:Web Components   点击:(8)  评论:(0)  加入收藏
Kubernetes 集群 CPU 使用率只有 13% :这下大家该知道如何省钱了
作者 | THE STACK译者 | 刘雅梦策划 | Tina根据 CAST AI 对 4000 个 Kubernetes 集群的分析,Kubernetes 集群通常只使用 13% 的 CPU 和平均 20% 的内存,这表明存在严重的过度...【详细内容】
2024-03-08  InfoQ    Tags:Kubernetes   点击:(12)  评论:(0)  加入收藏
Spring Security:保障应用安全的利器
SpringSecurity作为一个功能强大的安全框架,为Java应用程序提供了全面的安全保障,包括认证、授权、防护和集成等方面。本文将介绍SpringSecurity在这些方面的特性和优势,以及它...【详细内容】
2024-02-27  风舞凋零叶    Tags:Spring Security   点击:(54)  评论:(0)  加入收藏
五大跨平台桌面应用开发框架:Electron、Tauri、Flutter等
一、什么是跨平台桌面应用开发框架跨平台桌面应用开发框架是一种工具或框架,它允许开发者使用一种统一的代码库或语言来创建能够在多个操作系统上运行的桌面应用程序。传统上...【详细内容】
2024-02-26  贝格前端工场    Tags:框架   点击:(47)  评论:(0)  加入收藏
Spring Security权限控制框架使用指南
在常用的后台管理系统中,通常都会有访问权限控制的需求,用于限制不同人员对于接口的访问能力,如果用户不具备指定的权限,则不能访问某些接口。本文将用 waynboot-mall 项目举例...【详细内容】
2024-02-19  程序员wayn  微信公众号  Tags:Spring   点击:(39)  评论:(0)  加入收藏
开发者的Kubernetes懒人指南
你可以将本文作为开发者快速了解 Kubernetes 的指南。从基础知识到更高级的主题,如 Helm Chart,以及所有这些如何影响你作为开发者。译自Kubernetes for Lazy Developers。作...【详细内容】
2024-02-01  云云众生s  微信公众号  Tags:Kubernetes   点击:(50)  评论:(0)  加入收藏
链世界:一种简单而有效的人类行为Agent模型强化学习框架
强化学习是一种机器学习的方法,它通过让智能体(Agent)与环境交互,从而学习如何选择最优的行动来最大化累积的奖励。强化学习在许多领域都有广泛的应用,例如游戏、机器人、自动驾...【详细内容】
2024-01-30  大噬元兽  微信公众号  Tags:框架   点击:(68)  评论:(0)  加入收藏
Spring实现Kafka重试Topic,真的太香了
概述Kafka的强大功能之一是每个分区都有一个Consumer的偏移值。该偏移值是消费者将读取的下一条消息的值。可以自动或手动增加该值。如果我们由于错误而无法处理消息并想重...【详细内容】
2024-01-26  HELLO程序员  微信公众号  Tags:Spring   点击:(86)  评论:(0)  加入收藏
SpringBoot如何实现缓存预热?
缓存预热是指在 Spring Boot 项目启动时,预先将数据加载到缓存系统(如 Redis)中的一种机制。那么问题来了,在 Spring Boot 项目启动之后,在什么时候?在哪里可以将数据加载到缓存系...【详细内容】
2024-01-19   Java中文社群  微信公众号  Tags:SpringBoot   点击:(86)  评论:(0)  加入收藏
花 15 分钟把 Express.js 搞明白,全栈没有那么难
Express 是老牌的 Node.js 框架,以简单和轻量著称,几行代码就可以启动一个 HTTP 服务器。市面上主流的 Node.js 框架,如 Egg.js、Nest.js 等都与 Express 息息相关。Express 框...【详细内容】
2024-01-16  程序员成功  微信公众号  Tags:Express.js   点击:(88)  评论:(0)  加入收藏
站内最新
站内热门
站内头条