Code Monkey home page Code Monkey logo

Comments (17)

areyouok avatar areyouok commented on May 18, 2024

我觉得这样不好。
对于绝大部分应用来说,area是不需要设置的,除非这个应用需要连接两个不同的redis集群。
不同方法的name一般来说是不应该一样的,而且name也是可选的配置,不设置会自动生成一个。
cacheType默认REMOTE也是较好的设置。

直接把Cached写在class上面有些乱,那些属性是有效的,那些是无意义的,这怎么区分,除非发明一个新注解。
另外配置散落在各个地方是不好的,我想知道一个方法的属性是什么值,先查方法上面的注解,然后再查class上的注解,最后再查yml全局配置,这样是不是太麻烦了?

如果做一个选择:A,简单、重复繁琐。B,复杂,无重复。

那我选A。

from jetcache.

chenchi2038 avatar chenchi2038 commented on May 18, 2024

@Cached支持在class上使用后,可以由开发者决定是否使用,对于之前习惯在method上一一配置的人来说,没有任何改变,并没有要求开发者一定要怎么写的。

对于area,默认是default,对绝大部分应用来说是不需要设置,一旦需要设置,那就每个注解上都要设置,非常麻烦,目前好像没有看到有地方可以统一设置。

项目里生成key的时候,需要拼接area、name和key,用的连接符是_,这和目前常用的redis key连接符:不一样,会造成在部分redis管理工具不能对key进行很好的分层,建议是有个配置项对默认连接符进行配置。

关于是否在class上使用@Cached,举个对比的例子吧。

public class CacheService {
    @Cached(area = "book", name = ":activity:byId:", key = "#id", cacheType = CacheType.BOTH, expire = 300)
    @CacheRefresh(refresh = 60)
    public NutMap getActivity(Long id) {}

    @Cached(area = "book", name = ":viewpoints:", key = "#id", cacheType = CacheType.BOTH, expire = 300)
    @CacheRefresh(refresh = 10)
    public List<NutMap> getViewpoints(Long id) {}

    @Cached(area = "book", name = ":rotation:", key = "#id", cacheType = CacheType.BOTH, expire = 300)
    @CacheRefresh(refresh = 10)
    public List<NutMap> getRotation(Long id) {}

    @Cached(area = "book", name = ":viewpoint:", key = "#id + '#activityId'", cacheType = CacheType.BOTH, expire = 300)
    @CacheRefresh(refresh = 10)
    public NutMap getViewpoint(Long id, Long activityId) {    }
}

再看看在class上的

@Cached(area = "book", cacheType = CacheType.BOTH, expire = 300)
@CacheRefresh(refresh = 60)
public class CacheService {

    @Cached(name = ":activity:byId:", key = "#id")
    public NutMap getActivity(Long id) {}

    @Cached(name = ":viewpoints:", key = "#id")
    public List<NutMap> getViewpoints(Long id) {}

    @Cached(name = ":rotation:", key = "#id")
    public List<NutMap> getRotation(Long id) {}

    @Cached(name = ":viewpoint:", key = "#id + '#activityId'")
    public NutMap getViewpoint(Long id, Long activityId) {}
}

下面的版本明显更清晰,可读性更高啊,当然,就像前面说的,更喜欢单独针对method进行设置的,也可用继续用前一种写法。但是作为一个程序员,看着同一段配置代码被四处copy是一件很别扭的事情。

from jetcache.

areyouok avatar areyouok commented on May 18, 2024

项目里生成key的时候,拼接area、name和key的时候,用的连接符是_,这和目前常用的redis key连接符:不一样,会造成在部分redis管理工具不能对key进行很好的分层,建议是有个配置项对默认连接符进行配置。

这个是可以考虑的,不过我要说明一点,area并不拼接为key的一部分,area是用来查找对应的缓存配置的,比如连接到另一个redis集群。

我还是不喜欢太复杂,给人选择太多不一定是好事,容易留坑,而且复杂化以后bug也容易多。

