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

2019-05-26 12:29:11 +08:00
 beryl

使用:

// 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 动态代理 工厂模式

3472 次点击
所在节点    程序员
28 条回复
undeflife
2019-05-26 12:41:04 +08:00
通过配置文件和 @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
2019-05-26 12:41:40 +08:00
通过启动参数然后 if else?
beryl
2019-05-26 12:44:01 +08:00
@bxb100 怎么在注解中实现这种呢?
undeflife
2019-05-26 12:44:03 +08:00
上面写得不太对 Conditional 写在类上,这俩 Client 最好有实现相同的接口或父

使用 redis 的地方自动注入即可
beryl
2019-05-26 12:47:36 +08:00
@undeflife 因为有个 client 是一个第三方库, 是个接口,rediscluster 是我自己写的。 不太清楚怎么抽象出来一个父类。

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

thx
xiangyuecn
2019-05-26 12:52:41 +08:00
interface MyRedisClient{
定义需要的 redis 功能操作方法
}

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


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


别说我现在用的就是这么干的。。。不过我用 c#写的一套
beryl
2019-05-26 12:53:56 +08:00
@xiangyuecn 现在 RedisClient 是个接口,而且是第三方库。所以很难扩展
tangtj
2019-05-26 12:57:16 +08:00
可以使用 ApplicationContext 运行时根据配置文件动态获取 bean
xiangyuecn
2019-05-26 12:57:29 +08:00
@beryl #7 呆板😂

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

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

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

```

那么现在这个地方如果声明呢
mooncakejs
2019-05-26 13:14:34 +08:00
xml 就很方便了
codeyung
2019-05-26 13:14:56 +08:00
多数据源配置 getredis 根据条件传入不同的 redis 实例 你去搜索一下 应该是就改一个 redisService 就好了
beryl
2019-05-26 13:15:49 +08:00
@mooncakejs 怎么个方便呢?
undeflife
2019-05-26 13:45:09 +08:00
@beryl Conditional 会根据条件决定是否创建 bean,所以你只会有一个满足条件的 bean 存在,你使用的地方修改为 by type 而不是默认的 by name 即可
lihongjie0209
2019-05-26 13:53:14 +08:00
你直接注入一个 redisServiceFactory 不就好了?
beryl
2019-05-26 14:19:29 +08:00
@lihongjie0209 现在 cluster 是个 factory, 另一个也是 factory,
尝试封装,一个更高层的 factory, 但是没有成功
Takamine
2019-05-26 15:45:00 +08:00
看到是根据不同的配置,那我就觉得楼上 @Conditional 合适。_(:з」∠)_

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/567748

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX