the conditions of distributed lock

distributed lock要满足的四个条件:

  • 互斥性。在任意时刻,只有一个客户端能持有锁。
  • 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
  • 具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。
  • 解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。

the core of distributed lock

distributed lock的本质是将lock丢到一个third part进行管理, 所有的Client都对third part进行监听. 只有当lock不存在或被释放时, Client才能够获取lock. 同时要注意设置lock的expired time, 防止deadlock发生. 下图是architecture示意图

architecture

three different realizations of distributed lock

distributed lock有三种不同的实现方式, 分别是:

the comparation of three methods

  • 从理解的难易程度角度(low to high): 数据库 > redis > Zookeeper
  • 从实现的复杂性角度(low to high): 数据库 > redis >= Zookeeper
  • 从性能角度(high to low): redis > Zookeeper >= 数据库
  • 从可靠性角度(high to low): Zookeeper > redis > 数据库

references


type of Annotation

根据注解参数的个数, 分为三类:

  • 标记注解. 一个没有成员定义的Annotation类型被称为标记注解. 这种Annotation类型仅使用自身的存在与否来为我们提供信息. 比如后面的系统注解@Override
  • 单值注解
  • 完整注解 

根据注解使用方法和用途, 分为三类:

  • JDK内置系统注解
  • 元注解
  • 自定义注解

annotion in JDK

  • @Override: 用于修饰此方法覆盖了父类的方法
  • @Deprecated: 用于修饰已经过时的方法
  • @SuppressWarnnings: 用于通知java编译器禁止特定的编译警告

meta annotion

元注解的作用就是负责注解其他注解. Java5.0定义了4个标准的meta-annotation类型, 它们被用来提供对其它annotation类型作说明

@Target表示该注解用于什么地方

  • ElemenetType.CONSTRUCTOR 构造器声明
  • ElemenetType.FIELD 域声明(包括enum实例)
  • ElemenetType.LOCAL_VARIABLE 局部变量声明
  • ElemenetType.METHOD 方法声明
  • ElemenetType.PACKAGE 包声明
  • ElemenetType.PARAMETER 参数声明
  • ElemenetType.TYPE 类, 接口(包括注解类型)或enum声明

@Retention表示在什么级别保存该注解信息. 可选的 RetentionPolicy 参数包括:

  • RetentionPolicy.SOURCE 注解将被编译器丢弃
  • RetentionPolicy.CLASS 注解在class文件中可用, 但会被VM丢弃
  • RetentionPolicy.RUNTIME VM 将在运行期也保留注释, 因此可以通过反射机制读取注解的信息.

@Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API, 因此可以被例如javadoc此类的工具文档化

@Inherited元注解是一个标记注解, @Inherited阐述了某个被标注的类型是被继承的

self-defined annotion

定义注解格式

public @interface 注解名 {定义体}

其中的每一个方法实际上是声明了一个配置参数. 方法的名称就是参数的名称, 返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum). 可以通过default来声明参数的默认值.

注: 使用@interface自定义注解时, 自动继承了java.lang.annotation.Annotation接口, 由编译程序自动完成其他细节. 在定义注解时, 不能继承其他的注解或接口

可支持的数据类型

  • 所有基本数据类型(int,float,boolean,byte,double,char,long,short)
  • String类型
  • Class类型
  • enum类型
  • Annotation类型
  • 以上所有类型的数组

annotion example

@Target({ ElementType.FIELD, ElementType.LOCAL_VARIABLE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TemplateField {
    String value() default "";
}

annotion resolver

当实现一个注解, 若没有与之相关的处理器, 那么该注解就无异于注释, 而注解的处理就需要用到反射机制中的AnnotatedElement接口

实现AnnotatedElement接口的类

AnnotatedElement接口代表程序中可以接受注解的程序元素,该接口主要有如下几个实现类:

  • Class: 类定义
  • Constructor: 构造器定义
  • Field: 累的成员变量定义
  • Method: 类的方法定义
  • Package: 类的包定义

AnnotatedElement接口的方法

  • 方法1: <T extends Annotation> T getAnnotation(Class<T> annotationClass): 返回改程序元素上存在的、指定类型的注解, 如果该类型注解不存在, 则返回null.
  • 方法2: Annotation[] getAnnotations():返回该程序元素上存在的所有注解.
  • 方法3: boolean is AnnotationPresent(Class<?extends Annotation> annotationClass):判断该程序元素上是否包含指定类型的注解, 存在则返回true, 否则返回false.
  • 方法4: Annotation[] getDeclaredAnnotations(): 返回直接存在于此元素上的所有注释. 与此接口中的其他方法不同, 该方法将忽略继承的注释. (如果没有注释直接存在于此元素上, 则返回长度为零的一个数组. )该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响.

annotion resolver example

//利用反射,将实体中含有注解的field转化一个dataMap
protected Map<String, Object> resloverClass(Object object){
    Map<String, Object> data = new HashMap();
    try{
        Class clazz = object.getClass();
        for (Field field : clazz.getDeclaredFields()){
            if (field.isAnnotationPresent(TemplateField.class)){
                String methodName = "get" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1);
                Method method = clazz.getMethod(methodName);
                TemplateField templateField = field.getAnnotation(TemplateField.class);
                data.put(templateField.value(), method.invoke(object));
            }
        }
    } catch (Exception e){
        FactoryException factoryException = new FactoryException(e.getMessage());
        logger.error(factoryException.getMessage());
    }
    return data;
}

about self-defined annotion in application

  1. 对于每个URI进行权限控制, 在controller的每个request上加入这种注解, 写一个自定义拦截器, 在请求处理前进行权限的判断

  2. 结合spring aop的特性, 在service执行某个方法前后去执行自定义注解的相关方法

以上两者是从两个不同的方面进行运用, 一个是spring mvc, 另一个是spring data

references