fun.fengwk.convention4j.springboot.starter.cache.registry.DefaultCacheManagerRegistry Maven / Gradle / Ivy
The newest version!
package fun.fengwk.convention4j.springboot.starter.cache.registry;
import fun.fengwk.convention4j.common.cache.exception.CacheInitializationException;
import fun.fengwk.convention4j.common.cache.facade.CacheFacade;
import fun.fengwk.convention4j.common.cache.metrics.CacheManagerMetrics;
import fun.fengwk.convention4j.common.lang.StringUtils;
import fun.fengwk.convention4j.springboot.starter.cache.annotation.meta.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.ResolvableType;
import org.springframework.util.ReflectionUtils;
import java.beans.PropertyDescriptor;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
import static fun.fengwk.convention4j.springboot.starter.cache.annotation.meta.CacheAnnotationMetaReader.*;
import static fun.fengwk.convention4j.springboot.starter.cache.registry.CacheInitializationUtils.*;
/**
* @author fengwk
*/
@Slf4j
public class DefaultCacheManagerRegistry implements BeanPostProcessor {
private final ConcurrentMap, DefaultCacheManager> registry = new ConcurrentHashMap<>();
private final BeanFactory beanFactory;
private final CacheFacade cacheFacade;
private final CacheManagerMetrics cacheManagerMetrics;
public DefaultCacheManagerRegistry(BeanFactory beanFactory, CacheFacade cacheFacade, CacheManagerMetrics cacheManagerMetrics) {
this.beanFactory = Objects.requireNonNull(beanFactory, "beanFactory cannot be null");
this.cacheFacade = Objects.requireNonNull(cacheFacade, "cacheFacade cannot be null");
this.cacheManagerMetrics = Objects.requireNonNull(cacheManagerMetrics, "cacheManagerMetrics cannot be null");
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
CacheSupportClassFinder finder = new CacheSupportClassFinder();
finder.find(bean);
Class cacheSupportClass = finder.getCacheSupportClass();
if (cacheSupportClass != null) {
CacheSupportMeta cacheSupportMeta = finder.getCacheSupportMeta();
register(bean, cacheSupportClass, cacheSupportMeta);
}
return bean;
}
public DefaultCacheManager getCacheManager(Object bean) {
CacheSupportClassFinder finder = new CacheSupportClassFinder();
finder.find(bean);
Class cacheSupportClass = finder.getCacheSupportClass();
return registry.get(cacheSupportClass);
}
private void register(Object bean, Class cacheSupportClass, CacheSupportMeta cacheSupportMeta) {
DefaultCacheManager cacheManager = new DefaultCacheManager<>(
cacheSupportMeta.getVersion(), cacheFacade, cacheSupportMeta.getExpireSeconds(), cacheManagerMetrics,
beanFactory.getBean(cacheSupportMeta.getWriteTransactionSupport()));
registerMethods(cacheManager, cacheSupportClass, cacheSupportMeta.getObjClass(), bean);
registry.put(cacheSupportClass, cacheManager);
}
private void registerMethods(DefaultCacheManager cacheManager,
Class cacheSupportClass, Class objClass, Object bean) {
Method[] allDeclaredMethods = ReflectionUtils.getAllDeclaredMethods(cacheSupportClass);
for (Method method : allDeclaredMethods) {
if (!tryRegisterReadMethod(cacheManager, objClass, method)) {
tryRegisterWriteMethod(cacheManager, objClass, method, cacheSupportClass, bean);
}
}
}
private boolean tryRegisterReadMethod(
DefaultCacheManager cacheManager, Class objClass, Method method) {
ReadMethodMeta readMethodMeta = findReadMethodMeta(method);
if (readMethodMeta == null) {
return false;
}
String cacheName = StringUtils.isEmpty(readMethodMeta.getName()) ?
method.getName() : readMethodMeta.getName();
String cacheVersion = readMethodMeta.getVersion();
// 查找所有带有@ListenKey的字段
List collector = new ArrayList<>();
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
ResolvableType pType = ResolvableType.forMethodParameter(method, i);
ListenKeyMeta listenKeyMeta = findListenKeyMeta(parameter);
if (listenKeyMeta != null) {
// @ListenKey仅支持注释简单类型或简单的可迭代类型
if (!isSimplePropertyOrIterableSimpleProperty(pType)) {
log.error("Parameter annotated with @ListenKey only support simple types or collections of simple types, " +
"listenKeyMeta: {}, pType: {}", listenKeyMeta, pType);
throw new CacheInitializationException(
"Parameter annotated with @ListenKey only support simple types or collections of simple types.");
}
// 可以直接从参数表中获取到@ListenKey的情况
final int index = i;
DefaultListenKey defaultListenKey = new DefaultListenKey(
listenKeyMeta, params -> params[index],
parseListenKeyExpr(objClass, listenKeyMeta.getValue()),
pType);
collector.add(defaultListenKey);
} else {
// 如果无法从参数表中获取到@ListenKey,则需要深入参数对象当中查找@ListenKey
// 仅支持javaBean对象进行深入查询,因此对复杂对象进行排除
if (isJavaBean(pType.resolve())) {
// 检索所有get方法和字段,检查@ListenKey注解,方法优先于字段
final int index = i;
Set visited = new HashSet<>();
visited.add(pType);
scanAndCollectListenKeyField(pType, collector,
params -> params[index], objClass, visited);
}
}
}
// 检查是否存在重复的@ListenKey value
Set listenKeyValues = new HashSet<>();
for (DefaultListenKey defaultListenKey : collector) {
String value = defaultListenKey.getListenKeyMeta().getValue();
if (!listenKeyValues.add(value)) {
log.error("Duplicate @ListenKey value, value: {}", value);
throw new CacheInitializationException("Duplicate @ListenKey value '" + value + "'.");
}
}
// 注册读方法
cacheManager.registerReadMethod(
method, new DefaultCacheable<>(method, cacheVersion, collector));
return true;
}
private boolean tryRegisterWriteMethod(
DefaultCacheManager cacheManager, Class objClass, Method method,
Class cacheSupportClass, Object bean) {
WriteMethodMeta writeMethodMeta = findWriteMethodMeta(method);
if (writeMethodMeta == null) {
return false;
}
DefaultWriteMethod defaultWriteMethod = null;
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
EvictObjectMeta evictObjectMeta = findEvictObjectMeta(parameter);
if (evictObjectMeta != null) {
// 使用@EvictObject
if (!isParameterTypeOrMultiParameterType(parameter.getParameterizedType(), cacheSupportClass, objClass)) {
throw new CacheInitializationException("Parameter annotated with @CacheObject must be " +
"%s or List<%s> or %s[].", objClass.getName(), objClass.getName());
}
Function