如何实现自定义SpringBoot的Starter组件

目录
  • 一、前言
    • 1.1、starter加载原理
      • 1.1.1、加载starter
  • 二、自定义starter
    • 2.1、代码
      • 2.1.1、新建springboot项目。
      • 2.1.2、项目构建完成后,在resources文件夹下面新建META-INF文件夹,并新建spring.factories文件。
      • 2.1.3、因为我们是作为插件来使用,所以我们不需要启动类,删除启动类。并新建几个类:
  • 三、组件集成依赖测试
    • 3.1、新启另一个项目中,引入刚刚打包的pom依赖
    • 3.2、新建一个controller,里面注入上面提供的AnimalService类并调用其方法
    • 3.3、application.properties内容配置参数"animal.name"值
    • 3.4、最后通过项目启动类启动项目(项目启动类就一个@SpringBootApplicaiton注解)
    • 3.5、接口测试
  • 四、源码地址,参考资料

一、前言

想要自定义starter组件,首先要了解springboot是如何加载starter的,也就是springboot的自动装配机制原理。

1.1、starter加载原理

springboot通过一个@SpringBootApplication注解启动项目,springboot在项目启动的时候,会将项目中所有声明为Bean对象(注解、xml)的实例信息全部加载到ioc容器当中。 除此之外也会将所有依赖到的starter里的bean信息加载到ioc容器中,从而做到所谓的零配置,开箱即用。

1.1.1、加载starter

首先通过通过注解@SpringBootApplication找到@EnableAutoConfiguration注解进行加载starter。

再通过注解@EnableAutoConfiguration下注解@import找到AutoConfigurationImportSelector类加载器实现。

这个AutoConfigurationImportSelector类会去其引用的依赖jar包下,找到一个”spring.factories”文件,一般spring.factories文件里都会声明该依赖所提供的核心功能bean配置信息。文件一般在依赖jar包的META-INF文件夹下面。

以spring-boot版本2.7.7为例,加载spring.factories的代码在:

AutoConfigurationImportSelector.java->selectImports(AnnotationMetadata annotationMetadata)->getAutoConfigurationEntry(annotationMetadata)->getCandidateConfigurations(annotationMetadata, attributes)->SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader())->loadSpringFactories(classLoaderToUse):

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
        Map<String, List<String>> result = (Map)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            HashMap result = new HashMap();

            try {
                Enumeration urls = classLoader.getResources("META-INF/spring.factories");

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryTypeName = ((String)entry.getKey()).trim();
                        String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        String[] var10 = factoryImplementationNames;
                        int var11 = factoryImplementationNames.length;

                        for(int var12 = 0; var12 < var11; ++var12) {
                            String factoryImplementationName = var10[var12];
                            ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
                                return new ArrayList();
                            })).add(factoryImplementationName.trim());
                        }
                    }
                }

                result.replaceAll((factoryType, implementations) -> {
                    return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
                });
                cache.put(classLoader, result);
                return result;
            } catch (IOException var14) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
            }
        }
    }

举例如:spring-boot-autoconfig的spring.factories.

二、自定义starter

上面了解了springboot加载starter原理,其实就是加载依赖jar包下的spring.factories文件。所以我们要自定义starter,就需要在项目中建立一个META-INF的文件夹,然后在该文件夹下面建一个spring.factories文件,文件里将你需要提供出去的bean实例信息配置好就行。

2.1、代码

2.1.1、新建springboot项目。

简单演示所以需求配置任务依赖。如springboot构建很慢,或者打包的时候下载依赖很慢,可在pom文件中添加如下仓库配置,可以加快构建速度。

 <repositories>
        <repository>
            <id>alimaven</id>
            <url>https://maven.aliyun.com/repository/public</url>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>alimaven</id>
            <url>https://maven.aliyun.com/repository/public</url>
        </pluginRepository>
    </pluginRepositories>

注意:spring官方规定自定义组件的命名:

