前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自己实现一个spring-boot-starter

自己实现一个spring-boot-starter

作者头像
用户1215919
发布2021-12-28 12:48:06
2110
发布2021-12-28 12:48:06
举报
文章被收录于专栏:大大的微笑大大的微笑

SpringBoot自动装配

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

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

SpringFramework @Conditional

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

  1. 接口
代码语言:javascript
复制
public @interface Conditional {
   Class<? extends Condition>[] value();
}

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

  1. 用于匹配ucloud服务商
代码语言:javascript
复制
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
复制
	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
复制
@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
复制
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
复制
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
复制
@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
复制
@SpringBootTest
public class SendMessageTester {

    @Autowired
    private ISendMessageTemplate sendMessageTemplate;

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

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

手写个starter(以Redis为例)
  1. 依赖
代码语言:javascript
复制
	 <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.3.1</version>
        </dependency>
  1. properties
代码语言:javascript
复制
@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
复制
// 根据前面的内容我们知道
// 仅当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
复制
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.bellamy.learn.redisson.configuration.RedissonAutoConfiguration
开启提醒功能
  1. MAVEN依赖
代码语言:javascript
复制
<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
复制
{
  "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
复制
<dependency>
	<groupId>org.bellamy.learn</groupId>
	<artifactId>redis-spring-boot-starter</artifactId>
	<version>0.0.1-SNAPSHOT</version>
</dependency>
代码语言:javascript
复制
	redisson.host=127.0.0.1
	redisson.port =6379
	redisson.timeout=60000
  1. 开始测试
代码语言:javascript
复制
@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 删除。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 约定优于配置
  • SpringFramework @Conditional
  • SpringBoot @ConditionXXX注解
  • 手写个starter(以Redis为例)
  • 开启提醒功能
  • 在测试工程中引入如上的项目依赖
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档