面试重点:starter原理以及自己动手实现一个starter

前言

使用过Spring Boot的同学,都应该对starter不陌生,starter可以看过是一个个组件,用于提供不同的功能。Spring官方提供了很多starter,对应于不同的应用场景,以下为部分实现:
在这里插入图片描述
在我们需要某种功能的时候,只需要简单地导入一个starter就可以直接使用。那么为什么只要导入starter就能使用这些功能呢,Spring Boot是如何做到的?下边就通过自己实现一个starter来捋一捋这其中的流程。

在这篇文章 源码分析——Spring Boot是如何实现自动配置的
,我简单分析了下Spring Boot自动配置的相关原理。简单总结就是:

  1. 通过@EnableAutoConfiguration注解开启自动配置(@SpringBootApplication注解默认已包含)
  2. 自动加载类路径下META-INF/spring.factories文件,读取以EnableAutoConfiguration的全限定类名对应的值,作为候选配置类。这里默认给出了很多组件的自动配置类。
  3. 自动配置类可能会再导入一些依赖(比如@Import),或者给出一些配置条件,并且会通过@Bean注解把该组件所包含的组件注入到spring容器中以供使用。
  4. 自动配置类还可能会绑定xxxProperties配置文件类,该类又会和应用程序中的application.properties中的指定前缀绑定。第3步注入组件的时候,组件可能还会获取配置文件类中的内容,所以用户可以在application.properties修改指定配置,来制定自己的个性化服务。

其实starter的实现也是基于Spring Boot的自动配置来实现的,下边就参考官方文档(Creating Your Own Starter)来自己动手实现一个starter。

starter的有关规范

结构

一步步参考官方文档来:
在这里插入图片描述
首先可以看到,规范的starter包含两个model,一个autoconfigure,提供自动配置代码,一个starter,会加载 autoconfigure,并提供启动所需的所有依赖。

这里我的理解是 莫非还是为了解耦?starter只管启动,具体的配置啥的都交给autoconfigure,这里就看自己的理解了。

命名

接下来是命名,这里就不截取官方文档的原文了,大概意思就是:

  1. spring-boot开头的是官方的starter,非官方的最好不要用这个开头,比如前边看到的spring-boot-starter-aop等等,都是以此开头的。
  2. 自定义的starter可以以一个功能单词开头,后边跟上-spring-boot-starter,比如常见的mybatis-spring-boot-starterdruid-spring-boot-starter

这里是一些基本的规范,其它的规范到具体应用再说。

自定义starter

新建项目

接下来按照规范,一步步来创建自己的starter。首先创建一个空的Project。用以承载starterautoconfigure两个model。
在这里插入图片描述

在这里插入图片描述

这里命名不重要,只要具体的模块按照规范命名即可。

新建starter模块

接下来在当前Project下新建model,这里我选择先创建starter
在这里插入图片描述
创建maven工程
在这里插入图片描述

这里GroupId和ArtifactId相当于是Maven项目的三维坐标(一般还有个版本号)。当你把自己的项目发布到maven仓库后,他人若想使用你的项目,就通过这两个坐标来引入。其中GroupId类似代表企业,一般是域名反写,ArtifactId一般是具体的项目名,对于starter而言,规范就是xxx-spring-boot-starter,比如mybatis和druid的starter:

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.2</version>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.22</version>
</dependency>

这里我新建一个myservice的starter,做如下命名:
在这里插入图片描述
在这里插入图片描述

新建autoconfigure模块

建好后,我们再去新建autoconfigure这个model,这里因为是要借助Spring Boot做自动配置,就可以直接使用Spring Initializer来创建。
在这里插入图片描述

这里依然按照规范,ArtifactId为myservice-spring-boot-autoconfigure
在这里插入图片描述

然后什么都不导入,直接一路next,finish。

配置autoconfigure模块

pom依赖

修改pom文件,删除无关依赖:

<?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.2.6.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>cn.novalue.starter</groupId>
	<artifactId>myservice-spring-boot-autoconfigure</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>myservice-spring-boot-autoconfigure</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
	</dependencies>

</project>

