软件编程
位置:首页>> 软件编程>> java编程>> 如何实现自定义SpringBoot的Starter组件

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

作者:令狐前生  发布时间:2023-06-28 14:49:04 

标签:SpringBoot,Starter,组件

一、前言

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

1.1、starter加载原理

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

1.1.1、加载starter

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

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

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

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

这个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.

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

二、自定义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文件。

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

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下的命令操作)。

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

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"值

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

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接口测试:

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

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

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

四、源码地址,参考资料

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

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

来源:https://blog.csdn.net/u010132847/article/details/128920976

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com