前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >利用Spring特性给接口添加注解式挡板和分布式锁

利用Spring特性给接口添加注解式挡板和分布式锁

原创
作者头像
leaforbook
发布2019-02-12 10:43:46
2.4K0
发布2019-02-12 10:43:46
举报
文章被收录于专栏:Spring Cloud

在很多实际场景中,需要给接口加上挡板和分布式锁。比如,最常见的定时任务,有时候需要通过配置决定这个定时任务是该运行还是该暂停,有时候开启了多个实例,但是在同一时刻只允许其中一个实例运行这个定时任务(防止相同数据被执行多次),这时候有一种解决方案就是给这个定时任务加上分布式锁。

因为这些场景在项目中很常见,所以不推荐把挡板和分布式锁的判断逻辑硬编码到业务逻辑中。所以希望通过一个接口级的注解达到这种效果,这样既减少了编码工作量,又统一了挡板和分布式锁的实现方法,减少出错的可能性。下面介绍利用Spring的AOP特性,给接口加上挡板和分布式锁。


1. 定义注解

首先要定义一个注解,这个注解命名为@Baffle。@Baffle注解属于方法级别,有三个属性:

  • allowed :这个属性决定方法是否允许被调用,默认是“Y”,只要属性值是Y,该方法就允许被调用,否则不允许被调用;
  • lock:这个属性是分布式锁的key。默认是"",如果属性值是"",就不加锁,否则就加上分布式锁;
  • name:给方法命名,方便日志跟踪。
代码语言:txt
复制
package com.leaforbook.common.annotation;

import java.lang.annotation.*;

@Documented
@Target({ ElementType.METHOD , ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Baffle {
    String allowed() default "Y";
    String lock() default "";
    String name() default "";
}

2.实现切面逻辑

下面是切面逻辑的实现,首先要指定切点——加了@Baffle注解的方法都是切点。然后在around方法中根据注解属性,实现挡板和分布式锁的逻辑。最后在after方法实现释放锁的逻辑。

切面逻辑实现以后,只要加上@Baffle注解,就可以自带挡板和分布式锁功能了。是不是非常方便?

代码语言:txt
复制
package com.leaforbook.common.aspect;

import com.github.pagehelper.util.StringUtil;
import com.leaforbook.common.annotation.Baffle;
import com.leaforbook.common.util.DistributedLock;
import com.leaforbook.common.util.SnowFlake;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Slf4j
public class BaffleAspect {

    @Autowired
    private Environment env;

    @Autowired
    private DistributedLock distributedLock;

    @Pointcut("@annotation(baffle)")
    public void bafflePointcut(Baffle baffle) {

    }

    @Before("bafflePointcut(baffle)")
    public void before(JoinPoint joinPoint, Baffle baffle) {

    }

    @Around("bafflePointcut(baffle)")
    public Object around(ProceedingJoinPoint joinPoint, Baffle baffle) throws Throwable {
        log.info(baffle.allowed()+" "+baffle.lock()+" before");
        String allowed = baffle.allowed();
        if(allowed.startsWith("${")&&allowed.endsWith("}")) {
            allowed = env.getProperty(allowed.substring(2,allowed.length()-1));
        }

        if(!"Y".equals(allowed)) {
            log.info("该方法已设置挡板:"+baffle.name());
            return null;
        }

        String lock = baffle.lock();
        if(lock.startsWith("${")&&lock.endsWith("}")) {
            lock = env.getProperty(lock.substring(2,lock.length()-1));
        }

        if(StringUtil.isNotEmpty(lock)) {
            boolean isSuccess = distributedLock.tryLock(lock);
            if(!isSuccess) {
                log.info("该方法已被其他线程锁定:"+baffle.name());
                return null;
            }
        }

        return joinPoint.proceed();
    }

    @After("bafflePointcut(baffle)")
    public void after(JoinPoint joinPoint, Baffle baffle) {
        log.info(baffle.allowed()+" "+baffle.lock()+" after");

        String lock = baffle.lock();
        if(lock.startsWith("${")&&lock.endsWith("}")) {
            lock = env.getProperty(lock.substring(2,lock.length()-1));
        }

        if(StringUtil.isNotEmpty(lock)) {
            distributedLock.unLock(lock);
        }
    }

}

BaffleAspect有两个成员变量:

  • Environment env :这个成员变量用于读取Spring的配置数据,让注解可以接受${}格式的数据,直接获取配置值。
  • DistributedLock distributedLock:分布式锁接口。具有加锁tryLock和释放锁unLock的功能。

3.分布式锁接口设计

下面是DistributedLock接口的内容:

代码语言:txt
复制
package com.leaforbook.common.util;

import org.springframework.stereotype.Component;

@Component
public interface DistributedLock {
    boolean tryLock(String key);
    void unLock(String key);
}

具体实现你可以根据自己的情况去实现。有人用Redis实现,有人用Zookeeper实现,有人用关系型数据库实现……超出本文范畴,不做介绍。


实质上,本文就是一种自定义方法级注解的实现过程。通过本文介绍的方法,可以实现很多有用的方法级注解,比如服务注册,日志记录……大家可以发挥自己的想象力,根据自己的业务场景,实现自定义注解。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 定义注解
  • 2.实现切面逻辑
  • 3.分布式锁接口设计
相关产品与服务
关系型数据库
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档