序
本文主要研究一下JetCacheProxyConfiguration
JetCacheProxyConfiguration
com/alicp/jetcache/anno/config/JetCacheProxyConfiguration.java
@Configuration
public class JetCacheProxyConfiguration implements ImportAware, ApplicationContextAware {
protected AnnotationAttributes enableMethodCache;
private ApplicationContext applicationContext;
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
this.enableMethodCache = AnnotationAttributes.fromMap(
importMetadata.getAnnotationAttributes(EnableMethodCache.class.getName(), false));
if (this.enableMethodCache == null) {
throw new IllegalArgumentException(
"@EnableMethodCache is not present on importing class " + importMetadata.getClassName());
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Bean(name = CacheAdvisor.CACHE_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public CacheAdvisor jetcacheAdvisor(JetCacheInterceptor jetCacheInterceptor) {
CacheAdvisor advisor = new CacheAdvisor();
advisor.setAdviceBeanName(CacheAdvisor.CACHE_ADVISOR_BEAN_NAME);
advisor.setAdvice(jetCacheInterceptor);
advisor.setBasePackages(this.enableMethodCache.getStringArray("basePackages"));
advisor.setOrder(this.enableMethodCache.<Integer>getNumber("order"));
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public JetCacheInterceptor jetCacheInterceptor() {
return new JetCacheInterceptor();
}
}
JetCacheProxyConfiguration定义了JetCacheInterceptor、CacheAdvisor
JetCacheInterceptor
com/alicp/jetcache/anno/aop/JetCacheInterceptor.java
public class JetCacheInterceptor implements MethodInterceptor, ApplicationContextAware {
private static final Logger logger = LoggerFactory.getLogger(JetCacheInterceptor.class);
@Autowired
private ConfigMap cacheConfigMap;
private ApplicationContext applicationContext;
private GlobalCacheConfig globalCacheConfig;
ConfigProvider configProvider;
CacheManager cacheManager;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
if (configProvider == null) {
configProvider = applicationContext.getBean(ConfigProvider.class);
}
if (configProvider != null && globalCacheConfig == null) {
globalCacheConfig = configProvider.getGlobalCacheConfig();
}
if (globalCacheConfig == null || !globalCacheConfig.isEnableMethodCache()) {
return invocation.proceed();
}
if (cacheManager == null) {
cacheManager = applicationContext.getBean(CacheManager.class);
if (cacheManager == null) {
logger.error("There is no cache manager instance in spring context");
return invocation.proceed();
}
}
Method method = invocation.getMethod();
Object obj = invocation.getThis();
CacheInvokeConfig cac = null;
if (obj != null) {
String key = CachePointcut.getKey(method, obj.getClass());
cac = cacheConfigMap.getByMethodInfo(key);
}
/*
if(logger.isTraceEnabled()){
logger.trace("JetCacheInterceptor invoke. foundJetCacheConfig={}, method={}.{}(), targetClass={}",
cac != null,
method.getDeclaringClass().getName(),
method.getName(),
invocation.getThis() == null ? null : invocation.getThis().getClass().getName());
}
*/
if (cac == null || cac == CacheInvokeConfig.getNoCacheInvokeConfigInstance()) {
return invocation.proceed();
}
CacheInvokeContext context = configProvider.newContext(cacheManager).createCacheInvokeContext(cacheConfigMap);
context.setTargetObject(invocation.getThis());
context.setInvoker(invocation::proceed);
context.setMethod(method);
context.setArgs(invocation.getArguments());
context.setCacheInvokeConfig(cac);
context.setHiddenPackages(globalCacheConfig.getHiddenPackages());
return CacheHandler.invoke(context);
}
public void setCacheConfigMap(ConfigMap cacheConfigMap) {
this.cacheConfigMap = cacheConfigMap;
}
}
JetCacheInterceptor实现了aop的MethodInterceptor方法,其invoke方法先从spring中获取configProvider、globalCacheConfig,若globalCacheConfig为null或者是没有开启methodCache,则直接执行invocation.proceed(),否则获取cacheManager,然后从invocation获取key,从cacheConfigMap找到对应的CacheInvokeConfig,若为null则执行invocation.proceed(),否则通过configProvider.newContext(cacheManager).createCacheInvokeContext(cacheConfigMap)创建CacheInvokeContext,执行CacheHandler.invoke(context)
CacheHandler.invoke
com/alicp/jetcache/anno/method/CacheHandler.java
public static Object invoke(CacheInvokeContext context) throws Throwable {
if (context.getCacheInvokeConfig().isEnableCacheContext()) {
try {
CacheContextSupport._enable();
return doInvoke(context);
} finally {
CacheContextSupport._disable();
}
} else {
return doInvoke(context);
}
}
private static Object doInvoke(CacheInvokeContext context) throws Throwable {
CacheInvokeConfig cic = context.getCacheInvokeConfig();
CachedAnnoConfig cachedConfig = cic.getCachedAnnoConfig();
if (cachedConfig != null && (cachedConfig.isEnabled() || CacheContextSupport._isEnabled())) {
return invokeWithCached(context);
} else if (cic.getInvalidateAnnoConfigs() != null || cic.getUpdateAnnoConfig() != null) {
return invokeWithInvalidateOrUpdate(context);
} else {
return invokeOrigin(context);
}
}
private static Object invokeOrigin(CacheInvokeContext context) throws Throwable {
return context.getInvoker().invoke();
}
CacheHandler的invoke方法主要是执行doInvoke,它根据配置判断是走invokeWithCached、invokeWithInvalidateOrUpdate还是invokeOrigin
invokeWithCached
private static Object invokeWithCached(CacheInvokeContext context)
throws Throwable {
CacheInvokeConfig cic = context.getCacheInvokeConfig();
CachedAnnoConfig cac = cic.getCachedAnnoConfig();
Cache cache = context.getCacheFunction().apply(context, cac);
if (cache == null) {
logger.error("no cache with name: " + context.getMethod());
return invokeOrigin(context);
}
Object key = ExpressionUtil.evalKey(context, cic.getCachedAnnoConfig());
if (key == null) {
return loadAndCount(context, cache, key);
}
if (!ExpressionUtil.evalCondition(context, cic.getCachedAnnoConfig())) {
return loadAndCount(context, cache, key);
}
try {
CacheLoader loader = new CacheLoader() {
@Override
public Object load(Object k) throws Throwable {
Object result = invokeOrigin(context);
context.setResult(result);
return result;
}
@Override
public boolean vetoCacheUpdate() {
return !ExpressionUtil.evalPostCondition(context, cic.getCachedAnnoConfig());
}
};
Object result = cache.computeIfAbsent(key, loader);
return result;
} catch (CacheInvokeException e) {
throw e.getCause();
}
}
invokeWithCached先获取key,若key为null或者不满足表达式则执行loadAndCount,否则执行cache.computeIfAbsent(key, loader)
loadAndCount
private static Object loadAndCount(CacheInvokeContext context, Cache cache, Object key) throws Throwable {
long t = System.currentTimeMillis();
Object v = null;
boolean success = false;
try {
v = invokeOrigin(context);
success = true;
} finally {
t = System.currentTimeMillis() - t;
CacheLoadEvent event = new CacheLoadEvent(cache, t, key, v, success);
while (cache instanceof ProxyCache) {
cache = ((ProxyCache) cache).getTargetCache();
}
if (cache instanceof AbstractCache) {
((AbstractCache) cache).notify(event);
}
}
return v;
}
loadAndCount主要是执行invokeOrigin,然后发布CacheLoadEvent事件
invokeWithInvalidateOrUpdate
private static Object invokeWithInvalidateOrUpdate(CacheInvokeContext context) throws Throwable {
Object originResult = invokeOrigin(context);
context.setResult(originResult);
CacheInvokeConfig cic = context.getCacheInvokeConfig();
if (cic.getInvalidateAnnoConfigs() != null) {
doInvalidate(context, cic.getInvalidateAnnoConfigs());
}
CacheUpdateAnnoConfig updateAnnoConfig = cic.getUpdateAnnoConfig();
if (updateAnnoConfig != null) {
doUpdate(context, updateAnnoConfig);
}
return originResult;
}
invokeWithInvalidateOrUpdate先执行invokeOrigin,然后根据判断执行doInvalidate或者doUpdate
CacheFunction
CacheInvokeContext
com/alicp/jetcache/anno/method/CacheInvokeContext.java
private BiFunction<CacheInvokeContext, CacheAnnoConfig, Cache> cacheFunction;
public void setCacheFunction(BiFunction<CacheInvokeContext, CacheAnnoConfig, Cache> cacheFunction) {
this.cacheFunction = cacheFunction;
}
public BiFunction<CacheInvokeContext, CacheAnnoConfig, Cache> getCacheFunction() {
return cacheFunction;
}
CacheInvokeContext定义了cacheFunction,是一个BiFunction,第一个参数为CacheInvokeContext,第二个参数为CacheAnnoConfig,返回类型为Cache
createCacheInvokeContext
com/alicp/jetcache/anno/support/CacheContext.java
public CacheInvokeContext createCacheInvokeContext(ConfigMap configMap) {
CacheInvokeContext c = newCacheInvokeContext();
c.setCacheFunction((cic, cac) -> createOrGetCache(cic, cac, configMap));
return c;
}
protected CacheInvokeContext newCacheInvokeContext() {
return new CacheInvokeContext();
}
private Cache createOrGetCache(CacheInvokeContext invokeContext, CacheAnnoConfig cacheAnnoConfig, ConfigMap configMap) {
Cache cache = cacheAnnoConfig.getCache();
if (cache != null) {
return cache;
}
if (cacheAnnoConfig instanceof CachedAnnoConfig) {
cache = createCacheByCachedConfig((CachedAnnoConfig) cacheAnnoConfig, invokeContext);
} else if ((cacheAnnoConfig instanceof CacheInvalidateAnnoConfig) || (cacheAnnoConfig instanceof CacheUpdateAnnoConfig)) {
cache = cacheManager.getCache(cacheAnnoConfig.getArea(), cacheAnnoConfig.getName());
if (cache == null) {
CachedAnnoConfig cac = configMap.getByCacheName(cacheAnnoConfig.getArea(), cacheAnnoConfig.getName());
if (cac == null) {
String message = "can't find cache definition with area=" + cacheAnnoConfig.getArea()
+ " name=" + cacheAnnoConfig.getName() +
", specified in " + cacheAnnoConfig.getDefineMethod();
CacheConfigException e = new CacheConfigException(message);
logger.error("Cache operation aborted because can't find cached definition", e);
return null;
}
cache = createCacheByCachedConfig(cac, invokeContext);
}
}
cacheAnnoConfig.setCache(cache);
return cache;
}
private Cache createCacheByCachedConfig(CachedAnnoConfig ac, CacheInvokeContext invokeContext) {
String area = ac.getArea();
String cacheName = ac.getName();
if (CacheConsts.isUndefined(cacheName)) {
cacheName = configProvider.createCacheNameGenerator(invokeContext.getHiddenPackages())
.generateCacheName(invokeContext.getMethod(), invokeContext.getTargetObject());
}
Cache cache = __createOrGetCache(ac, area, cacheName);
return cache;
}
public Cache __createOrGetCache(CachedAnnoConfig cac, String area, String cacheName) {
QuickConfig.Builder b = QuickConfig.newBuilder(area, cacheName);
TimeUnit timeUnit = cac.getTimeUnit();
if (cac.getExpire() > 0) {
b.expire(Duration.ofMillis(timeUnit.toMillis(cac.getExpire())));
}
if (cac.getLocalExpire() > 0) {
b.localExpire(Duration.ofMillis(timeUnit.toMillis(cac.getLocalExpire())));
}
if (cac.getLocalLimit() > 0) {
b.localLimit(cac.getLocalLimit());
}
b.cacheType(cac.getCacheType());
b.syncLocal(cac.isSyncLocal());
if (!CacheConsts.isUndefined(cac.getKeyConvertor())) {
b.keyConvertor(configProvider.parseKeyConvertor(cac.getKeyConvertor()));
}
if (!CacheConsts.isUndefined(cac.getSerialPolicy())) {
b.valueEncoder(configProvider.parseValueEncoder(cac.getSerialPolicy()));
b.valueDecoder(configProvider.parseValueDecoder(cac.getSerialPolicy()));
}
b.cacheNullValue(cac.isCacheNullValue());
b.useAreaInPrefix(globalCacheConfig.isAreaInCacheName());
PenetrationProtectConfig ppc = cac.getPenetrationProtectConfig();
if (ppc != null) {
b.penetrationProtect(ppc.isPenetrationProtect());
b.penetrationProtectTimeout(ppc.getPenetrationProtectTimeout());
}
b.refreshPolicy(cac.getRefreshPolicy());
return cacheManager.getOrCreateCache(b.build());
}
createCacheInvokeContext方法会设置cacheFunction为(cic, cac) -> createOrGetCache(cic, cac, configMap),通过createOrGetCache来创建或者获取Cache;createOrGetCache从cacheAnnoConfig.getCache()获取Cache,不为null则返回,为null则通过createCacheByCachedConfig来创建,其最后是创建QuickConfig,然后通过cacheManager.getOrCreateCache(b.build())来创建Cache
CacheAdvisor
com/alicp/jetcache/anno/aop/CacheAdvisor.java
public class CacheAdvisor extends AbstractBeanFactoryPointcutAdvisor {
public static final String CACHE_ADVISOR_BEAN_NAME = "jetcache2.internalCacheAdvisor";
@Autowired
private ConfigMap cacheConfigMap;
private String[] basePackages;
@Override
public Pointcut getPointcut() {
CachePointcut pointcut = new CachePointcut(basePackages);
pointcut.setCacheConfigMap(cacheConfigMap);
return pointcut;
}
public void setCacheConfigMap(ConfigMap cacheConfigMap) {
this.cacheConfigMap = cacheConfigMap;
}
public void setBasePackages(String[] basePackages) {
this.basePackages = basePackages;
}
}
CacheAdvisor继承了spring的AbstractBeanFactoryPointcutAdvisor,其getPointcut返回的是CachePointcut
CachePointcut
com/alicp/jetcache/anno/aop/CachePointcut.java
public class CachePointcut extends StaticMethodMatcherPointcut implements ClassFilter {
private static final Logger logger = LoggerFactory.getLogger(CachePointcut.class);
private ConfigMap cacheConfigMap;
private String[] basePackages;
public CachePointcut(String[] basePackages) {
setClassFilter(this);
this.basePackages = basePackages;
}
@Override
public boolean matches(Class clazz) {
boolean b = matchesImpl(clazz);
logger.trace("check class match {}: {}", b, clazz);
return b;
}
private boolean matchesImpl(Class clazz) {
if (matchesThis(clazz)) {
return true;
}
Class[] cs = clazz.getInterfaces();
if (cs != null) {
for (Class c : cs) {
if (matchesImpl(c)) {
return true;
}
}
}
if (!clazz.isInterface()) {
Class sp = clazz.getSuperclass();
if (sp != null && matchesImpl(sp)) {
return true;
}
}
return false;
}
public boolean matchesThis(Class clazz) {
String name = clazz.getName();
if (exclude(name)) {
return false;
}
return include(name);
}
private boolean include(String name) {
if (basePackages != null) {
for (String p : basePackages) {
if (name.startsWith(p)) {
return true;
}
}
}
return false;
}
private boolean exclude(String name) {
if (name.startsWith("java")) {
return true;
}
if (name.startsWith("org.springframework")) {
return true;
}
if (name.indexOf("$$EnhancerBySpringCGLIB$$") >= 0) {
return true;
}
if (name.indexOf("$$FastClassBySpringCGLIB$$") >= 0) {
return true;
}
return false;
}
@Override
public boolean matches(Method method, Class targetClass) {
boolean b = matchesImpl(method, targetClass);
if (b) {
if (logger.isDebugEnabled()) {
logger.debug("check method match true: method={}, declaringClass={}, targetClass={}",
method.getName(),
ClassUtil.getShortClassName(method.getDeclaringClass().getName()),
targetClass == null ? null : ClassUtil.getShortClassName(targetClass.getName()));
}
} else {
if (logger.isTraceEnabled()) {
logger.trace("check method match false: method={}, declaringClass={}, targetClass={}",
method.getName(),
ClassUtil.getShortClassName(method.getDeclaringClass().getName()),
targetClass == null ? null : ClassUtil.getShortClassName(targetClass.getName()));
}
}
return b;
}
private boolean matchesImpl(Method method, Class targetClass) {
if (!matchesThis(method.getDeclaringClass())) {
return false;
}
if (exclude(targetClass.getName())) {
return false;
}
String key = getKey(method, targetClass);
CacheInvokeConfig cac = cacheConfigMap.getByMethodInfo(key);
if (cac == CacheInvokeConfig.getNoCacheInvokeConfigInstance()) {
return false;
} else if (cac != null) {
return true;
} else {
cac = new CacheInvokeConfig();
CacheConfigUtil.parse(cac, method);
String name = method.getName();
Class<?>[] paramTypes = method.getParameterTypes();
parseByTargetClass(cac, targetClass, name, paramTypes);
if (!cac.isEnableCacheContext() && cac.getCachedAnnoConfig() == null &&
cac.getInvalidateAnnoConfigs() == null && cac.getUpdateAnnoConfig() == null) {
cacheConfigMap.putByMethodInfo(key, CacheInvokeConfig.getNoCacheInvokeConfigInstance());
return false;
} else {
cacheConfigMap.putByMethodInfo(key, cac);
return true;
}
}
}
public static String getKey(Method method, Class targetClass) {
StringBuilder sb = new StringBuilder();
sb.append(method.getDeclaringClass().getName());
sb.append('.');
sb.append(method.getName());
sb.append(Type.getMethodDescriptor(method));
if (targetClass != null) {
sb.append('_');
sb.append(targetClass.getName());
}
return sb.toString();
}
private void parseByTargetClass(CacheInvokeConfig cac, Class<?> clazz, String name, Class<?>[] paramTypes) {
if (!clazz.isInterface() && clazz.getSuperclass() != null) {
parseByTargetClass(cac, clazz.getSuperclass(), name, paramTypes);
}
Class<?>[] intfs = clazz.getInterfaces();
for (Class<?> it : intfs) {
parseByTargetClass(cac, it, name, paramTypes);
}
boolean matchThis = matchesThis(clazz);
if (matchThis) {
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (methodMatch(name, method, paramTypes)) {
CacheConfigUtil.parse(cac, method);
break;
}
}
}
}
private boolean methodMatch(String name, Method method, Class<?>[] paramTypes) {
if (!Modifier.isPublic(method.getModifiers())) {
return false;
}
if (!name.equals(method.getName())) {
return false;
}
Class<?>[] ps = method.getParameterTypes();
if (ps.length != paramTypes.length) {
return false;
}
for (int i = 0; i < ps.length; i++) {
if (!ps[i].equals(paramTypes[i])) {
return false;
}
}
return true;
}
public void setCacheConfigMap(ConfigMap cacheConfigMap) {
this.cacheConfigMap = cacheConfigMap;
}
}
CachePointcut继承了spring的StaticMethodMatcherPointcut,其matches方法委托给了matchesImpl,它主要是通过cacheConfigMap.getByMethodInfo(key)来获取CacheInvokeConfig,如果是noCacheInvokeConfigInstance则返回false,若不为null则返回true,若为null则创建CacheInvokeConfig维护到cacheConfigMap中
CommonConfiguration
com/alicp/jetcache/anno/config/CommonConfiguration.java
@Configuration
public class CommonConfiguration {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public ConfigMap jetcacheConfigMap() {
return new ConfigMap();
}
}
CommonConfiguration创建ConfigMap实例
小结
JetCacheProxyConfiguration主要是定义了JetCacheInterceptor、CacheAdvisor,其中JetCacheInterceptor实现了aop的MethodInterceptor方法,其invoke方法主要是通过configProvider.newContext(cacheManager).createCacheInvokeContext(cacheConfigMap)创建CacheInvokeContext,执行CacheHandler.invoke(context)通过context.getCacheFunction().apply(context, cac)获取com.alicp.jetcache.Cache,然后进行相关操作
;CachePointcut继承了spring的StaticMethodMatcherPointcut,其matches方法委托给了matchesImpl,它主要是通过cacheConfigMap.getByMethodInfo(key)来获取CacheInvokeConfig,如果是noCacheInvokeConfigInstance则返回false,若不为null则返回true,若为null则创建CacheInvokeConfig维护到cacheConfigMap中。