java中callback回调机制解析

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

@Service
public class JedisSpringDemo {
	@Resource(name = "shardedJedisPool")
	private ShardedJedisPool shardedJedisPool;
	
	public String set(String key, String value){
		ShardedJedis shardedJedis = null;
		try{
			// 从连接池中获取jedis分片对象
			shardedJedis = shardedJedisPool.getResource();
			// 设置值到redis中
			return shardedJedis.set(key, value);
		}catch (Exception e){
			System.out.println(e.getMessage());
		}finally {
			if(null != shardedJedis){
				shardedJedis.close();
			}
		}
		return null;
	}
}
从上面的代码中,不知道大家有没有看出什么问题出来?就我看来,上面的这段代码违反了 DRY 原则,怎么说了,上面代码中的 try catch finally 中的绝大部分代码都是雷同的,唯一不同的就是我们 return 的那一行具体的调用方法,如果像这种方法很多的话 (jedis 提供了几十种类似的方法 ) ,我们的代码重复率是很高的,代码重复率一旦高起来,相应的维护成本也会提高,下面我们就来引进一种改进方法 -- 回调机制。

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

public interface RedisOperations {
	<T> T execute(ConnectionCallback<T> action);
   String set(final String key, final String value);
   String get(final String key);
}
其次,定义连接 Redis 服务器的回调接口,代码如下:
public interface ConnectionCallback<T> {
	T doInRedis(ShardedJedis shardedJedis);
}
最后定义具体的操作服务类,代码如下:
@Service("redisTemplate")
public class RedisTemplate implements RedisOperations{
	@Resource(name = "shardedJedisPool")
	private ShardedJedisPool shardedJedisPool;
	
	@Override
	public <T> T execute(ConnectionCallback<T> action) {
		ShardedJedis shardedJedis = null;
		try{
			// 从连接池中获取jedis分片对象
			shardedJedis = shardedJedisPool.getResource();
			
			return action.doInRedis(shardedJedis);
			
		}catch (Exception e){
			System.out.println(e.getMessage());
		}finally {
			if(null != shardedJedis){
				shardedJedis.close();
			}
		}
		return null;
	}
	
   /**
	 * attention:真正封装的方法,非常的简洁干脆
	 */
	public String set(final String key, final String value){
		return execute(new ConnectionCallback<String>() {
			@Override
			public String doInRedis(
					ShardedJedis shardedJedis) {
				return shardedJedis.set(key, value);
			}
		});
	}
	
	public String get(final String key){
		return execute(new ConnectionCallback<String>(){
			@Override
			public String doInRedis(ShardedJedis shardedJedis) {
				return shardedJedis.get(key);
			}
		});
	}
}
通过上面的代码,我们可以清晰的看到,将 try catch finally 部分的公共代码都封装到了回调函数中,当调用具体方法的时候,再实现回调方法的具体业务逻辑即可,代码的复用率更高了。

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

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

public interface RedisCallback<T> {
    T doInRedis(RedisConnection connection) throws DataAccessException;
}
其次,定义操作方法,代码如下:
public interface RedisOperations<K, V> {
    <T> T execute(RedisCallback<T> action);
    <T> T execute(SessionCallback<T> session);