SpringBoot官方命名方式
格式:spring-boot-starter-{模块名}
举例:spring-boot-starter-web
自定义命名方式
格式:{模块名}-spring-boot-starter
举例:mystarter-spring-boot-starter

2.1.2、项目构建完成后,在resources文件夹下面新建META-INF文件夹,并新建spring.factories文件。

2.1.3、因为我们是作为插件来使用,所以我们不需要启动类,删除启动类。并新建几个类:

一个接口AnimalService:

package com.example.demospringbootstarter.service;

/**
 * @Project: demo-spring-boot-starter
 * @Description:
 * @Author: chengjiangbo
 * @Date: 2023/2/7  15:12
 */
public interface AnimalService {

    String say();
}

两个接口实现类CatService和DogService:

package com.example.demospringbootstarter.service;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Service;

/**
 * @Project: demo-spring-boot-starter
 * @Description:
 * @Author: chengjiangbo
 * @Date: 2023/2/7  14:49
 */
@Service
public class CatService implements AnimalService{

    public static String name = "cat";

    @Override
    public String say() {
        return "喵喵";
    }
}
package com.example.demospringbootstarter.service;

import org.springframework.stereotype.Service;

/**
 * @Project: demo-spring-boot-starter
 * @Description:
 * @Author: chengjiangbo
 * @Date: 2023/2/7  14:49
 */
@Service
public class DogService implements AnimalService{

    public static String name = "dog";

    @Override
    public String say() {
        return "汪汪";
    }
}

再建一个配置AnimalProperties类,方便注入属性值:

package com.example.demospringbootstarter.config;

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

/**
 * @Project: demo-spring-boot-starter
 * @Description:
 * @Author: chengjiangbo
 * @Date: 2023/2/7  15:37
 */
@Data
@ConfigurationProperties(prefix = "animal")
public class AnimalProperties {

    private String name;
}

最后新建一个核心自动装备配置类:

package com.example.demospringbootstarter.config;

import com.example.demospringbootstarter.service.AnimalService;
import com.example.demospringbootstarter.service.CatService;
import com.example.demospringbootstarter.service.DogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Project: demo-spring-boot-starter
 * @Description:
 * @Author: chengjiangbo
 * @Date: 2023/2/7  14:48
 */
@Configuration
@EnableConfigurationProperties(AnimalProperties.class)
public class AnimalAutoConfig {

    @Autowired
    private AnimalProperties animalProperties;

    @Bean
    public AnimalService demoService(){
        switch (animalProperties.getName()){
            case "cat":
                return new CatService();
            case "dog":
                return new DogService();
            default:
                return null;
        }
    }
}

META-INF/spring.factories的内容为:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.example.demospringbootstarter.config.AnimalAutoConfig

以上步骤都好后,使用maven命令打包:

mvn clean install -Dmaven.test.skip=true

或者使用idea的LIfecycle点击对应操作(注意不是plugin下的命令操作)。

pom.xml内容为:

<?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.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo-spring-boot-starter</artifactId>
    <version>0.0.4-SNAPSHOT</version>
    <name>demo-spring-boot-starter</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

    </dependencies>

    <repositories>
        <repository>
            <id>alimaven</id>
            <url>https://maven.aliyun.com/repository/public</url>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>alimaven</id>
            <url>https://maven.aliyun.com/repository/public</url>
        </pluginRepository>
    </pluginRepositories>

</project>

三、组件集成依赖测试

3.1、新启另一个项目中,引入刚刚打包的pom依赖

        <dependency>
            <groupId>com.example</groupId>
            <artifactId>demo-spring-boot-starter</artifactId>
            <version>0.0.4-SNAPSHOT</version>
        </dependency>

3.2、新建一个controller,里面注入上面提供的AnimalService类并调用其方法

package com.cjb.mavendemo.controllers;

import com.example.demospringbootstarter.service.AnimalService;
import com.example.inputoutputlogspringbootstarter.config.PrintResponseTime;
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;

/**
 * @Project: maven-demo
 * @Description:
 * @Author: chengjiangbo
 * @Date: 2023/2/7  10:26
 */
