自定义一个spring-boot-starter

前言:

想必大家对于XXX-spring-boot-starter这一串都很熟悉,当我们在springboot当中需要使用某一个插件的时候,往往只需要几步:

        1.引入相关依赖

        2.添加配置

        3.使用

通过上面简单的几步,就能够进行使用了!接下来我就将结合我开发中的一个实例带大家走一遍封装一个自定starter的流程!

适用场景:

        1.当我们项目存在一些通用的配置、组件、工具类、依赖等,可能会被多个项目用到,可以抽取出来封装成一个 Starter,便于复用。

        2.一些复杂的配置和初始化操作,可以通过封装成 Starter,简化应用项目中的配置。

        3.统一团队内的技术规范,封装一些常用的功能,减少重复劳动,提高开发效率。

我的场景引入:

公司使用的MQ是Kafka,Kafka当中,没有对延时队列的支持,为此叫我开发了一款简易版本的MQ,支持发布订阅模式,消息延时消费,ack机制,重试机制,持久化机制等。

在其中,消费者生产者与MQ之间的连接,消息推送,都通过websocket完成,那为了避免每次使用都要去集成一次websocket,以及写一堆消费、推送相关的代码,所以我决定自定义一个starter,来简化操作。

实现步骤:

 1.创建项目并引入相关依赖:

在我这因为需要使用到websocket和Lombok相关的东西,所以也进行了引入,这里主要的就是spring-boot-xxx的几个依赖:

<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
    </dependency>
    <dependency>
      <groupId>org.java-websocket</groupId>
      <artifactId>Java-WebSocket</artifactId>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>
  </dependencies>
2.代码 - 配置代码写入:

这里主要做的就是把你原来可能要重复写的,进行抽取,我这下面一大堆主要就是针对具体使用需要做的配置:建立连接,消息监听处理器等。大家可以结合自己的场景去进行拓展编写。

@Slf4j
@Component
public class ConnectComponent {

    @Value("${easy-mq.baseURI}")
    private String BASE_URI;

    @Value("${spring.application.name}")
    private String SERVERNAME;

    @Value("${easy-mq.topics}")
    private String TOPICS;

    @Value("${easy-mq.connectFlag}")
    private Boolean connectFlag = Boolean.FALSE;

    @Autowired
    private EasyMQAllocation easyMQAllocation;

    private final Map<String, ConnectBase> connections = new ConcurrentHashMap<>();

    public String getBaseUri() {
        return "ws://" + BASE_URI + "/";
    }

    public Map<String, String> getConnectURIMap() {
        if (TOPICS.isEmpty()) {
            return new HashMap<>();
        }

        String[] topicArr = TOPICS.split(",");
        Map<String, String> map = new HashMap<>();
        for (String topic : topicArr) {
            if (topic.isEmpty()) {
                continue;
            }

            // 拼接连接地址
            String uri = getBaseUri() + topic + "/" + SERVERNAME;
            map.put(topic, uri);
        }

        return map;
    }

    @Bean
    public Map<String, ConnectBase> webSocketClients() {
        log.info("Initializing websocket connections with identifiers...");
        if (!connectFlag) {
            return connections;
        }

        Map<String, String> connectURIMap = getConnectURIMap();
        if (connectURIMap.isEmpty()) {
            return connections;
        }

        Set<String> keySet = connectURIMap.keySet();
        for (String topicName : keySet) {
            log.info("init websocket connect to : {}------------ ", connectURIMap.get(topicName));
            try {
                ListenerHandler listenerHandler;
                try {
                    String className = easyMQAllocation.getListeners().get(topicName);
                    Class<?> clazz = Class.forName(className);
                    listenerHandler = (ListenerHandler) clazz.getDeclaredConstructor().newInstance();
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException |
                         InvocationTargetException e) {
                    log.error("Failed to instantiate handler for topic: {}", topicName, e);
                    // 通过反射的方式获取失败,使用默认的
                    listenerHandler = new BaseListenerHandler();
                }
                ConnectBase webSocketClient = new ConnectBase(new URI(connectURIMap.get(topicName)), listenerHandler);
                webSocketClient.connect();
                connections.put(topicName, webSocketClient);
            } catch (URISyntaxException e) {
                throw new RuntimeException();
            }
        }
        return connections;
    }

}
3.在 resources/META-INF 目录下创建 spring.factories 文件

在这个文件中声明你的自动配置类。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.mao.easymq.entity.EasyMQAllocation,com.mao.easymq.connect.ConnectComponent

4.打包发布:

略 

如上就完成我们的一个自定义starter了

使用:

既然完成了封装,那么就要使用起来了,具体怎么使用呢,其实就和使用别的starter一样:

1.引入依赖:
<dependencies>
        <dependency>
            <groupId>com.mao</groupId>
            <artifactId>easymq-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
2.填写配置:
easy-mq:
  connectFlag: true
  baseURI: 127.0.0.1:12121/easyMQ
  topics: popupPb
  listeners:
    popupPb: com.mao.testStarter.all.PopUpListenerHandler
3.可能存在的一些别的操作:

比方说我这是需要去实现我的消息监听处理器处理消息:

@Slf4j
public class PopUpListenerHandler implements ListenerHandler {


    @Override
    public Boolean messageOperate(String msg) {
        log.info("使用自定义的监听处理器处理消息:{}", msg);
        return Boolean.TRUE;
    }
    
}

如上就结束了,可以直接启动项目进行测试了。

last:

实际的一个自定义starter,代码肯定不是上面展示的那么点,大家可以随便用一个小例子先尝试尝试,毕竟工作中你可以装菜,但是真让你上了你不能不会啊!

附上一个我的上面starter的git地址,里面还有对websocket的相关操作,感兴趣的可以去看看:

easymq-spring-boot-starter: easyMQ的springboot启动器

  • 18
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值