Java 动态切换两个不同的类声明 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
beryl
V2EX    程序员

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

  •  1
    &nsp;
  •   beryl 2019 年 5 月 26 日 3848 次点击
    这是一个创建于 2432 天前的主题,其中的信息可能已经有所发展或是发生改变。

    使用:

    // 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
    undeflife
        1
    undeflife  
       2019 年 5 月 26 日   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;
    }
    }
    bxb100
        2
    bxb100  
       2019 年 5 月 26 日
    通过启动参数然后 if else?
    beryl
        3
    beryl  
    OP
       2019 年 5 月 26 日
    @bxb100 怎么在注解中实现这种呢?
    undeflife
        4
    undeflife  
       2019 年 5 月 26 日
    上面写得不太对 Conditional 写在类上,这俩 Client 最好有实现相同的接口或父

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

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

    thx
    xiangyuecn
        6
    xiangyuecn  
       2019 年 5 月 26 日
    interface MyRedisClient{
    定义需要的 redis 功能操作方法
    }

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


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


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

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

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

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

    ```

    那么现在这个地方如果声明呢
    mooncakejs
        14
    mooncakejs  
       2019 年 5 月 26 日 via iPhone
    xml 就很方便了
    codeyung
        15
    codeyung  
       2019 年 5 月 26 日
    多数据源配置 getredis 根据条件传入不同的 redis 实例 你去搜索一下 应该是就改一个 redisService 就好了
    beryl
        16
    beryl  
    OP
       2019 年 5 月 26 日
    @mooncakejs 怎么个方便呢?
    undeflife
        17
    undeflife  
       2019 年 5 月 26 日
    @beryl Conditional 会根据条件决定是否创建 bean,所以你只会有一个满足条件的 bean 存在,你使用的地方修改为 by type 而不是默认的 by name 即可
    lihongjie0209
        18
    lihongjie0209  
       2019 年 5 月 26 日
    你直接注入一个 redisServiceFactory 不就好了?
    beryl
        19
    beryl  
    OP
       2019 年 5 月 26 日
    @lihongjie0209 现在 cluster 是个 factory, 另一个也是 factory,
    尝试封装,一个更高层的 factory, 但是没有成功
    Takamine
        20
    Takamine  
       2019 年 5 月 26 日 via Android
    看到是根据不同的配置,那我就觉得楼上 @Conditional 合适。_(:з」∠)_
    beryl
        21
    beryl  
    OP
       2019 年 5 月 26 日
    @undeflife 有没有一种,不满足『最好有实现相同的接口或父』,的实现方式呢,thx
    undeflife
        22
    undeflife  
       2019 年 5 月 26 日
    @beryl 使用工厂类咯
    beryl
        23
    beryl  
    OP
       2019 年 5 月 26 日
    @undeflife 对设计模式不是很清楚,虽然不是很懂, 有种朦胧感, 不过还是感谢。
    我自己再研究下吧。
    xuanbg
        24
    xuanbg  
       2019 年 5 月 27 日
    没明白什么需求,只看到一个集群一个单机的区别。但 Redis 功能上来讲集群和单机并没有什么不同啊?为啥要写两个方法?
    yxjn
        25
    yxjn  
       2019 年 5 月 27 日
    spring boot 很简单,只要在配置文件里修改即可。注册的 redistemplate 即是相应的 redis 配置下的。
    palmers
        26
    palmers  
       2019 年 5 月 27 日
    我理解 lz 的需求是需要动态切换 redis 的数据源, 在向上抽象一个委托类或适配器来执行业务 然后利用观察者模式 或者工厂 bean 来切换 redis 数据源 我觉得这个方法可以办到
    beryl
        27
    beryl  
    OP
       2019 年 5 月 27 日
    @palmers 大体思路可以明白,可能是现在对这些不太透彻理解,所以细节实现还是没能实现。
    beryl
        28
    beryl  
    OP
       2019 年 5 月 27 日
    @yxjn 然而不是 spring boot ...
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5243 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 01:23 PVG 09:23 LAX 17:23 JFK 20:23
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86