APIJSON(十一:AbstractVerifier源码阅读(2))

APIJSON(十一:AbstractVerifier源码阅读(2))

2021SC@SDUSC

元素定义

类的一开始,当然还是一大堆的元素定义——

// 共享 STRUCTURE_MAP 则不能 remove 等做任何变更,否则在并发情况下可能会出错,加锁效率又低,所以这里改为忽略对应的 key
public static final Map<String, Entry<String, Object>> ROLE_MAP;

public static final List<String> OPERATION_KEY_LIST;

// <TableName, <METHOD, allowRoles>>
// <User, <GET, [OWNER, ADMIN]>>
@NotNull
public static final Map<String, Map<RequestMethod, String[]>> SYSTEM_ACCESS_MAP;
@NotNull
public static final Map<String, Map<RequestMethod, String[]>> ACCESS_MAP;

// <method tag, <version, Request>>
// <PUT Comment, <1, { "method":"PUT", "tag":"Comment", "structure":{ "MUST":"id"... }... }>>
@NotNull
public static final Map<String, SortedMap<Integer, JSONObject>> REQUEST_MAP;

// 正则匹配的别名快捷方式,例如用 "PHONE" 代替 "^((13[0-9])|(15[^4,\\D])|(18[0-2,5-9])|(17[0-9]))\\d{8}$"
@NotNull
public static final Map<String, Pattern> COMPILE_MAP;

map

这里大量使用了@NotNull的注解,申明其不能为空,以及map接口

Map是java中的接口,Map.Entry是Map的一个内部接口。

Map提供了一些常用方法,如keySet()、entrySet()等方法。

keySet()方法返回值是Map中key值的集合;entrySet()的返回值也是返回一个Set集合,此集合的类型为Map.Entry。

Map.Entry是Map声明的一个内部接口,此接口为泛型,定义为Entry<K,V>。它表示Map中的一个实体(一个key-value对)。接口中有getKey(),getValue方法。

接下来则是一个static块

