【Spring Boot】 Starter -- 个人开发一个redission-lock-starter并发布到公共仓库

本文介绍了SpringBoot的starter特性,如何通过添加依赖快速集成组件,并展示了自定义starter的开发步骤,包括整合Redisson、配置自动装配和发布到Maven仓库的过程。
摘要由CSDN通过智能技术生成

关于Starter

Spring Boot秉承“约定大于配置”的开发方式,使得我们基于Spring Boot开发项目的效率变得十分高。相信使用过Spring Boot的小伙伴都会发现,当我们要用到某个Spring提供的组件时,只需要在pom.xml文件中添加该组件的starter依赖就能集成到项目中。

例如,在pom.xml文件中添加spring-boot-starter-web依赖,就能让项目整合Spring MVC的功能。并且在最简使用下几乎不需要进行任何的配置,而以往想要集成Spring MVC,不仅要添加一堆类似于spring-webspring-webmvc等相关依赖包,以及完成许多繁杂的配置才能够实现集成。

这是因为starter里已经帮我们整合了各种依赖包,避免了依赖包缺失或依赖包之间出现版本冲突等问题。以及完成了许多基础配置和自动装配,让我们可以在最简使用下,跳过绝大部分的配置,从而达到开箱即用的效果。这也是Spring Boot实现“约定大于配置”的核心之一。


动手开发一个Starter

通过以上的描述,我们可以简单地将starter看作是对一个组件功能粒度较大的模块化封装,包括了所需依赖包的整合及基础配置和自动装配等。

除了Spring官方提供的starter外,我们自己也可以根据业务开发一个starter。例如,当项目积累到一定程度时,我们可以将一些通用功能下沉为一个starter。而开发一个starter也很简单,只需要以下步骤:

  1. 新建一个Maven项目,在pom.xml文件中定义好所需依赖;
  2. 新建配置类,写好配置项和默认值,使用@ConfigurationProperties指明配置项前缀;
  3. 新建自动装配类,使用@Configuration@Bean来进行自动装配;
  4. 新建spring.factories文件,用于指定自动装配类的路径;
  5. 将starter安装到maven仓库,让其他项目能够引用;

接下来,以封装一个用于操作redis的starter为例,一步步展示这些步骤的具体实现过程。首先是第一步,新建一个maven项目,完整的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.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.axin</groupId>
    <artifactId>spring-boot-redission-lock-starter</artifactId>
    <version>1.0.0</version>
    <name>spring-boot-redission-lock-starter</name>
    <description>Spring boot redission lock starter</description>

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

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

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

        <!-- https://mvnrepository.com/artifact/org.redisson/redisson-spring-boot-starter -->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.26.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.redisson</groupId>
                    <artifactId>redisson-spring-data-32</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-data-27</artifactId>
            <version>3.26.0</version>
        </dependency>

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

第二步,新建切面类RedissonDistributedLockAspectConfiguration,配置切面;

@Aspect
@Order(Ordered.LOWEST_PRECEDENCE - 1)
public class RedissonDistributedLockAspectConfiguration implements ApplicationContextAware {

    private final Logger logger = LoggerFactory.getLogger(RedissonDistributedLockAspectConfiguration.class);

    @Autowired
    private RedissonClient redissonClient;

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    private ExpressionParser parser = new SpelExpressionParser();

    private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();

    @Pointcut("@annotation(com.axin.redission.lock.LockAction)")
    private void lockPoint() {

    }

    @Around("lockPoint()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        Method method = ((MethodSignature) pjp.getSignature()).getMethod();
        LockAction lockAction = method.getAnnotation(LockAction.class);
        String key = lockAction.value();
        Object[] args = pjp.getArgs();
        key = parse(key, method, args);

        RLock lock = getLock(key, lockAction);
        if (!lock.tryLock(lockAction.waitTime(), lockAction.leaseTime(), lockAction.unit())) {
            logger.debug("get lock failed [{}]", key);
            return null;
        }

        //得到锁,执行方法,释放锁
        logger.debug("get lock success [{}]", key);
        try {
            return pjp.proceed();
        } catch (Exception e) {
            logger.error("execute locked method occured an exception", e);
        } finally {
            lock.unlock();
            logger.debug("release lock [{}]", key);
        }
        return null;
    }