很多时候繁琐而简单的代码可读性高。你的第二个版本,类很短,一眼能看到头,但是实际项目开发中类都很大,那么我读代码的时候,在一个方法上面发现了一个Cached注解,它到底会有什么样的行为,还要翻到文件的最上面去看一下,然后在我的脑子中merge一下,我不认为这样算可读性高。如果不明真相的群众没有到上面去看一下,那么理解错了行为,不就是一个坑吗?增加这个功能不是给了你一个在类上写注解的选择,而是强迫所有用户都要翻到最上面看一下。

其它:

  • 你的第一段代码繁琐有一个原因是它设置了name,而第二段代码没有设置。
  • 默认expire可以在yml中全局设置。
  • 正常情况用默认cacheType = CacheType.REMOTE足够了,除非是访问量特别大的,所有的地方都设置BOTH会占用太多内存。

from jetcache.

areyouok avatar areyouok commented on May 18, 2024

项目里生成key的时候,拼接area、name和key的时候,用的连接符是_,这和目前常用的redis key连接符:不一样,会造成在部分redis管理工具不能对key进行很好的分层,建议是有个配置项对默认连接符进行配置。

看了下代码,name和key之间没有下划线连接,而是直接拼接的,如果需要:可以自己加在name上,所以这里也不用改了哈。

from jetcache.

rchlz avatar rchlz commented on May 18, 2024

@areyouok 连接符可以有?作为配置项?

from jetcache.

areyouok avatar areyouok commented on May 18, 2024

楼上我说过了,name和key之间并没有下划线连接。不过昨天说的不是很全面。详细说是这样的:

1、name会作为key前缀,拼接时和key之间没有任何连接符,area不会作为key前缀。所以只要自己指定name就不会有任何问题。

2、如果没有指定name,自动生成的name会包含area、类名、方法名、参数,使用了各种连接符,有下划线、点,但是name的key之间仍然没有连接符。如果需要定制,不是指定一个连接符就可以,而是需要用户自己给出一个name生成器,这个真的需要么?如果用户关心这方面的监控,手工指定name是不是更好?

from jetcache.

rchlz avatar rchlz commented on May 18, 2024

①area不会作为前缀我知道。这里有一个问题,我想楼主的问题是不是把area看作redis里的db0~db15来对待的?有点类似Tair的namespace?不知道我理解的对不对。@areyouok 黄兄对area在redis中是怎么处理的?

②就是说name+key的连接方式,其实很多用户去写代码的时候不会或者忘记自己加个连接符,亦或者加了连接符,每个coder用的连接符可能不一样。这样规范性上来说,不如直接给个配置项配置连接符。省的用户去@cached注解上手动指定。

from jetcache.

areyouok avatar areyouok commented on May 18, 2024

1、就是相当于tair的不同集群(或不同namespace),之前我们的同一个应用需要连好几个tair的,不同的tair配置是不一样的,所以需要area加以区分。一般你没有需要,这个area就不用设置了,默认的就好。

2、name作为key前缀的一部分,首先我考虑的是唯一性问题,这是为了防止key冲突,所以之前生成的name又长又不好看,也没有考虑过分隔符的问题。如果要改好像只能允许用户自己定制一个name生成器(默认用之前的生成方式,以免用户升级jetcache以后出现key前缀变更造成兼容性问题),能用到这个地步的都是高级用户了。

这个我改一下吧,预留出指定生成器的接口。

from jetcache.

areyouok avatar areyouok commented on May 18, 2024

有了:
c729e7f

from jetcache.

rchlz avatar rchlz commented on May 18, 2024

这效率,杠杠的:+1:默认的generator能不能接受一个连接符参数?

from jetcache.

areyouok avatar areyouok commented on May 18, 2024

你看下代码就知道了,不能简单的加个连接符参数。

有点遗漏,还需要再改一下。之前我的说法有问题,area确实作为key前缀了,哈哈。现在杯具了,有点不好改。

from jetcache.

areyouok avatar areyouok commented on May 18, 2024

又提交了一个,应该是改好了。

from jetcache.

chenchi2038 avatar chenchi2038 commented on May 18, 2024

@areyouok 这改动是不是有点重了,并且还是需要开发者通过代码来实现自定义连接符而不是通过配置。