static {
   ROLE_MAP = new LinkedHashMap<>();
   ROLE_MAP.put(UNKNOWN, new Entry<String, Object>());
   ROLE_MAP.put(LOGIN, new Entry<String, Object>("userId>", 0));
   ROLE_MAP.put(CONTACT, new Entry<String, Object>("userId{}", "contactIdList"));
   ROLE_MAP.put(CIRCLE, new Entry<String, Object>("userId-()", "verifyCircle()")); // "userId{}", "circleIdList"));  // 还是 {"userId":"currentUserId", "userId{}": "contactIdList", "@combine": "userId,userId{}" } ? 
   ROLE_MAP.put(OWNER, new Entry<String, Object>("userId", "userId"));
   ROLE_MAP.put(ADMIN, new Entry<String, Object>("userId-()", "verifyAdmin()"));
   
   OPERATION_KEY_LIST = new ArrayList<>();
   OPERATION_KEY_LIST.add(TYPE.name());
   OPERATION_KEY_LIST.add(VERIFY.name());
   OPERATION_KEY_LIST.add(INSERT.name());
   OPERATION_KEY_LIST.add(UPDATE.name());
   OPERATION_KEY_LIST.add(REPLACE.name());
   OPERATION_KEY_LIST.add(EXIST.name());
   OPERATION_KEY_LIST.add(UNIQUE.name());
   OPERATION_KEY_LIST.add(REMOVE.name());
   OPERATION_KEY_LIST.add(MUST.name());
   OPERATION_KEY_LIST.add(REFUSE.name());


   SYSTEM_ACCESS_MAP = new HashMap<String, Map<RequestMethod, String[]>>();

   SYSTEM_ACCESS_MAP.put(Access.class.getSimpleName(), getAccessMap(Access.class.getAnnotation(MethodAccess.class)));
   SYSTEM_ACCESS_MAP.put(Function.class.getSimpleName(), getAccessMap(Function.class.getAnnotation(MethodAccess.class)));
   SYSTEM_ACCESS_MAP.put(Request.class.getSimpleName(), getAccessMap(Request.class.getAnnotation(MethodAccess.class)));
   SYSTEM_ACCESS_MAP.put(Response.class.getSimpleName(), getAccessMap(Response.class.getAnnotation(MethodAccess.class)));

   if (Log.DEBUG) {
      SYSTEM_ACCESS_MAP.put(Table.class.getSimpleName(), getAccessMap(Table.class.getAnnotation(MethodAccess.class)));
      SYSTEM_ACCESS_MAP.put(Column.class.getSimpleName(), getAccessMap(Column.class.getAnnotation(MethodAccess.class)));
      SYSTEM_ACCESS_MAP.put(PgAttribute.class.getSimpleName(), getAccessMap(PgAttribute.class.getAnnotation(MethodAccess.class)));
      SYSTEM_ACCESS_MAP.put(PgClass.class.getSimpleName(), getAccessMap(PgClass.class.getAnnotation(MethodAccess.class)));
      SYSTEM_ACCESS_MAP.put(SysTable.class.getSimpleName(), getAccessMap(SysTable.class.getAnnotation(MethodAccess.class)));
      SYSTEM_ACCESS_MAP.put(SysColumn.class.getSimpleName(), getAccessMap(SysColumn.class.getAnnotation(MethodAccess.class)));
      SYSTEM_ACCESS_MAP.put(ExtendedProperty.class.getSimpleName(), getAccessMap(ExtendedProperty.class.getAnnotation(MethodAccess.class)));

      SYSTEM_ACCESS_MAP.put(Document.class.getSimpleName(), getAccessMap(Document.class.getAnnotation(MethodAccess.class)));
      SYSTEM_ACCESS_MAP.put(TestRecord.class.getSimpleName(), getAccessMap(TestRecord.class.getAnnotation(MethodAccess.class)));
   }

   ACCESS_MAP = new HashMap<>(SYSTEM_ACCESS_MAP);

   REQUEST_MAP = new HashMap<>(ACCESS_MAP.size()*6);  // 单个与批量增删改

   COMPILE_MAP = new HashMap<String, Pattern>();
}

static{}

概念解释

1、 类加载的特性
在JVM的生命周期里,每个类只会被加载一次。

类加载的原则:延迟加载,能少加载就少加载,因为虚拟机的空间是有限的。

2、 类加载的时机
1)第一次创建对象要加载类.

2)调用静态方法时要加载类,访问静态属性时会加载类。

3)加载子类时必定会先加载父类。

4)创建对象引用不加载类.

  1. 子类调用父类的静态方法时

​ (1)当子类没有覆盖父类的静态方法时,只加载父类,不加载子类

​ (2)当子类有覆盖父类的静态方法时,既加载父类,又加载子类

6)访问静态常量,如果编译器可以计算出常量的值,则不会加载类,例如:public static final int a =123;否则会加载类,例如:public static final int a = math.PI。

静态块(static{})
(1) static关键字还有一个比较关键的作用,用来形成静态代码块(static{}(即static块))以优化程序性能。

(2) static块可以置于类中的任何地方,类中可以有多个static块。

(3) 在类初次被加载的时候执行且仅会被执行一次(这是优化性能的原因!!!),会按照static块的顺序来执行每个static块,一般用来初始化静态变量和调用静态方法。
否则每当调用方法时,都会生成这些成员对象,造成空间的浪费。

LinkedHashMap

ROLE_MAP = new LinkedHashMap<>();

首先可以看到先创建了一个LinkedHashMap的对象

本质上,LinkedHashMap = HashMap + 双向链表,也就是说,HashMap和双向链表合二为一即是LinkedHashMap。也可以这样理解,LinkedHashMap 在不对HashMap做任何改变的基础上,给HashMap的任意两个节点间加了两条连线(before指针和after指针),使这些节点形成一个双向链表。在LinkedHashMapMap中,所有put进来的Entry都保存在HashMap中,但由于它又额外定义了一个以head为头结点的空的双向链表,因此对于每次put进来Entry还会将其插入到双向链表的尾部。
这里写图片描述

