001/** 002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.jboot.aop; 017 018import com.jfinal.aop.Interceptor; 019import com.jfinal.kit.HashKit; 020import com.jfinal.kit.SyncWriteMap; 021 022import java.lang.reflect.Method; 023import java.util.Map; 024import java.util.Objects; 025 026public class InterceptorCache { 027 028 private static final Map<MethodKey, Interceptor[]> cache = new SyncWriteMap<>(2048, 0.25F); 029 030 public static void put(MethodKey methodKey, Interceptor[] inters) { 031 Objects.requireNonNull(methodKey, "methodKey can not be null"); 032 Objects.requireNonNull(inters, "inters can not be null"); 033 034 cache.putIfAbsent(methodKey, inters); 035 } 036 037 public static Interceptor[] get(MethodKey methodKey) { 038 return cache.get(methodKey); 039 } 040 041 public static MethodKey getMethodKey(Class<?> target, Method method) { 042 long paraHash = HashKit.FNV_OFFSET_BASIS_64; 043 Class<?>[] paraTypes = method.getParameterTypes(); 044 for (Class<?> pt : paraTypes) { 045 paraHash ^= pt.getName().hashCode(); 046 paraHash *= HashKit.FNV_PRIME_64; 047 } 048 049 return new MethodKey(target.getName().hashCode(), method.getName().hashCode(), paraHash); 050 } 051 052 public static void clear() { 053 cache.clear(); 054 } 055 056 057 public static class MethodKey { 058 final int classHash; 059 final int methodHash; 060 final long paraHash; 061 062 MethodKey(int classHash, int methodHash, long paraHash) { 063 this.classHash = classHash; 064 this.methodHash = methodHash; 065 this.paraHash = paraHash; 066 } 067 068 @Override 069 public int hashCode() { 070 return classHash ^ methodHash ^ ((int) paraHash); 071 } 072 073 /** 074 * 通过比较三部分 hash 值,避免超大规模场景下可能的 key 值碰撞 075 * <p> 076 * 不必判断 if (methodKey instanceof MethodKey),因为所有 key 类型必须要相同 077 * 不必判断 if (this == methodKey),因为每次用于取值的 methodKey 都是新建的 078 */ 079 @Override 080 public boolean equals(Object methodKey) { 081 MethodKey mk = (MethodKey) methodKey; 082 return mk != null && classHash == mk.classHash && methodHash == mk.methodHash && paraHash == mk.paraHash; 083 } 084 085 @Override 086 public String toString() { 087 return "classHash = " + classHash + "\nmethodHash = " + methodHash + "\nparaHash = " + paraHash; 088 } 089 } 090}