首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  程序员

Java 动态切换两个不同的类声明

  •  1
     
  •   beryl · 147 天前 · 2023 次点击
    这是一个创建于 147 天前的主题,其中的信息可能已经有所发展或是发生改变。

    使用:

    // case 1

    @Resource("testService")
    private RedisClient redisClient;
    
    
    // ...
    // 省略重写的 redis 方法
    
    

    // case 2

    @Resource("testService")
    private RedisClusterClient redisClient;
    
    
    // ...
    // 省略重写的 redis 方法
    
    

    期望统一成一个:

    @Resource("testService")
    private MyRedisClient redisClient;
    
    
    // ...
    // 省略重写的 redis 方法
    
    

    想根据不同配置,MyRedisClient 代理到不同的单例或者集群模式的类。

    因为不同环境有的是单点的,要使用 case1 的方式, 有的是 cluster 模式,要使用 case2, 但是这样要切换代码才可以。

    想通过配置方式不知道怎么实现,想到可能需要通过代理模式实现,但是具体细节一直没有搞清楚?

    Java 动态代理 工厂模式

    28 回复  |  直到 2019-05-27 13:58:03 +08:00
        1
    undeflife   147 天前   ♥ 2
    通过配置文件和 @Conditional 方式自动切换

    @Conditional(value = { RedisContextHolder.RedisServiceCondition.class })
    private RedisClient redisClient;

    @Conditional(value = { RedisClusterContextHolder.RedisClusterServiceCondition.class })
    private RedisClusterClient redisClient;



    public static class RedisServiceCondition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    context.getEnvironment().getProperty("application.redis")
    ....
    return boolean;
    }
    }
        2
    bxb100   147 天前
    通过启动参数然后 if else?
        3
    beryl   147 天前
    @bxb100 怎么在注解中实现这种呢?
        4
    undeflife   147 天前
    上面写得不太对 Conditional 写在类上,这俩 Client 最好有实现相同的接口或父

    使用 redis 的地方自动注入即可
        5
    beryl   147 天前
    @undeflife 因为有个 client 是一个第三方库, 是个接口,rediscluster 是我自己写的。 不太清楚怎么抽象出来一个父类。

    另外 Conditional 方法还没用过,在查。每太看明白你上面的示例

    thx
        6
    xiangyuecn   147 天前
    interface MyRedisClient{
    定义需要的 redis 功能操作方法
    }

    根据单点或集群分别实现 MyRedisClient 底层调用逻辑
    RedisClient implements MyRedisClient
    RedisClusterClient implements MyRedisClient


    通过配置给 client 动态赋值
    private MyRedisClient redisClient=new (RedisClient or RedisClusterClient)


    别说我现在用的就是这么干的。。。不过我用 c#写的一套
        7
    beryl   147 天前
    @xiangyuecn 现在 RedisClient 是个接口,而且是第三方库。所以很难扩展
        8
    tangtj   147 天前
    可以使用 ApplicationContext 运行时根据配置文件动态获取 bean
        9
    xiangyuecn   147 天前
    @beryl #7 呆板😂

    根据单点或集群分别实现 MyRedisClient 底层调用逻辑
    MyXXOO_RedisClient implements MyRedisClient 里面调用了 RedisClient 底层逻辑
    MyXXOO_RedisClusterClient implements MyRedisClient 里面调用到了 RedisClusterClient 底层逻辑

    通过配置给 client 动态赋值
    private MyRedisClient redisClient=new (MyXXOO_RedisClient or MyXXOO_RedisClusterClient)
        10
    undeflife   147 天前
    @beryl 第三方库你同样可以自己再封装一层。
    这个场景最合适使用 @Conditional
    上面的代码我随手写的 有些错漏,
    随手收了个例子 你可以看看
    https://reflectoring.io/spring-boot-conditionals/
        11
    notreami   147 天前
    适配模式?门面模式?
        12
    beryl   147 天前
    @undeflife 我看下,不过现在是用的 spring mvc 4.x 支持 @Conditional, 应该有些细微差别。我研究下
        13
    beryl   147 天前
    @undeflife 不明白的一点是,我写了自己的条件,但是在声明的地方还是没看懂怎么写。

    原先通过
    ```
    @Resource("testService")
    private RedisClient redisClient;

    ```

    那么现在这个地方如果声明呢
        14
    mooncakejs   147 天前 via iPhone
    xml 就很方便了
        15
    codeyung   147 天前
    多数据源配置 getredis 根据条件传入不同的 redis 实例 你去搜索一下 应该是就改一个 redisService 就好了
        16
    beryl   147 天前
    @mooncakejs 怎么个方便呢?
        17
    undeflife   147 天前
    @beryl Conditional 会根据条件决定是否创建 bean,所以你只会有一个满足条件的 bean 存在,你使用的地方修改为 by type 而不是默认的 by name 即可
        18
    lihongjie0209   147 天前
    你直接注入一个 redisServiceFactory 不就好了?
        19
    beryl   147 天前
    @lihongjie0209 现在 cluster 是个 factory, 另一个也是 factory,
    尝试封装,一个更高层的 factory, 但是没有成功
        20
    Takamine   147 天前 via Android
    看到是根据不同的配置,那我就觉得楼上 @Conditional 合适。_(:з」∠)_
        21
    beryl   147 天前
    @undeflife 有没有一种,不满足『最好有实现相同的接口或父』,的实现方式呢,thx
        22
    undeflife   147 天前
    @beryl 使用工厂类咯
        23
    beryl   147 天前
    @undeflife 对设计模式不是很清楚,虽然不是很懂, 有种朦胧感, 不过还是感谢。
    我自己再研究下吧。
        24
    xuanbg   146 天前
    没明白什么需求,只看到一个集群一个单机的区别。但 Redis 功能上来讲集群和单机并没有什么不同啊?为啥要写两个方法?
        25
    yxjn   146 天前
    spring boot 很简单,只要在配置文件里修改即可。注册的 redistemplate 即是相应的 redis 配置下的。
        26
    palmers   146 天前
    我理解 lz 的需求是需要动态切换 redis 的数据源, 在向上抽象一个委托类或适配器来执行业务 然后利用观察者模式 或者工厂 bean 来切换 redis 数据源 我觉得这个方法可以办到
        27
    beryl   146 天前
    @palmers 大体思路可以明白,可能是现在对这些不太透彻理解,所以细节实现还是没能实现。
        28
    beryl   146 天前
    @yxjn 然而不是 spring boot ...
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   723 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 25ms · UTC 21:26 · PVG 05:26 · LAX 14:26 · JFK 17:26
    ♥ Do have faith in what you're doing.