这里 spring-boot-starter的依赖是一定要有的,官方文档说了,starter模块要直接或者间接导入该模块,这里就把它放到autoconfigure模块下了。当然这里的依赖放置可能并不是很规范,只是为了学习罢了。

Either way, your starter must reference the core Spring Boot starter (spring-boot-starter) directly or indirectly (i.e. no need to add it if your starter relies on another starter). If a project is created with only your custom starter, Spring Boot’s core features will be honoured by the presence of the core starter.

由于我们这个模块只管配置,那么把启动类也删除了,test文件夹也删除,配置文件application.properties也可以删除了。

xxxProperties配置

按照开头的自动配置描述,新建一个MyProperties配置类。

@ConfigurationProperties(prefix = "myservice")
public class MyProperties {
    private String prefix;
    private String suffix;

    public String getPrefix() {
        return prefix;
    }

    public String getSuffix() {
        return suffix;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }
}

这里注解 @ConfigurationProperties 表示这是一个配置文件,其中的属性字段可以在application.properties中指定。prefix = "myservice"表示匹配 myservice前缀。例如这里,我们将来使用的时候就可以通过配置myservice.prefix=xxx来配置前缀。

服务提供类

然后我们新建个MyService服务类,表示我们这个starter可以提供的服务。

public class MyService {

    private MyProperties myProperties;

    public MyService(MyProperties myProperties) {
        this.myProperties = myProperties;
    }

    public String addPrefix(String s) {
        return this.myProperties.getPrefix() + "-" + s;
    }
}

这里把配置文件作为构造方法参数传递进去,然后在具体服务中使用,这里只简单的提供一个添加前缀的服务。

自动配置

最后一步,就是编写一个自动配置类,绑定我们的配置文件、并将我们的服务注入到spring容器。如下:

// 必须,指明这是一个配置类
@Configuration
// 可选,表示在web应用中才配置
@ConditionalOnWebApplication
// 必须,绑定我们的配置文件类
@EnableConfigurationProperties(MyProperties.class)
// 可选,表示可以在配置文件中,通过myservice.enable来设置是否配置该类
// 如果没有指明,则默认为true,即表示配置,如果指明为false,就不配置了
@ConditionalOnProperty(prefix = "myservice", value = "enable", matchIfMissing = true)
public class MyServiceAutoConfiguration {

	// 注入配置文件
    @Autowired
    MyProperties myProperties;
	// 用@Bean将MyService注入到Spring容器中,并把配置文件传进去,以供MyService使用
    @Bean
    public MyService myService() {
        return new MyService(myProperties);
    }
}

这里关于自动配置有很多相关的注解,提供了更细粒度的配置控制,比如@Conditionalxxx系列,表示在满足什么条件下才配置。或者@AutoConfigureOrder指定顺序等等,可根据具体需求选择配置。
在这里插入图片描述

META-INF/spring.factories

在前边说过,Spring Boot的自动配置会自动加载类路径下META-INF/spring.factories文件,并将以类EnableAutoConfiguration的全限定类名对应的值作为候选配置类。所以这里还需要新建该文件。
在这里插入图片描述

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.novalue.starter.MyServiceAutoConfiguration

这样,Spring Boot就能自动扫描到我们这个配置类并加载了。

打包构建

编写完后,将两个模块打包发布到maven仓库。因为导入的时候是从maven仓库查找的。这里说一点,我们默认打包发布是发布在我们本地的maven仓库的,所以只能本地使用。如果想要将自己的服务公开出去,可以查找发布到maven中心仓库的方法。

IDEA可以很简单地执行打包操作:
在这里插入图片描述
在这里插入图片描述
以此打包好autoconfigure模块和starter模块。

到此,自定义starter就算完成了,下边测试一下。

测试

可以新建个Spring Boot的maven项目测试,这里我省事,就还在原Project下新建model测试了,效果一样的。
在这里插入图片描述

因为我们写的自动配置有个@ConditionalOnWebApplication,表示在Web应用程序下才配置,所以这里要勾选Spring Web。
在这里插入图片描述