@RestController
@RequestMapping(value = "/test")
public class TestController {

    @Autowired
    private AnimalService animalService;

    @PrintResponseTime
    @GetMapping("/call")
    public String call(){
        return animalService.say();
    }
}

3.3、application.properties内容配置参数"animal.name"值

3.4、最后通过项目启动类启动项目(项目启动类就一个@SpringBootApplicaiton注解)

package com.cjb.mavendemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MavenDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(MavenDemoApplication.class, args);
    }

}

3.5、接口测试

调用http接口测试:

修改"animal.name"值为"cat",再次调用http接口访问:

四、源码地址,参考资料

  1. 组件代码:https://download.csdn.net/download/u010132847/87426046

    1. 集成自定义组件代码:https://download.csdn.net/download/u010132847/87426048

到此这篇关于实现自定义SpringBoot的Starter组件的文章就介绍到这了,更多相关SpringBoot自定义Starter组件内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SpringMVC五大组件与执行原理分析总结

    目录 1.DispatcherServlet(前端(核心)控制器) 2.HandlerMapping(处理器映射器) 3.Controller(处理请求的控制器) 4.ModelAndView(封装数据和视图信息) 5.ViewResolver(视图解析器) SpringMVC执行原理 总结 Spring MVC是包含在spring中的一个基于MVC设计思想的Web应用程序框架,目的是简化开发工作,提高开发效率. 优点 和Spring框架无缝集成,能直接使用Spring的IoC容器.AOP支持:

  • SpringCloud Gateway路由组件详解

    目录 简介 核心概念 具体示例 GlobalFilter 简介   Gateway是SpringCloud Alibaba中的路由组件(前身是Zuul),作为浏览器端请求的统一入口.当项目采用微服务模式时,若包含了路由模块,浏览器端的请求都不会直接请求含有业务逻辑的各个业务模块,而是请求这个路由模块,然后再由它来转发到各个业务模块去. 核心概念   Gateway中的三个核心概念:路由.断言(Predicate).过滤器.   路由:由唯一id.目的url.断言和过滤组成   断言:即路由规则,

  • SpringMVC的五大核心组件用法及说明

    目录 SpringMVC的五大核心组件 一.DispatcherServlet 二.HandlerMapping 三.Controller 四.ModelAndView 五.ViewResolver SpringMVC框架的核心组件及其流程图 SpringMVC框架 总结 SpringMVC的五大核心组件 DispatcherServlet -前端控制器,用于统一接收请求并分发,组织处理请求的流程 HandlerMapping -映射请求路径与处理请求的控制器 Controller -由开发人员

  • Spring七大组件是哪些以及作用

    目录 核心容器(Spring core) Spring上下文(Spring context) Spring面向切面编程(Spring AOP) Spring DAO模块 Spring ORM模块 Spring Web模块 Spring MVC框架(Spring WebMVC) 核心容器(Spring core) 核心容器提供Spring框架的基本功能.Spring以bean的方式组织和管理Java应用中的各个组件及其关系.Spring使用BeanFactory来产生和管理Bean,它是工厂模式的

  • Springboot轻量级的监控组件SpringbootAdmin

    目录 简介 服务端配置 客户端配置 最后 简介 Springboot Admin是一个管理和监控Springboot项目的组件,分为服务端和客户端,两端通过http进行通信.由于其轻量级的特性,所以特别适合中小项目使用. 其效果图如下: 服务端配置 1,引入Springboot admin和Spring Security依赖. <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-

  • Spring Boot自定义Starter组件开发实现配置过程

    目录 自定义starter 为什么要自定义starter 自定义starter的命名规则 实现方法 引入依赖 编写测试类 创建配置类 创建spring.factories文件 乱码问题 解决方案: 1. 使用yml配置文件进行配置. 2. 使用自定义配置文件如: 3. 把中文换成对应的ASCII码. 自定义starter SpringBoot中的starter是一种非常重要的机制,能够抛弃以前繁杂的配置,将其统一集成进 starter,应用者只需要在maven中引入starter依赖,Sprin

  • SpringBoot配置Actuator组件,实现系统监控

    目录 一.Actuator简介 二.与SpringBoot2.0整合 1.核心依赖Jar包 2.Yml配置文件 三.监控接口详解 1.Info接口 2.Health接口 3.Beans接口 4.Conditions接口 5.HeapDump接口 6.Mappings接口 7.ThreadDump接口 8.ShutDown接口 四.源代码地址 一.Actuator简介 监控分类 Actuator 提供Rest接口,展示监控信息. 接口分为三大类: 应用配置类:获取应用程序中加载的应用配置.环境变量

  • vue子组件使用自定义事件向父组件传递数据

    使用v-on绑定自定义事件可以让子组件向父组件传递数据,用到了this.$emit('自定义的事件名称',传递给父组件的数据) <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../js/vue.js"></scr

  • Jquery Easyui自定义下拉框组件使用详解(21)

    本文实例为大家分享了Jquery Easyui自定义下拉框组件的实现代码,供大家参考,具体内容如下 加载方式 JS调用加载 自定义下拉框不能通过标签的方式进行创建. <input id="box" /> <script> $(function () { //JS 加载调用 $('#box').combo({ required : true, multiple : true, }); }); </script> 属性列表 <script>

  • vue 自定义 select内置组件

    1.整合了第三方 jQuery 插件 (select2) <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <link rel="stylesheet" href="js/select2/select2.min.css" /> <style> html, body

  • js中自定义react数据验证组件实例详解

    我们在做前端表单提交时,经常会遇到要对表单中的数据进行校验的问题.如果用户提交的数据不合法,例如格式不正确.非数字类型.超过最大长度.是否必填项.最大值和最小值等等,我们需要在相应的地方给出提示信息.如果用户修正了数据,我们还要将提示信息隐藏起来. 有一些现成的插件可以让你非常方便地实现这一功能,如果你使用的是knockout框架,那么你可以借助于Knockout-Validation这一插件.使用起来很简单,例如我下面的这一段代码: ko.validation.locale('zh-CN');

  • 浅析JS中什么是自定义react数据验证组件

    我们在做前端表单提交时,经常会遇到要对表单中的数据进行校验的问题.如果用户提交的数据不合法,例如格式不正确.非数字类型.超过最大长度.是否必填项.最大值和最小值等等,我们需要在相应的地方给出提示信息.如果用户修正了数据,我们还要将提示信息隐藏起来. 有一些现成的插件可以让你非常方便地实现这一功能,如果你使用的是knockout框架,那么你可以借助于Knockout-Validation这一插件.使用起来很简单,例如我下面的这一段代码: ko.validation.locale('zh-CN');

  • vue 自定义提示框(Toast)组件的实现代码

    1.自定义 提示框 组件 src / components / Toast / index.js /** * 自定义 提示框( Toast )组件 */ var Toast = {}; var showToast = false, // 存储toast显示状态 showLoad = false, // 存储loading显示状态 toastVM = null, // 存储toast vm loadNode = null; // 存储loading节点元素 Toast.install = func

  • 详解vue 自定义marquee无缝滚动组件

    先上效果图: (1) 看起来可能有点卡顿,但是实际上页面上看起来挺顺畅的. (2) 思路就是获取每一个列表的宽度,设置定时器移动列表,当移动的距离达到一个列表的宽度的时候,把这个距离放到数组的最后.这样就能达成无缝循环滚动了. 大致的情况就是下面这样: 接下来就是代码的实现: index.vue 引入组件 <template> <div> <marqueeLeft :send-val='send'></marqueeLeft > </div> &

  • vue 自定义全局方法,在组件里面的使用介绍

    在main.js里进行全局注册 Vue.prototype.funcName = function (){} 在所有组件里可调用 this. funcName(); 以上这篇vue 自定义全局方法,在组件里面的使用介绍就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

随机推荐