   …………省略若干方法…………

}
最后,回调机制的实现 RedisTemplate 类,代码如下:
public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V> {

	// 以下定义的是Redis支持的操作类型,例如SetOperations就是用来操作Set类型的,由于Redis支持的操作类型比较多,所以将每种操作类型都抽象成一个具体的操作类
	private ValueOperations<K, V> valueOps;
	private ListOperations<K, V> listOps;
	private SetOperations<K, V> setOps;
	private ZSetOperations<K, V> zSetOps;
	private HyperLogLogOperations<K, V> hllOps;

	/**
	 * Constructs a new <code>RedisTemplate</code> instance.
	 */
	public RedisTemplate() {}

	public <T> T execute(RedisCallback<T> action) {
		return execute(action, isExposeConnection());
	}

	public <T> T execute(RedisCallback<T> action, boolean exposeConnection) {
		return execute(action, exposeConnection, false);
	}

	public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {
		Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it");
		Assert.notNull(action, "Callback object must not be null");
       // 获取Redis服务器的连接工厂
		RedisConnectionFactory factory = getConnectionFactory();
		RedisConnection conn = null;
		try {

			if (enableTransactionSupport) {
				// only bind resources in case of potential transaction synchronization
             // 如果开启了事物的话,需将连接绑定到事物上
				conn = RedisConnectionUtils.bindConnection(factory, enableTransactionSupport);
			} else {
            // 获取连接
				conn = RedisConnectionUtils.getConnection(factory);
			}

			boolean existingConnection = TransactionSynchronizationManager.hasResource(factory);

			RedisConnection connToUse = preProcessConnection(conn, existingConnection);

			boolean pipelineStatus = connToUse.isPipelined();
			if (pipeline && !pipelineStatus) {
				connToUse.openPipeline();
			}

			RedisConnection connToExpose = (exposeConnection ? connToUse : createRedisConnectionProxy(connToUse));
			T result = action.doInRedis(connToExpose);

			// close pipeline
			if (pipeline && !pipelineStatus) {
				connToUse.closePipeline();
			}

			// TODO: any other connection processing?
			return postProcessResult(result, connToUse, existingConnection);
		} finally {

			if (enableTransactionSupport) {
				RedisConnectionUtils.unbindConnection(factory);
			} else {
				RedisConnectionUtils.releaseConnection(conn, factory);
			}
		}
	}

	public <T> T execute(SessionCallback<T> session) {
		Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it");
		Assert.notNull(session, "Callback object must not be null");

		RedisConnectionFactory factory = getConnectionFactory();
		// bind connection
		RedisConnectionUtils.bindConnection(factory, enableTransactionSupport);
		try {
			return session.execute(this);
		} finally {
			RedisConnectionUtils.unbindConnection(factory);
		}
	}
…………省略若干创建连接代码…………

…………以下是具体的操作,会调用回调方法…………
    	protected List<Object> execRaw() {
		return execute(new RedisCallback<List<Object>>() {
			public List<Object> doInRedis(RedisConnection connection) throws DataAccessException {
				return connection.exec();
			}
		});
	}

	public void delete(K key) {
		final byte[] rawKey = rawKey(key);

		execute(new RedisCallback<Object>() {

			public Object doInRedis(RedisConnection connection) {
				connection.del(rawKey);
				return null;
			}
		}, true);
	}

	public void delete(Collection<K> keys) {
		if (CollectionUtils.isEmpty(keys)) {
			return;
		}

		final byte[][] rawKeys = rawKeys(keys);

		execute(new RedisCallback<Object>() {

			public Object doInRedis(RedisConnection connection) {
				connection.del(rawKeys);
				return null;
			}
		}, true);
	}
}
通过上面的示例,大家应该对 callback 机制有了一定的了解,最后,一言以蔽之 -- 如果你调用我,那么我就回调。
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
微信支付v3版的支付回调是基于异步通知机制进行的,需要在接收支付结果的服务器端编写Java代码来处理回调请求。以下是一个简单的示例代码: ```java import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse; import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.service.WxPayService; import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/v1/pay") public class WechatPayCallbackController { private final WxPayService wxPayService; public WechatPayCallbackController() { // 初始化微信支付服务 wxPayService = new WxPayServiceImpl(); wxPayService.setKey("your-wxpay-api-key"); // 设置支付密钥 } @PostMapping("/callback") public String payCallback(@RequestBody String notifyData) { try { // 解析支付通知 wxPayService.parseNotifyResult(notifyData); // 处理支付成功逻辑,例如更新订单状态等 // 返回成功响应给微信支付平台 return WxPayNotifyResponse.success("处理成功"); } catch (WxPayException e) { // 处理支付失败逻辑,例如记录错误日志等 // 返回失败响应给微信支付平台 return WxPayNotifyResponse.fail(e.getMessage()); } } } ``` 上述代码是一个使用Spring Boot框架的控制器类,负责处理微信支付的回调请求。在回调方法`payCallback`,通过`wxPayService.parseNotifyResult`方法解析支付通知的XML数据,并在处理成功或失败后返回相应的结果。 需要注意的是,为了保证安全性,建议在实际开发将`your-wxpay-api-key`替换为实际的支付密钥。 另外,此代码仅作为示例,实际情况可能需要结合具体的业务逻辑进行扩展和修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值