Redis学习记录(二)--使用Jedis连接
标签(空格分隔): javaWEB
在Java环境中连接Redis首选Jedis,因为Jedis封装的特别好,所以连接对于开发者也就变得很简单了,本文主要讲述如何写出优雅的Jedis连接代码.
1.设计模式分析
对于Jedis,有一个连接池JedisPool
,这个连接池管理着程序中的jedis示例,对于单机部署,每一次使用jedis都是去池中取出来连接池,然后再使用他获取我们想要的结果.是不是有点感觉像数据库连接池?那么一般形式代码如下:
public String get(final String key) {
Jedis jedis = jedisPool.getResource();
String result = jedis.get(key);
jedis.close();
return result;
}
然而这样写方法多的话,每一个都要如此重复获取,然后执行,然后关闭,返回结果,一套流程,就像模板一样,那么设计模式就可以考虑模板模式.
模板设计模式主要是将通用的逻辑都抽离出来,不通用的逻辑根据实现类的具体策略而执行不同的策略.因为JedisPool
比较类似数据库连接池,因此我们可以参考Spring里的JdbcTemplate
,里面有如下代码:
public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
//获取连接
Connection con = DataSourceUtils.getConnection(getDataSource());
try {
Connection conToUse = con;
if (this.nativeJdbcExtractor != null) {
conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
}
else {
// Create close-suppressing Connection proxy, also preparing returned Statements.
conToUse = createConnectionProxy(con);
}
//执行策略
return action.doInConnection(conToUse);
}
catch (SQLException ex) {
DataSourceUtils.releaseConnection(con, getDataSource());
con = null;
throw getExceptionTranslator().translate("ConnectionCallback", getSql(action), ex);
}
finally {
//关闭连接
DataSourceUtils.releaseConnection(con, getDataSource());
}
}
分析:
代码分为三部分,获取连接,执行策略,关闭释放连接.除了策略,其他都是模板,而策略是一个函数式接口,如下:
public interface ConnectionCallback<T> {
T doInConnection(Connection con) throws SQLException, DataAccessException;
}
那么具体策略就是实现该接口的实现类里面的策略了.这样就很好地做到模板和策略分离,还有一个好处就是函数式接口可以很好地配合java8语法,写出相当优雅的代码.
2.实现
2.1 函数式接口实现
首先参照Spring,实现自己的函数式接口:
比上面多了一个泛型E代表传入参数,这样做的话,就会使得该接口更加具有通用性.
/**
* 模仿Spring ConnectionCallback写的模板接口
* T为操作返回值 E为参数类型
* 配合java8使用,效果更佳
* @author Niu Li
* @date 2016/12/8
*/
public interface WorkCallback<T,E> {
/**
* 具体执行策略
* @param e 传入参数
* @return 结果
*/
T doWorkCallback(E e);
}
2.2 实现单机版Jedis
实现思路,首先在JedisClientSingle
写一个私有的excute方法,用于实现函数式接口,定义不同策略,代码具体如下:
/**
* 单机版jedis(配置建议都放在依赖注入配置中)
* @author Niu Li
* @date 2016/12/8
*/
public class JedisClientSingle{
/**
* 连接池,建议使用其他工具注入进来
*/
private JedisPool jedisPool;
public String get(final String key) {
return excute(new WorkCallback<String, Jedis>() {
public String doWorkCallback(Jedis jedis) {
return jedis.get(key);
}
});
}
public String set(final String key, final String value) {
return excute(new WorkCallback<String, Jedis>() {
public String doWorkCallback(Jedis jedis) {
return jedis.set(key,value);
}
});
}
/**
* 模板方法,很适合提取公共操作
* @param workCallback 处理函数
* @param <T> 返回类型
* @return 结果
*/
private <T> T excute(WorkCallback<T, Jedis> workCallback) {
Jedis jedis=null;
try {
jedis = jedisPool.getResource();
return workCallback.doWorkCallback(jedis);
} catch (Exception e) {
e.printStackTrace();
}finally {
if (null !=jedis){
jedis.close();
}
}
return null;
}
}
对于jedisPool
的注入的话,Spring中可以如下配置
<!-- 配置redis客户端单机版 -->
<bean id="jedispoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="${redis.maxactive}"/>
<property name="maxIdle" value="${redis.maxidle}"/>
<property name="minIdle" value="${redis.minidle}"/>
<property name="maxWaitMillis" value="${redis.timeout}"/>
</bean>
<bean id="jedisPool" class="redis.clients.jedis.JedisPool" destroy-method="destroy" depends-on="jedispoolConfig">
<constructor-arg name="poolConfig" ref="jedispoolConfig"/>
<constructor-arg name="host" value="${redis.ip}"/>
<constructor-arg name="port" value="${redis.port}"/>
</bean>
2.3实现集群版
集群版就简单很多了,只能说Jedis封装的太好了
/**
* jedis集群
* @author Niu Li
* @date 2016/12/8
*/
public class JedisClientCluster {
/**
* 集群控制,建议使用其他工具注入进来
*/
private JedisCluster jedisCluster;
/**
* 其他的直接使用jedisCluster的方法即可
*/
public String get(final String key) {
return jedisCluster.get(key);
}
}
对于jedisCluster
的注入,Spring配置如下:
<!-- 配置redis客户端集群版 -->
<!--<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
<constructor-arg>
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.1.101"/>
<constructor-arg name="port" value="1001"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.1.101"/>
<constructor-arg name="port" value="1002"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.1.101"/>
<constructor-arg name="port" value="1003"/>
</bean>
</set>
</constructor-arg>
</bean>
这种实现是不是很优雅?
参考代码:
https://github.com/nl101531/JavaWEB 下Util-Demo
参考链接:
本文从该博客学习总结而得
https://muyinchen.github.io