新建完成后,在pom.xml中导入我们的starter依赖

		<dependency>
			<groupId>cn.novalue.starter</groupId>
			<artifactId>myservice-spring-boot-starter</artifactId>
			<version>1.0-SNAPSHOT</version>
		</dependency>

作为测试,可以在application.properties文件中,做自定义配置,比如设置前缀:

myservice.prefix=this is prefix

新建一个TestController,注入我们的MyService

@RestController
public class TestController {
    @Autowired
    private MyService myService;

    @GetMapping("/test")
    public String test() {
        return myService.addPrefix("test MyService");
    }
}

这里调用myService.addPrefix。启动项目,浏览器输入http://localhost:8080/test
在这里插入图片描述

说明我们确实可以使用myService的服务,并且可以自定义前缀。

总结

总结自定义starter的主要流程和注意事项:

  1. 规范是定义一个starter模块和autoconfigure模块,starter模块依赖autoconfigure模块,并提供启动所需的依赖。starter模块不提供服务。
  2. 在命名上,一般是前缀-spring-boot-starter前缀-spring-boot-autoconfigure,比如mybatis-spring-boot-starter
  3. 可以编写xxxProperties配置文件,按照自己的需求,提供可自定义的配置选项。
  4. autoconfigure模块中编写自己的服务类,可以导入配置文件并使用其中的配置。
  5. 自动配置类要标注@Configuration注解,用@EnableConfigurationProperties绑定配置文件,可按照自己的需求,给出自动配置的条件、时机、顺序等。用@Bean把自己所要暴露的服务类提供出来,让其注入到Spring容器中。
  6. 新建META-INF/spring.factories文件,把自己的配置类全类名绑定到Spring Boot自动配置类的全类名上。如下所示:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.novalue.starter.MyServiceAutoConfiguration
  1. 打包发布两个模块。
  • 15
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Boot 中,Starter 是一种特殊的依赖,它能够帮助我们快速地集成一些常用的功能,例如日志、数据库等。如果我们想要实现一个自己的 Starter,可以按照以下步骤来进行: 1. 创建一个 Maven 项目,项目的命名规则为 `spring-boot-starter-{name}`,其中 `{name}` 表示 Starter 的名称,例如 `spring-boot-starter-mybatis`。 2. 在项目的 `pom.xml` 文件中,添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>${spring.boot.version}</version> <scope>compile</scope> </dependency> ``` 这个依赖表示我们的 Starter 依赖于 Spring Boot 的核心 Starter。 3. 创建一个自定义的 Starter 类,该类需要继承自 `org.springframework.boot.autoconfigure.EnableAutoConfiguration` 类,并且需要添加 `@Configuration` 和 `@ConditionalOnClass` 注解,例如: ```java @Configuration @ConditionalOnClass(MyService.class) @EnableConfigurationProperties(MyProperties.class) public class MyAutoConfiguration { @Autowired private MyProperties properties; @Bean @ConditionalOnMissingBean public MyService myService() { return new MyService(properties.getName()); } } ``` 上述代码表示,当 MyService 类存在时,才会加载这个 Starter。另外,`@EnableConfigurationProperties(MyProperties.class)` 注解表示需要将 `MyProperties` 类注入到配置文件中。 4. 创建一个自定义的 Properties 类,用于读取配置文件中的属性,例如: ```java @ConfigurationProperties(prefix = "my") public class MyProperties { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } ``` 上述代码中,`@ConfigurationProperties(prefix = "my")` 注解表示该类需要读取配置文件中以 `my` 开头的属性,例如 `my.name`。 5. 将项目打包成 Jar 文件,并上传到 Maven 仓库中。 6. 在其他项目中,可以通过添加以下依赖来使用我们的 Starter: ```xml <dependency> <groupId>com.example</groupId> <artifactId>spring-boot-starter-mybatis</artifactId> <version>1.0.0</version> </dependency> ``` 上述代码中,`com.example` 表示我们自己的组织名称,`spring-boot-starter-mybatis` 表示我们自己的 Starter 名称,`1.0.0` 表示版本号。 通过以上步骤,我们就成功地实现一个自己的 Starter,可以方便地在其他项目中使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值