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)当子类没有覆盖父类的静态方法时,只加载父类,不加载子类
(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 综述(二):彻头彻尾理解 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)
在指定位置插入元素,后面的元素都往后移一个元素。
实现的方法
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。