• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

实现自定义SpringBoot的Starter组件

武飞扬头像
令狐前生
帮助1

一、前言

想要自定义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):

  1.  
    private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
  2.  
    Map<String, List<String>> result = (Map)cache.get(classLoader);
  3.  
    if (result != null) {
  4.  
    return result;
  5.  
    } else {
  6.  
    HashMap result = new HashMap();
  7.  
     
  8.  
    try {
  9.  
    Enumeration urls = classLoader.getResources("META-INF/spring.factories");
  10.  
     
  11.  
    while(urls.hasMoreElements()) {
  12.  
    URL url = (URL)urls.nextElement();
  13.  
    UrlResource resource = new UrlResource(url);
  14.  
    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
  15.  
    Iterator var6 = properties.entrySet().iterator();
  16.  
     
  17.  
    while(var6.hasNext()) {
  18.  
    Entry<?, ?> entry = (Entry)var6.next();
  19.  
    String factoryTypeName = ((String)entry.getKey()).trim();
  20.  
    String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
  21.  
    String[] var10 = factoryImplementationNames;
  22.  
    int var11 = factoryImplementationNames.length;
  23.  
     
  24.  
    for(int var12 = 0; var12 < var11; var12) {
  25.  
    String factoryImplementationName = var10[var12];
  26.  
    ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
  27.  
    return new ArrayList();
  28.  
    })).add(factoryImplementationName.trim());
  29.  
    }
  30.  
    }
  31.  
    }
  32.  
     
  33.  
    result.replaceAll((factoryType, implementations) -> {
  34.  
    return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
  35.  
    });
  36.  
    cache.put(classLoader, result);
  37.  
    return result;
  38.  
    } catch (IOException var14) {
  39.  
    throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
  40.  
    }
  41.  
    }
  42.  
    }
学新通

举例如: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文件中添加如下仓库配置,可以加快构建速度。

  1.  
    <repositories>
  2.  
    <repository>
  3.  
    <id>alimaven</id>
  4.  
    <url>https://maven.aliyun.com/repository/public</url>
  5.  
    </repository>
  6.  
    </repositories>
  7.  
     
  8.  
    <pluginRepositories>
  9.  
    <pluginRepository>
  10.  
    <id>alimaven</id>
  11.  
    <url>https://maven.aliyun.com/repository/public</url>
  12.  
    </pluginRepository>
  13.  
    </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:

  1.  
    package com.example.demospringbootstarter.service;
  2.  
     
  3.  
    /**
  4.  
    * @Project: demo-spring-boot-starter
  5.  
    * @Description:
  6.  
    * @Author: chengjiangbo
  7.  
    * @Date: 2023/2/7 15:12
  8.  
    */
  9.  
    public interface AnimalService {
  10.  
     
  11.  
    String say();
  12.  
    }

两个接口实现类CatService和DogService:

  1.  
    package com.example.demospringbootstarter.service;
  2.  
     
  3.  
    import lombok.AllArgsConstructor;
  4.  
    import lombok.Data;
  5.  
    import lombok.NoArgsConstructor;
  6.  
    import org.springframework.stereotype.Service;
  7.  
     
  8.  
    /**
  9.  
    * @Project: demo-spring-boot-starter
  10.  
    * @Description:
  11.  
    * @Author: chengjiangbo
  12.  
    * @Date: 2023/2/7 14:49
  13.  
    */
  14.  
    @Service
  15.  
    public class CatService implements AnimalService{
  16.  
     
  17.  
    public static String name = "cat";
  18.  
     
  19.  
    @Override
  20.  
    public String say() {
  21.  
    return "喵喵";
  22.  
    }
  23.  
    }
学新通
  1.  
    package com.example.demospringbootstarter.service;
  2.  
     
  3.  
    import org.springframework.stereotype.Service;
  4.  
     
  5.  
    /**
  6.  
    * @Project: demo-spring-boot-starter
  7.  
    * @Description:
  8.  
    * @Author: chengjiangbo
  9.  
    * @Date: 2023/2/7 14:49
  10.  
    */
  11.  
    @Service
  12.  
    public class DogService implements AnimalService{
  13.  
     
  14.  
    public static String name = "dog";
  15.  
     
  16.  
    @Override
  17.  
    public String say() {
  18.  
    return "汪汪";
  19.  
    }
  20.  
    }
学新通

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

  1.  
    package com.example.demospringbootstarter.config;
  2.  
     
  3.  
    import lombok.Data;
  4.  
    import org.springframework.boot.context.properties.ConfigurationProperties;
  5.  
     
  6.  
    /**
  7.  
    * @Project: demo-spring-boot-starter
  8.  
    * @Description:
  9.  
    * @Author: chengjiangbo
  10.  
    * @Date: 2023/2/7 15:37
  11.  
    */
  12.  
    @Data
  13.  
    @ConfigurationProperties(prefix = "animal")
  14.  
    public class AnimalProperties {
  15.  
     
  16.  
    private String name;
  17.  
    }
