在spring中利用动态代理整合单机,集群与哨兵的redis客户端(基于jedis)

简述

此篇文章为基于jedis利用动态代理整合单机,集群和哨兵模式的redis客户端,通过在application.properties内设置redis.client.mode可以启用不同的客户端。

动态代理

通过配置文件生成不同模式的客户端

@Configuration
public class JedisConfig {

    @Value("${redis.client.mode}")
    private String clientMode;

    @Value("${redis.host}")
    private String hosts;

    @Value("${password}")
    private String password;

    @Value("${timeout}")
    private String timeout;
    
    private JedisPool jedisPool;

    private JedisCluster jedisCluster;

    private JedisSentinelPool jedisSentinelPool;

    @PostConstruct
    public void create() {
        List<HostAndPort> hnps = new ArrayList<>();
        for (String host : hosts.split(",")) {
            String[] hostAndPort = host.split(":");
            HostAndPort hnp = new HostAndPort(hostAndPort[0], Integer.parseInt(hostAndPort[1]));
            hnps.add(hnp);
        }
        if ("single".equals(clientMode)) {
            HostAndPort hnp = hnps.iterator().next();
            jedisPool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), Integer.parseInt(timeout), password);
        } else if ("cluster".equals(clientMode)) {
            jedisCluster = new JedisCluster(new HashSet<>(hnps), 0, 2, 5, "cluster", new JedisPoolConfig());
        } else if ("sentinel".equals(clientMode)) {
            //此处需指定哨兵模式的参数,此例仅为示意。
            HostAndPort sentinel1 = hnps.get(0);
            HostAndPort sentinel2 = hnps.get(1);
            Set<String> sentinels = new HashSet<String>();
            sentinels.add(sentinel1.toString());
            sentinels.add(sentinel2.toString());
            jedisSentinelPool = new JedisSentinelPool("mymaster", sentinels, new GenericObjectPoolConfig(), 1000,
                password, 2);
        } else {
            throw new IllegalArgumentException("illegal redis client mode, only support single, cluster and sentinel.");
        }
    }
    
    public String getClientMode() {
        return clientMode;
    }

    public JedisPool getJedisPool() {
        return jedisPool;
    }

    public JedisCluster getJedisCluster() {
        return jedisCluster;
    }

    public JedisSentinelPool getJedisSentinelPool() {
        return jedisSentinelPool;
    }
}

利用动态代理动态指定不同模式的客户端执行jedisCommand

@Component
class JedisProxy implements InvocationHandler {

    @Resource
    private JedisConfig jedisConfig;

    public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
        if ("single".equals(jedisConfig.getClientMode())) {
            return execSingleJedisCommand(m, args);
        } else if ("cluster".equals(jedisConfig.getClientMode())) {
            return execClusterCommand(m, args);
        } else if ("sentinel".equals(jedisConfig.getClientMode())) {
            return execSentinelCommand(m, args);
        } else {
            throw new IllegalArgumentException("illegal redis client mode, only support single, cluster and sentinel.");
        }
    }

    private Object execSentinelCommand(Method m, Object[] args) throws IllegalAccessException, InvocationTargetException {
        try (Jedis jedis0 = jedisConfig.getJedisSentinelPool().getResource()) {
            return m.invoke(jedis0, args);
        } catch (Exception e) {
            System.out.println("sentinel redis client " + m.getName() + " error, detail:\n" + e);
            throw e;
        }
    }

    private Object execClusterCommand(Method m, Object[] args) throws IllegalAccessException, InvocationTargetException {
        try {
            return m.invoke(jedisConfig.getJedisCluster(), args);
        } catch (Exception e) {
            System.out.println("cluster redis client " + m.getName() + " error, detail:\n" + e);
            throw e;
        }
    }

    private Object execSingleJedisCommand(Method m, Object[] args) throws IllegalAccessException, InvocationTargetException {
        try (Jedis jedis0 = jedisConfig.getJedisPool().getResource()) {
            return m.invoke(jedis0, args);
        } catch (Exception e) {
            System.out.println("single redis client " + m.getName() + " error, detail:\n" + e);
            throw e;
        }
    }
}

利用依赖注入以及Proxy动态生成JedisCommand接口的实现类

@Component
public class JedisClient {
    @Bean
    private JedisCommands generateClient() {
        return (JedisCommands) Proxy.newProxyInstance(JedisProxy.class.getClassLoader(), new Class[]{JedisCommands.class}, new JedisProxy());
    }
}

最后经过依赖注入jedisCommand就可以直接使用了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值