jetcache之阿里旗下的一款缓存框架,支持本地缓存与远程缓存,官网地址:
https://github.com/alibaba/jetcache,上面也有一些使用文档
下面说下CreateCache这个注解的工作原理,这个注解的作用从名字上可以看出就是创建一个Cache,作用跟下面的代码相同
代码语言:javascript复制// 声明缓存
private Cache<Long, User> userCache;
// 创建缓存
QuickConfig qc = QuickConfig.newBuilder("user-cache")
.cacheType(CacheType.BOTH)
.syncLocal(true)
.expire(Duration.ofSeconds(200))
.build();
userCache = cacheManager.getOrCreateCache(qc);
下面看下@CreateCache注解是如何创建一个缓存的,入口类为
代码语言:javascript复制CreateCacheAnnotationBeanPostProcessor,没错,这是一个BeanPostProcessor,这个类重写了
代码语言:javascript复制AutowiredAnnotationBeanPostProcessor类的postProcessProperties方法,下面看下这个方案具体实现了什么逻辑
代码语言:javascript复制 public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
} catch (BeanCreationException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
clear(metadata, pvs);
}
try {
// 这是核心方法
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
} catch (NoClassDefFoundError err) {
throw new IllegalStateException("Failed to introspect bean class [" clazz.getName()
"] for autowiring metadata: could not find class that it depends on", err);
}
}
}
}
return metadata;
}
上面注释了类CreateCacheAnnotationBeanPostProcessor的buildAutowiringMetadata方法是@CreateCache这个注解创建Cache的核心功能,下面就看下这个方法具体实现:
代码语言:javascript复制 private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
Class<?> targetClass = clazz;
do {
final LinkedList<InjectionMetadata.InjectedElement> currElements =
new LinkedList<InjectionMetadata.InjectedElement>();
doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
// 判断类属性是否有CreateCache注解
CreateCache ann = field.getAnnotation(CreateCache.class);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static fields: " field);
}
return;
}
// AutowiredFieldElement是InjectionMetadata.InjectedElement类
currElements.add(new AutowiredFieldElement(field, ann));
}
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new InjectionMetadata(clazz, elements);
}
下面看下AutowiredFieldElement这个类具体实现了啥,
代码语言:javascript复制 private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
private Field field;
private CreateCache ann;
public AutowiredFieldElement(Field field, CreateCache ann) {
super(field, null);
this.field = field;
this.ann = ann;
}
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
beanFactory.registerDependentBean(beanName, "globalCacheConfig");
// CreateCacheWrapper 类创建时会自动创建cache对象
CreateCacheWrapper wrapper = new CreateCacheWrapper(beanFactory, ann, field);
field.setAccessible(true);
field.set(bean, wrapper.getCache());
}
}
// 创建cache对象
public CreateCacheWrapper(ConfigurableListableBeanFactory beanFactory, CreateCache ann, Field field) {
this.beanFactory = beanFactory;
this.ann = ann;
this.field = field;
CacheRefresh cr = field.getAnnotation(CacheRefresh.class);
if (cr != null) {
refreshPolicy = CacheConfigUtil.parseRefreshPolicy(cr);
}
CachePenetrationProtect penetrateProtect = field.getAnnotation(CachePenetrationProtect.class);
if (penetrateProtect != null) {
protectConfig = CacheConfigUtil.parsePenetrationProtectConfig(penetrateProtect);
}
// 初始化,看这个方法时对照文章开始手动创建cache的代码
init();
}
private void init() {
GlobalCacheConfig globalCacheConfig = beanFactory.getBean(GlobalCacheConfig.class);
ConfigProvider configProvider = beanFactory.getBean(ConfigProvider.class);
CacheManager cacheManager = beanFactory.getBean(CacheManager.class);
if (cacheManager == null) {
logger.error("There is no cache manager instance in spring context");
}
CachedAnnoConfig cac = new CachedAnnoConfig();
cac.setArea(ann.area());
cac.setName(ann.name());
cac.setTimeUnit(ann.timeUnit());
cac.setExpire(ann.expire());
cac.setLocalExpire(ann.localExpire());
cac.setCacheType(ann.cacheType());
cac.setSyncLocal(ann.syncLocal());
cac.setLocalLimit(ann.localLimit());
cac.setSerialPolicy(ann.serialPolicy());
cac.setKeyConvertor(ann.keyConvertor());
cac.setRefreshPolicy(refreshPolicy);
cac.setPenetrationProtectConfig(protectConfig);
String cacheName = cac.getName();
if (CacheConsts.isUndefined(cacheName)) {
String[] hiddenPackages = globalCacheConfig.getHiddenPackages();
CacheNameGenerator g = configProvider.createCacheNameGenerator(hiddenPackages);
cacheName = g.generateCacheName(field);
}
cache = configProvider.newContext(cacheManager).__createOrGetCache(cac, ann.area(), cacheName);
}