学新通

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

  1.  
    package com.example.demospringbootstarter.config;
  2.  
     
  3.  
    import com.example.demospringbootstarter.service.AnimalService;
  4.  
    import com.example.demospringbootstarter.service.CatService;
  5.  
    import com.example.demospringbootstarter.service.DogService;
  6.  
    import org.springframework.beans.factory.annotation.Autowired;
  7.  
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
  8.  
    import org.springframework.context.annotation.Bean;
  9.  
    import org.springframework.context.annotation.Configuration;
  10.  
     
  11.  
    /**
  12.  
    * @Project: demo-spring-boot-starter
  13.  
    * @Description:
  14.  
    * @Author: chengjiangbo
  15.  
    * @Date: 2023/2/7 14:48
  16.  
    */
  17.  
    @Configuration
  18.  
    @EnableConfigurationProperties(AnimalProperties.class)
  19.  
    public class AnimalAutoConfig {
  20.  
     
  21.  
    @Autowired
  22.  
    private AnimalProperties animalProperties;
  23.  
     
  24.  
    @Bean
  25.  
    public AnimalService demoService(){
  26.  
    switch (animalProperties.getName()){
  27.  
    case "cat":
  28.  
    return new CatService();
  29.  
    case "dog":
  30.  
    return new DogService();
  31.  
    default:
  32.  
    return null;
  33.  
    }
  34.  
    }
  35.  
    }
学新通

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

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

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

mvn clean install -Dmaven.test.skip=true

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

学新通

pom.xml内容为:

  1.  
    <?xml version="1.0" encoding="UTF-8"?>
  2.  
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3.  
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4.  
    <modelVersion>4.0.0</modelVersion>
  5.  
    <parent>
  6.  
    <groupId>org.springframework.boot</groupId>
  7.  
    <artifactId>spring-boot-starter-parent</artifactId>
  8.  
    <version>2.3.4.RELEASE</version>
  9.  
    <relativePath/> <!-- lookup parent from repository -->
  10.  
    </parent>
  11.  
    <groupId>com.example</groupId>
  12.  
    <artifactId>demo-spring-boot-starter</artifactId>
  13.  
    <version>0.0.4-SNAPSHOT</version>
  14.  
    <name>demo-spring-boot-starter</name>
  15.  
    <description>Demo project for Spring Boot</description>
  16.  
    <properties>
  17.  
    <java.version>8</java.version>
  18.  
    </properties>
  19.  
    <dependencies>
  20.  
    <dependency>
  21.  
    <groupId>org.springframework.boot</groupId>
  22.  
    <artifactId>spring-boot-starter-web</artifactId>
  23.  
    </dependency>
  24.  
     
  25.  
    <dependency>
  26.  
    <groupId>org.projectlombok</groupId>
  27.  
    <artifactId>lombok</artifactId>
  28.  
    <optional>true</optional>
  29.  
    </dependency>
  30.  
     
  31.  
    </dependencies>
  32.  
     
  33.  
    <repositories>
  34.  
    <repository>
  35.  
    <id>alimaven</id>
  36.  
    <url>https://maven.aliyun.com/repository/public</url>
  37.  
    </repository>
  38.  
    </repositories>
  39.  
     
  40.  
    <pluginRepositories>
  41.  
    <pluginRepository>
  42.  
    <id>alimaven</id>
  43.  
    <url>https://maven.aliyun.com/repository/public</url>
  44.  
    </pluginRepository>
  45.  
    </pluginRepositories>
  46.  
     
  47.  
    </project>
学新通

三、组件集成依赖测试

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

  1.  
    <dependency>
  2.  
    <groupId>com.example</groupId>
  3.  
    <artifactId>demo-spring-boot-starter</artifactId>
  4.  
    <version>0.0.4-SNAPSHOT</version>
  5.  
    </dependency>

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

  1.  
    package com.cjb.mavendemo.controllers;
  2.  
     
  3.  
    import com.example.demospringbootstarter.service.AnimalService;
  4.  
    import com.example.inputoutputlogspringbootstarter.config.PrintResponseTime;
  5.  
    import org.springframework.beans.factory.annotation.Autowired;
  6.  
    import org.springframework.web.bind.annotation.GetMapping;
  7.  
    import org.springframework.web.bind.annotation.RequestMapping;
  8.  
    import org.springframework.web.bind.annotation.RestController;
  9.  
     
  10.  
    /**
  11.  
    * @Project: maven-demo
  12.  
    * @Description:
  13.  
    * @Author: chengjiangbo
  14.  
    * @Date: 2023/2/7 10:26
  15.  
    */
  16.  
    @RestController
  17.  
    @RequestMapping(value = "/test")
  18.  
    public class TestController {
  19.  
     
  20.  
    @Autowired
  21.  
    private AnimalService animalService;
  22.  
     
  23.  
    @PrintResponseTime
  24.  
    @GetMapping("/call")
  25.  
    public String call(){
  26.  
    return animalService.say();
  27.  
    }
  28.  
    }
学新通

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

学新通

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

  1.  
    package com.cjb.mavendemo;
  2.  
     
  3.  
    import org.springframework.boot.SpringApplication;
  4.  
    import org.springframework.boot.autoconfigure.SpringBootApplication;
  5.  
     
  6.  
    @SpringBootApplication
  7.  
    public class MavenDemoApplication {
  8.  
     
  9.  
    public static void main(String[] args) {
  10.  
    SpringApplication.run(MavenDemoApplication.class, args);
  11.  
    }
  12.  
     
  13.  
    }

3.5、接口测试

调用http接口测试:

学新通

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

学新通

四、源码地址

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

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

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgiijab
系列文章
更多 icon
同类精品
更多 icon
继续加载