我的分支里是这样改的:
JetCachePropertiesGlobalCacheConfig.java里增加keyDelimiterdefaultArea两个配置参数,可以通过配置文件来定义这两个参数的值。

JetCacheAutoConfiguration中将配置文件中的keyDelimiterdefaultArea赋值给_globalCacheConfig

然后就是修改CacheContext中生成cache相关的代码了:

    private Cache createCacheByCachedConfig(CachedAnnoConfig ac, Method method, String[] hiddenPackages) {
        String area = ac.getArea();
        if (CacheConsts.DEFAULT_AREA.equalsIgnoreCase(area) && globalCacheConfig.getDefaultArea() != null) {
            area = globalCacheConfig.getDefaultArea().trim();    // 使用配置文件中的area
        }        
    }

 public Cache __createOrGetCache(CachedAnnoConfig cachedAnnoConfig, String area, String cacheName) {
        // 使用配置文件中的连接符
        String fullCacheName = area + (globalCacheConfig.getKeyDelimiter() == null ? "_" : globalCacheConfig.getKeyDelimiter()) + cacheName;        
    }

    protected Cache buildRemote(CachedAnnoConfig cachedAnnoConfig, String area, String cacheName) {
        //  使用配置文件中的连接符
        String keyPrefix = cacheBuilder.getConfig().getKeyPrefix() != null ? cacheBuilder.getConfig().getKeyPrefix() : "";
        keyPrefix += cacheName;
        keyPrefix += globalCacheConfig.getKeyDelimiter() != null ? globalCacheConfig.getKeyDelimiter()  : "_";
        cacheBuilder.setKeyPrefix(keyPrefix);
    }

配置文件:

jetcache:
  statIntervalMinutes: 15
  hiddenPackages: cn.cytong
  keyDelimiter: :
  defaultArea: booking

对于redis缓存,生成的key格式就是:booking:{cacheName}:{key}格式了。

from jetcache.

rchlz avatar rchlz commented on May 18, 2024

大概就是这个意思,不过area不应该作为key的前缀,另外defaulyArea不应该在这里配置,而应该在caches的配置里有个名叫default的Cache

from jetcache.

rchlz avatar rchlz commented on May 18, 2024

说错了,jetcache对应的是local和remote下的子项名叫default

from jetcache.

areyouok avatar areyouok commented on May 18, 2024

@chenchi2038
你的改动主要是定制了area和cache name之间的连接符,以及并且可以定制default area的名字(我觉得default area的名字还要定制是很奇怪的,你觉得呢,写文档的时候要怎么跟人解释这个事情T_T)。

但是area本来就不该作为key的一部分(之前我把area放到key里是失策了),况且默认生成的cache name可读性也很不好比如c.a.j.a.m.ClassUtilTest$C1.foo2(Lc.a.j.a.m.ClassUtilTest$I1;)这样的,也许有人想要只用类名+方法名作为自动生成的cache name,所以既然定制就灵活点。使用上也不是很复杂,只要在业务程序的App Class里面加个bean就好了,不用改jetcache本身,并不比配置麻烦多少。最简单的情况就是这样:

    @Bean
    public SpringConfigProvider springConfigProvider() {
        return new SpringConfigProvider(){
            public CacheNameGenerator createCacheNameGenerator(String[] hiddenPackages){
                return new DefaultCacheNameGenerator(){};
            }
        };
    }

这里返回了一个匿名内部类覆盖了DefaultCacheNameGenerator,然后在当前版本的CacheContext中,只要不是DefaultCacheNameGenerator本身就不会把area加到key里面了。当然你还可以覆盖方法实现自己的cache name自动生成。

SpringConfigProvider这个类本来就是用来覆盖的,也许使用者想要定制自己的key生成器,或者encoder/decoder都可以通过这样的方式来实现。

from jetcache.

areyouok avatar areyouok commented on May 18, 2024

我增加了一个选项,areaInCacheName,为了保持兼容,默认是true。把它设置为false之后,area就不会出现在key前缀中,因此也不需要配置连接符了。

配合新的Encoder/Decoder的useIdentityNumber选项,以后使用jetcache和不使用jetcache的程序可以读写同一个key。

from jetcache.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.