    /**
     * @param key    表达式
     * @param method 方法
     * @param args   方法参数
     * @return
     * @description 解析spring EL表达式
     * @author handsometong
     * @date 2022年11月9日 上午10:41:01
     * @version 1.0.0
     */
    private String parse(String key, Method method, Object[] args) {
        String[] params = discoverer.getParameterNames(method);
        EvaluationContext context = new StandardEvaluationContext();
        for (int i = 0; i < params.length; i++) {
            context.setVariable(params[i], args[i]);
        }
        return applicationContext.getEnvironment().getProperty("spring.application.name").toUpperCase() + parser.parseExpression(key).getValue(context, String.class);
    }

    private RLock getLock(String key, LockAction lockAction) {
        switch (lockAction.lockType()) {
            case REENTRANT_LOCK:
                return redissonClient.getLock(key);
            case FAIR_LOCK:
                return redissonClient.getFairLock(key);
            case READ_LOCK:
                return redissonClient.getReadWriteLock(key).readLock();
            case WRITE_LOCK:
                return redissonClient.getReadWriteLock(key).writeLock();
            default:
                throw new RuntimeException("do not support lock type:" + lockAction.lockType().name());
        }
    }
}

第三步,在项目的resources目录下新建一个META-INF目录,并在该目录下新建spring.factories文件。如下图所示:
在这里插入图片描述

spring.factories文件里指定自动装配类的路径:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.axin.redission.RedissonDistributedLockAspectConfiguration

若需要指定多个自动装配类的路径,则使用逗号分隔。如下示例:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.axin.redission.autoconfigure.DemoConfiguration,\
  com.axin.redission.autoconfigure.RedissonDistributedLockAspectConfiguration

最后install这个maven项目,命令如下:

mvn clean install

如果使用的开发工具是IDEA的话就比较简单,只需要双击一下install即可:

在这里插入图片描述


使用Starter

在任意一个Spring Boot项目的pom.xml文件中添加如下依赖:

<dependency>
    <groupId>com.axin</groupId>
    <artifactId>spring-boot-redission-lock-starter</artifactId>
    <version>1.0.0</version>
 </dependency>

在项目的application.yml中添加如下配置项来覆盖默认配置,若默认配置已符合需求则可以省略这一步:

spring:
  redis:
    redisson:
      singleServerConfig:
        # 空闲链接超时
        idleConnectionTimeout: 10000
        # 链接超时
        connectTimeout: 10000
        timeout: 3000
        retryAttempts: 3
        retryInterval: 1500
        password: null
        subscriptionsPerConnection: 5
        clientName: null
        address: "redis://192.168.0.10:6379"
        # 最小空闲订阅连接数
        subscriptionConnectionMinimumIdleSize: 1
        # 订阅连接池大小
        subscriptionConnectionPoolSize: 50
        # 最小空闲连接数
        connectionMinimumIdleSize: 24
        connectionPoolSize: 64
        database: 0
        dnsMonitoringInterval: 5000
      threads: 16
      nettyThreads: 32
      codec: "!<org.redisson.codec.Kryo5Codec> {}"
      transportMode: "NIO"
      lockWatchdogTimeout: 1000

发布到公共仓库

  1. 首先把对应maven项目上传到gitee(或者GitHub)
  2. 打开https://www.jitpack.io/网站,输入对应项目的git地址

在这里插入图片描述

  1. 根据jitpack介绍,在项目中配置
<!-- 配置仓库 -->
  <repositories>
      <repository>
          <id>jitpack.io</id>
           <url>https://www.jitpack.io</url>
      </repository>
  </repositories>


  <dependencies>
        <dependency>
	    <groupId>com.gitee.sunsjgitee</groupId>
	    <artifactId>spring-boot-redission-lock-starter</artifactId>
	    <version>Tag</version>
	</dependency>
  <dependencies>


  1. 然后reload项目就可以了
  • 20
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

生如夏花般绚丽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值