java的中回调回调机制解析

我们首先来看下面一段代码,这段代码是我们使用Jedis 封装服务的一个实现:

[java]  查看纯 文本  
  1. @服务  
  2. 公开 JedisSpringDemo {   
  3.     @Resource (name =  “shardedJedisPool” )  
  4.     私人 ShardedJedisPool shardedJedisPool;  
  5.       
  6.     public  String set(String key,String value){  
  7.         ShardedJedis shardedJedis =  null ;  
  8.         尝试{  
  9.             //从连接池中获取jedis分片对象  
  10.             shardedJedis = shardedJedisPool.getResource();  
  11.             //设置值到redis中  
  12.             返回 shardedJedis.set(key,value);  
  13.         } catch  (Exception e){  
  14.             的System.out.println(e.getMessage());  
  15.         } finally  {  
  16.             if null  != shardedJedis){  
  17.                 shardedJedis.close();  
  18.             }  
  19.         }  
  20.         返回null ;   
  21.     }  
  22. }  
从上面的代码中,不知道大家有没有看出什么问题出来?就我看,上面的这段代码违反了 DRY  原则,怎么说了,上面代码中的 try  catch  finally  中的绝大部分代码都是雷同的,唯一不同的就是我们 返回 的那一行具体的调用方法,如果像这种方法很多的话 (jedis  提供了几十种类似的方法 ,我们的代码重复率是很高的,代码重复率一旦高起来,相应的维护成本也会提高,下面我们就来引进一种改进方法 回调机制。

首先,我们创建一个接口类,该接口定义Jedis 的操作,代码如下:

[java]  查看纯 文本  
  1. 公共接口 RedisOperations {   
  2.     T执行(ConnectionCallback <T>动作);  
  3.    String set(final  String key,  final  String value);  
  4.    String get(final  String key);  
  5. }  
其次,定义连接 Redis的 服务器的回调接口,代码如下:
[java]  查看纯 文本  
  1. 公共接口 ConnectionCallback <T> {   
  2.     T doInRedis(ShardedJedis shardedJedis);  
  3. }  
最后定义具体的操作服务类,代码如下:
[java]  查看纯 文本  
  1. @Service “redisTemplate” )  
  2. 公共 RedisTemplate  实现 RedisOperations {   
  3.     @Resource (name =  “shardedJedisPool” )  
  4.     私人 ShardedJedisPool shardedJedisPool;  
  5.       
  6.     @覆盖  
  7.     public  <T> T execute(ConnectionCallback <T> action){  
  8.         ShardedJedis shardedJedis =  null ;  
  9.         尝试{  
  10.             //从连接池中获取jedis分片对象  
  11.             shardedJedis = shardedJedisPool.getResource();  
  12.               
  13.             return  action.doInRedis(shardedJedis);  
  14.               
  15.         } catch  (Exception e){  
  16.             的System.out.println(e.getMessage());  
  17.         } finally  {  
  18.             if null  != shardedJedis){  
  19.                 shardedJedis.close();  
  20.             }  
  21.         }  
  22.         返回null ;   
  23.     }  
  24.       
  25.    / ** 
  26.      *注意:真正封装的方法,非常的简洁干脆 
  27.      * /  
  28.     public  String set(final  String key,  final  String value){  
  29.         return  execute(new  ConnectionCallback <String>(){  
  30.             @覆盖  
  31.             public  String doInRedis(  
  32.                     ShardedJedis shardedJedis){  
  33.                 返回 shardedJedis.set(key,value);  
  34.             }  
  35.         });  
  36.     }  
  37.       
  38.     public  String get(final  String key){  
  39.         return  execute(new  ConnectionCallback <String>(){  
  40.             @覆盖  
  41.             public  String doInRedis(ShardedJedis shardedJedis){  
  42.                 返回 shardedJedis.get(key);  
  43.             }  
  44.         });  
  45.     }  
  46. }  
通过上面的代码,我们可以清晰的看到,将 try  catch  finally  部分的公共代码都封装到了回调函数中,当调用具体方法的时候,再实现回调方法的具体业务逻辑即可,代码的复用率更高了。

如果大家对spring  jdbc 或者是spring数据  Redis的源码研究过,就应该知道JdbcTemplate RedisTemplate 这两个类,这两个框架中用到了大量的回调机制,下面我们就以spring数据  redis为例,来简单的看下高手是如何玩转回调机制的。

首先定义回调方法,代码如下:

[java]  查看纯 文本  
  1. 公共接口 RedisCallback <T> {   
  2.     T doInRedis(RedisConnection连接)  抛出 DataAccessException;  
  3. }  
其次,定义操作方法,代码如下:
[java]  查看纯 文本  
  1. 公共接口 RedisOperations <K,V> {   
  2.     执行(RedisCallback <T>动作);  
  3.     执行(SessionCallback <T> session);  
  4.   
  5.    ............省略若干方法............  
  6.   
  7. }  