而其中大量使用的put方法就是给LinkedHashMap添加键值对的方法。具体可参考如下文章:

Map 综述(一):彻头彻尾理解 HashMap

Map 综述(二):彻头彻尾理解 LinkedHashMap

List

public static final List<String> OPERATION_KEY_LIST;

List 是一个接口,它继承于Collection的接口。它代表着有序的队列。

List中元素可以重复,并且是有序的(这里的有序指的是按照放入的顺序进行存储。如按照顺序把1,2,3存入List,那么,从List中遍历出来的顺序也是1,2,3)。

void add(int index, E element)

在指定位置插入元素,后面的元素都往后移一个元素。

img

实现的方法

getAccessMap

public static HashMap<RequestMethod, String[]> getAccessMap(MethodAccess access)

注意到getAccessMap传入的值是MethodAccess类

public @interface MethodAccess

这就是MethodAccess的类的定义,发现用了看起来很奇怪的@interface

java 中@interface 和interface 的区别

什么是java Annotation
Java 从1.5开始提供了 Annotation (注释,标注),它用来修饰应用程序的元素(类,方法,属性,参数,本地变量,包、元数据),编译器将其与元数据一同存储在 class 文件中,运行期间通过 Java 的反射来处理对其修饰元素的访问。Annotation 仅仅用来修饰元素,而不能影响代码的执行。只有通过其配套的框架或工具才能对其信息进行访问和处理。

区别

①、interface :声明了这是一个java 的接口

②、@interface : 是用来修饰 Annotation 的,请注意,它不是 interface。这个关键字声明隐含了一个信息:它是继承了 java.lang.annotation.Annotation 接口,而不是声明了一个 interface。

这其中主要对请求方法的权限做了定义,只允许某些角色通过对应方法访问数据库。

比如说get方法,默认允许的角色UNKNOWN, LOGIN, CONTACT, CIRCLE, OWNER, ADMIN;

String[] GET() default {UNKNOWN, LOGIN, CONTACT, CIRCLE, OWNER, ADMIN};

可以发现这些方法的权限是从低到高的,POST、PUT、DELETE方法只默认允许OWNER,或ADMIN进行使用

String[] GET() default {UNKNOWN, LOGIN, CONTACT, CIRCLE, OWNER, ADMIN};

String[] HEAD() default {UNKNOWN, LOGIN, CONTACT, CIRCLE, OWNER, ADMIN};

String[] GETS() default {LOGIN, CONTACT, CIRCLE, OWNER, ADMIN};

String[] HEADS() default {LOGIN, CONTACT, CIRCLE, OWNER, ADMIN};

String[] POST() default {OWNER, ADMIN};

String[] PUT() default {OWNER, ADMIN};

String[] DELETE() default {OWNER, ADMIN};

重新到我们的getAcessMap方法,它就是用来获取这些权限Map的。

if (access == null) {
   return null;
}

HashMap<RequestMethod, String[]> map = new HashMap<>();
map.put(GET, access.GET());
map.put(HEAD, access.HEAD());
map.put(GETS, access.GETS());
map.put(HEADS, access.HEADS());
map.put(POST, access.POST());
map.put(PUT, access.PUT());
map.put(DELETE, access.DELETE());
return map;

put(GET, access.GET());
map.put(HEAD, access.HEAD());
map.put(GETS, access.GETS());
map.put(HEADS, access.HEADS());
map.put(POST, access.POST());
map.put(PUT, access.PUT());
map.put(DELETE, access.DELETE());
return map;


它首先进行判断access是否为空,不是的话,就会创建一个HashMap对这些权限进行依次存储,并返回这个HashMap。

猜你喜欢

转载自blog.csdn.net/qq_50861917/article/details/121878897