前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >jetcache源码分支之CreateCache注解

jetcache源码分支之CreateCache注解

作者头像
johnhuster的分享
发布2024-02-23 08:36:49
1270
发布2024-02-23 08:36:49
举报
文章被收录于专栏:johnhusterjohnhuster

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);
    }
本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-02-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com