最后,回调机制的实现 RedisTemplate  类,代码如下:
[java]  查看纯 文本  
  1. public class  RedisTemplate <K,V>  扩展 RedisAccessor  实现 RedisOperations <K,V> {   
  2.   
  3.     //以下定义的是Redis支持的操作类型,例如SetOperations就是用来操作设置类型的,由于Redis支持的操作类型比较多,所以将每种操作类型都抽象成一个具体的操作类  
  4.     私人 ValueOperations <K,V> valueOps;  
  5.     private  ListOperations <K,V> listOps;  
  6.     私人 SetOperations <K,V> setOps;  
  7.     私有 ZSetOperations <K,V> zSetOps;  
  8.     私人 HyperLogLogOperations <K,V> hllOps;  
  9.   
  10.     / ** 
  11.      *构造一个新的<code> RedisTemplate </ code>实例。 
  12.      * /  
  13.     public  RedisTemplate(){}  
  14.   
  15.     public  <T> T execute(RedisCallback <T> action){  
  16.         return  execute(action,isExposeConnection());  
  17.     }  
  18.   
  19.     public  <T> T execute(RedisCallback <T> action,  boolean  exposedConnection){  
  20.         return  execute(action,exposedConnection,  false );  
  21.     }  
  22.   
  23.     public  <T> T execute(RedisCallback <T> action,  boolean  exposedConnection,  boolean  pipeline){  
  24.         Assert.isTrue(已初始化,  “模板未初始化;在使用之前调用afterPropertiesSet()” );  
  25.         Assert.notNull(action,  “Callback object must not be null” );  
  26.        //获取Redis服务器的连接工厂  
  27.         RedisConnectionFactory factory = getConnectionFactory();  
  28.         RedisConnection conn =  null ;  
  29.         尝试 {  
  30.   
  31.             if  (enableTransactionSupport){  
  32.                 //仅在潜在事务同步的情况下才绑定资源  
  33.              //如果开启了事物的话,需将连接绑定到事物上  
  34.                 conn = RedisConnectionUtils.bindConnection(factory,enableTransactionSupport);  
  35.             }  else  {  
  36.             //获取连接  
  37.                 conn = RedisConnectionUtils.getConnection(factory);  
  38.             }  
  39.   
  40.             boolean  existingConnection = TransactionSynchronizationManager.hasResource(factory);  
  41.   
  42.             RedisConnection connToUse = preProcessConnection(conn,existingConnection);  
  43.   
  44.             boolean  pipelineStatus = connToUse.isPipelined();  
  45.             if  (pipeline &&!pipelineStatus){  
  46.                 connToUse.openPipeline();  
  47.             }  
  48.   
  49.             RedisConnection connToExpose =(exposeConnection?connToUse:createRedisConnectionProxy(connToUse));  
  50.             T result = action.doInRedis(connToExpose);  
  51.   
  52.             //关闭管道  
  53.             if  (pipeline &&!pipelineStatus){  
  54.                 connToUse.closePipeline();  
  55.             }  
  56.   
  57.             // TODO:任何其他连接处理?  
  58.             return  postProcessResult(result,connToUse,existingConnection);  
  59.         }  finally  {  
  60.   
  61.             if  (enableTransactionSupport){  
  62.                 RedisConnectionUtils.unbindConnection(工厂);  
  63.             }  else  {  
  64.                 RedisConnectionUtils.releaseConnection(conn,factory);  
  65.             }  
  66.         }  
  67.     }  
  68.   
  69.     public  <T> T execute(SessionCallback <T> session){  
  70.         Assert.isTrue(已初始化,  “模板未初始化;在使用之前调用afterPropertiesSet()” );  
  71.         Assert.notNull(session,  “Callback object must not be null” );  
  72.   
  73.         RedisConnectionFactory factory = getConnectionFactory();  
  74.         //绑定连接  
  75.         RedisConnectionUtils.bindConnection(factory,enableTransactionSupport);  
  76.         尝试 {  
  77.             return  session.execute(this );  
  78.         }  finally  {  
  79.             RedisConnectionUtils.unbindConnection(工厂);  
  80.         }  
  81.     }  
  82. ............省略若干创建连接代码............  
  83.   
  84. ............以下是具体的操作,会调用回调方法............  
  85.         protected  List <Object> execRaw(){  
  86.         return  execute(new  RedisCallback <List <Object >>(){  
  87.             public  List <Object> doInRedis(RedisConnection connection)  throws  DataAccessException {  
  88.                 return  connection.exec();  
  89.             }  
  90.         });  
  91.     }  
  92.   
  93.     public void  delete(K key){   
  94.         final byte [] rawKey = rawKey(key);   
  95.   
  96.         execute(new  RedisCallback <Object>(){  
  97.   
  98.             public  Object doInRedis(RedisConnection connection){  
  99.                 connection.del(rawKey);  
  100.                 返回null ;   
  101.             }  
  102.         },  true );  
  103.     }  
  104.   
  105.     public void  delete(Collection <K> keys){   
  106.         if  (CollectionUtils.isEmpty(keys)){  
  107.             返回;  
  108.         }  
  109.   
  110.         final byte [] [] rawKeys = rawKeys(keys);   
  111.   
  112.         execute(new  RedisCallback <Object>(){  
  113.   
  114.             public  Object doInRedis(RedisConnection connection){  
  115.                 connection.del(rawKeys);  
  116.                 返回null ;   
  117.             }  
  118.         },  true );  
  119.     }  
  120. }  
通过上面的示例,大家应该对 回调 机制有了一定的了解,最后,一言以蔽之 如果你调用我,那么我就回调。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值