jetcache源码分支之CreateCache注解

2024-02-23 08:36:49 浏览数 (2)

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);
    }

0 人点赞