Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >自己实现一个spring-boot-starter

自己实现一个spring-boot-starter

作者头像
用户1215919
发布于 2021-12-28 04:48:06
发布于 2021-12-28 04:48:06
27800
代码可运行
举报
文章被收录于专栏:大大的微笑大大的微笑
运行总次数:0
代码可运行

SpringBoot自动装配

  1. ImportSelector
  2. Registrar
约定优于配置

SpringBoot默认会扫描META-INF下面的spring.factories文件中的类的全路径进行装配

SpringFramework @Conditional

Conditional.class 是从Spring4.0开始提供的,通过当前注解可以实现多条件装配;该注解需要搭配Condition.class接口使用. 以下是注解的内容

  1. 接口
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public @interface Conditional {
   Class<? extends Condition>[] value();
}

下面以接入短信服务商为例;通过扫描我们在配置文件中配置使用哪家服务商然后自动进行装配.

  1. 用于匹配ucloud服务商
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class UCloudConditional implements Condition {
    private Properties properties;
    @Override
    public boolean matches
		(ConditionContext conditionContext, 
		 AnnotatedTypeMetadata annotatedTypeMetadata)
		throws Exception{
        properties = new Properties();
        InputStream is = conditionContext.getResourceLoader()
			.getResource("classpath:xxx.properties").getInputStream();
            properties.load(is); // 这里的properties文件可以自行定义
            return StringUtils.isEmpty(properties.getProperty("sms.used"))
                    ? false
                   "ucloud".equalsIgnoreCase(properties.getProperty("sms.used")); // 看当前是否匹配
  1. 用于匹配创蓝服务商
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	public class ClConditional implements Condition {
    private Properties properties;
// 内容差不多同上所示
    @Override
    public boolean matches
		(ConditionContext conditionContext,
		AnnotatedTypeMetadata annotatedTypeMetadata)
		throws Exception{
		
        properties = new Properties();
        InputStream  is = conditionContext.getResourceLoader().getResource("classpath:xxx.properties").getInputStream();
	properties.load(is);
	return StringUtils.isEmpty(properties.getProperty("sms.used"))
	? true
	: "cl".equalsIgnoreCase(properties.getProperty("sms.used"));
  1. 配置类
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
public class SMSMessageConfiguration {

    @Bean
    @Conditional(UCloudConditional.class)
    public ISendMessageTemplate createUCloudTemplate() {
        return new UCloudSendMessageTemplate();
    }

    @Bean
    @Conditional(ClConditional.class)
    public ISendMessageTemplate createClTemplate() {
        return new ClSendMessageTemplate();
    }
}
  1. 提供服务
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface ISendMessageTemplate {
    void sendMessage(String phone, String content);
}

public class ClSendMessageTemplate {
 void sendMessage(String phone, String content){
	System.out.printf("using chuanglan send msg, phone:%s, content:%s", phone, content);
 }
}

public class UCloudSendMessageTemplate {
	void sendMessage(String phone, String content){
	   System.out.printf("using ucloud send msg, phone:%s, content:%s", phone, content);
	}
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class SendMessageTester {
	@Autowired
    private ISendMessageTemplate sendMessageTemplate;

    /**
     * 短信发送
     *
     * @param phone
     * @param content
     * @return
     */
	@Test
    public void testSend(){
        sendMessageTemplate.sendMessage("13800138000", "Hi");
    }
}
SpringBoot @ConditionXXX注解

通过如上案例会发现还是需要很多的代码才能实现一个条件注入;因此在SpringBoot中对于上述进行了进一步的简化,SpringBoot中提供了大量的@ConditionXxx注解. 例如提供了诸如: @ConditionalOnBean@ConditionalOnClass@ConditionalOnProperty@ConditionalOnMissingBean等注解的支持. 还是以上述的发送短信案例为例,依据上面的代码做如下改动

  1. configuration
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
public class SMSMessageConfiguration {
    @Bean
    @ConditionalOnProperty(name = "sms.used", havingValue  = "ucloud")
    public ISendMessageTemplate createUCloudTemplate() {
        return new UCloudSendMessageTemplate();
    }
	
    @Bean
    @ConditionalOnProperty(value  = "sms.used", havingValue  = "cl")
    public ISendMessageTemplate createClTemplate() {
        return new ClSendMessageTemplate();
    }
}
  1. 测试
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@SpringBootTest
public class SendMessageTester {

    @Autowired
    private ISendMessageTemplate sendMessageTemplate;

    @Test
    public void testSend(){
        sendMessageTemplate.sendMessage("13800138000", "Hi");
    }
}

通过上诉案例两者都可以实现条件装配,相比于SpringFramework框架提供的方式,SpringBoot更方便,提供的条件装配的注解种类更多

手写个starter(以Redis为例)
  1. 依赖
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	 <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.3.1</version>
        </dependency>
  1. properties
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@ConfigurationProperties(prefix = "redisson")
public class RedissonProperties {

    private String  host = "localhost";

    private Integer port = 6379;

    private Integer timeout = 10000;

    private boolean ssl;

    private String password;

}
  1. configuration
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 根据前面的内容我们知道
// 仅当Redisson.class被使用到时才装配
@ConditionalOnClass(Redisson.class)
// 激活配置
@EnableConfigurationProperties(RedissonProperties.class)
@Configuration
public class RedissonAutoConfiguration {

    // 这里是配置
    @Bean
    public RedissonClient newRedissonClient(RedissonProperties redissonProperties) {
        Config config = new Config();

        config.useSingleServer()
                .setAddress(redissonProperties.getHost()
                        + ":"
                        + redissonProperties.getPort())
                .setPassword(redissonProperties.getPassword())
                .setConnectTimeout(redissonProperties.getTimeout());

        return Redisson.create(config);

    }
}
  1. spring.factories (MATA-INF)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.bellamy.learn.redisson.configuration.RedissonAutoConfiguration
开启提醒功能
  1. MAVEN依赖
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-configuration-processor</artifactId>
	<version>2.3.3.RELEASE</version>
</dependency>
  1. 增加提示的配置内容

additional-spring-configuration-metadata.json(位置同上)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "properties": [
    {
      "name": "redisson.host",
      "type": "java.lang.String",
      "description": "redis服务地址.",
      "defaultValue": "localhost"
    },
    {
      "name": "redisson.prot",
      "type": "java.lang.Integer",
      "description": "redis服务端口号.",
      "defaultValue": 6379
    },
    {
      "name": "redisson.timeout",
      "type": "java.lang.Integer",
      "description": "redis服务连接超时时间.",
      "defaultValue": 10000
    },
    {
      "name": "redisson.ssl",
      "type": "java.lang.Boolean",
      "description": "ssl连接.",
      "defaultValue": false
    },
    {
      "name": "redisson.password",
      "type": "java.lang.String",
      "description": "redis密码.",
      "defaultValue": ""
    }
  ]
}
在测试工程中引入如上的项目依赖
  1. 依赖
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dependency>
	<groupId>org.bellamy.learn</groupId>
	<artifactId>redis-spring-boot-starter</artifactId>
	<version>0.0.1-SNAPSHOT</version>
</dependency>
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	redisson.host=127.0.0.1
	redisson.port =6379
	redisson.timeout=60000
  1. 开始测试
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@RestController
public class TestController {

    @Autowired
    private RedissonClient client;

    @GetMapping(value = "/operation")
    public Object operation(String val) throws ExecutionException, InterruptedException {
        RBucket<String> bucket = client.getBucket("name");
        if (bucket.get() == null) {
            bucket.set(val);
        }
        return bucket.get();
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Springboot自动装配原理_自动装配原理
我们在这里使用springboot来代替ssm的整合,只是通过xml的形式来整合redis
全栈程序员站长
2022/09/23
5400
Springboot自动装配原理_自动装配原理
Spring中的@Conditional注解
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interfac
用户1215919
2021/12/28
2390
开发一个属于自己的Spring Boot Starter
通过以上的描述,我们可以简单地将starter看作是对一个组件功能粒度较大的模块化封装,包括了所需依赖包的整合及基础配置和自动装配等。
端碗吹水
2020/09/23
4.9K0
开发一个属于自己的Spring Boot Starter
Spring全注解开发---常用注解笔记整理
@Configuration和 @Bean注解以及补充注解的详细说明,强推!!! 配合@Bean注解一起使用的@Scope注解,感兴趣可以看看
大忽悠爱学习
2021/11/15
7160
Spring Boot2 系列教程(七)理解自动化配置的原理
Spring Boot 中的自动化配置确实够吸引人,甚至有人说 Spring Boot 让 Java 又一次焕发了生机,这话虽然听着有点夸张,但是不可否认的是,曾经臃肿繁琐的 Spring 配置确实让人感到头大,而 Spring Boot 带来的全新自动化配置,又确实缓解了这个问题。
江南一点雨
2019/09/24
4820
sbc(三)自定义Starter-SpringBoot重构去重插件
之前看过SSM(十四) 基于annotation的http防重插件的朋友应该记得我后文说过之后要用 SpringBoot来进行重构。
crossoverJie
2022/08/19
3710
sbc(三)自定义Starter-SpringBoot重构去重插件
如何自定义一个starter,你学废了么?
前两天,一位朋友面试时又被问到了starter。我在给他做模拟面试时,我刻意强调了一下,一定要自己去动手写一个 自定义starter,果然面试中被问到了。
田维常
2023/08/31
3660
如何自定义一个starter,你学废了么?
手写一个简单的starter
由于任何人都可以编写自己的 starter,为了区分官方的 starter 和个人的 starter,通常在命名上面会有一个规范。SpringBoot 官方提出规范如下:
悟空宇
2024/03/11
2070
手写一个简单的starter
14-SpringBoot自动配置-Condition
我们在前面的篇章基本上已经熟悉了怎么使用SpringBoot,但是呢。对于SpringBoot的一些高级的特性 或者 底层原理还是不是很清楚。
Devops海洋的渔夫
2022/03/23
5650
14-SpringBoot自动配置-Condition
如何实现一个自定义的starter
如果要实现一个自定义的starter,首先需要引入两个依赖spring-boot的jar包:spring-boot-autoconfigure和spring-boot-configuration-processor:
路行的亚洲
2021/04/28
9650
如何实现一个自定义的starter
spring@Conditional
@Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean。
逍遥壮士
2020/09/18
6730
spring@Conditional
掌握了SpringBoot的自动装配原理后你会发现自定义Starter也是非常容易的哦!
  在实际项目中我们需要手动来手写Starter组件的场景相对来说还是比较少的,但是对于自定义Starter组件的原理大家还是需要掌握清楚,第一个是增加自己的自信心,第二个是掌握的自动装配的原理后Starter组件的实现其实就是非常简单的事情了。我们通过Redis的客户端程序来给大家介绍。对于Redis服务我们可以使用的Java客户端还是比较多的,但是在SpringBoot项目中我们怎么来使用呢?
用户4919348
2021/07/29
4370
掌握了SpringBoot的自动装配原理后你会发现自定义Starter也是非常容易的哦!
spring boot 系列之六:深入理解spring boot的自动配置[通俗易懂]
我们知道,spring boot自动配置功能可以根据不同情况来决定spring配置应该用哪个,不应该用哪个,举个例子:
全栈程序员站长
2022/07/18
3740
spring boot 系列之六:深入理解spring boot的自动配置[通俗易懂]
SpringBoot健康检查实现原理
相信看完之前文章的同学都知道了SpringBoot自动装配的套路了,直接看spring.factories文件,当我们使用的时候只需要引入如下依赖
Java学习录
2019/10/10
1.4K0
SpringBoot健康检查实现原理
Spring常用配置(二)
按:最近公众号文章主要是整理一些老文章,主要是个人CSDN上的博客,也会穿插一些新的技术点。 ---- OK,上篇博客我们介绍了Spring中一些常见的配置,上篇博客中介绍到的都是非常常见的注解,但是在Spring框架中,常见的注解除了上篇博客提到的之外,还有许多其他的注解,只不过这些注解相对于上文提到过的注解使用频率稍微低一些,当然这个使用频率只是相对而言。OK,那么接下来我们就再来了解Spring中的几个注解。 Spring Aware 一般情况下,我们在使用Spring框架时,Bean和Spring容
江南一点雨
2018/04/02
8230
条件注解,Spring Boot 的基石!
Spring4 中提供了更加通用的条件注解,让我们可以在满足不同条件时创建不同的 Bean,这种配置方式在 Spring Boot 中得到了广泛的使用,大量的自动化配置都是通过条件注解来实现的,查看松哥之前的 Spring Boot 文章,凡是涉及到源码解读的文章,基本上都离不开条件注解:
江南一点雨
2019/08/06
3420
SpringBoot基础篇Bean之条件注入@Condition使用姿势
前面几篇关于Bean的基础博文中,主要集中在Bean的定义和使用,但实际的情况中有没有一些场景是不加载我定义的bean,或者只有满足某些前提条件的时候才加载我定义的Bean呢?
一灰灰blog
2019/03/14
2.3K0
SpringBoot基础篇Bean之条件注入@Condition使用姿势
【小家Spring】Spring注解驱动开发---向Spring Ioc容器中注册Bean的7种方式
Spring是一个非常强大的反转控制(IOC)框架,以帮助分离项目组件之间的依赖关系。因此可以说Spring容器对Bean的注册、管理可以说是它的核心内容,最重要的功能部分。
YourBatman
2019/09/03
6860
【小家Spring】Spring注解驱动开发---向Spring Ioc容器中注册Bean的7种方式
SpringBoot内置http编码功能为例分析自动配置过程
在完成了以上步骤的过滤、筛选之后,我们最终获得了要进行自动配置的类的集合,在将该集合返回之前,在 AutoConfigurationlmportSelector 类中完 成的最后一步操作就是相关事件的封装和广播,相关代码如下。
愿天堂没有BUG
2022/10/28
5310
SpringBoot内置http编码功能为例分析自动配置过程
Spring的注解
Spring框架的注解用途广泛,极大地简化了Java企业级应用的开发。注解通过提供元数据来替代传统的XML配置方式,让开发者能够通过简单的声明方式控制各种Spring框架的特性,从而实现依赖注入、面向切面编程等功能。
闻说社
2024/07/01
1050
Spring的注解
推荐阅读
相关推荐
Springboot自动装配原理_自动装配原理
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验