FabricJavaPool代码实现解析

FabricJavaPool代码解析

https://blog.csdn.net/oe1019/article/details/105982128
由于原作者未提供源码,未解析代码逻辑实现,因此整理一下代码实现逻辑

项目结构

在这里插入图片描述

调用流程

1. 创建fabric用户信息

/**
	通过获取配置文件中用户的身份信息,创建用户对象
*/
public static User getUser() {
    User appuser = null;
    File sampleStoreFile = new File(System.getProperty("user.home") + "/test.properties");
    if (sampleStoreFile.exists()) { //For testing start fresh
       sampleStoreFile.delete();
    }
    final SampleStore sampleStore = new SampleStore(sampleStoreFile);
    try {
        appuser = sampleStore.getMember("peer1", "Org1", "Org1MSP",
               new File(String.valueOf(findFileSk(Paths.get(configUserPath).toFile()))),
               new File("./src/main/resources/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem"));
    } catch (Exception e) {
        e.printStackTrace();
    }
    return appuser;
}

2. 创建Fabric连接池

private  static  ObjectPool<FabricConnection>  fabricJavaPool = FabricConnectionPoolFactory.getPool(getUser(), "mychannel");
public class FabricConnectionPoolFactory {

    private FabricConnectionPoolFactory() {
    }

    public static GenericObjectPool<FabricConnection> getPool(User appUser, String channel) {
        return new FabricJavaPool(appUser, channel);
    }
}
import org.apache.commons.pool2.impl.GenericObjectPool;
import com.github.samyuan1990.FabricJavaPool.api.FabricConnection;

public class FabricJavaPool extends GenericObjectPool<FabricConnection> {

    public FabricJavaPool(User appUser, String channel) {
        super(new ConnectionPoolFactory(appUser, channel));
    }

	/**
		私有的连接池工厂
	*/
	private static class ConnectionPoolFactory extends BasePooledObjectFactory<FabricConnection> {

        private FabricJavaPoolConfig config =  new FabricJavaPoolConfig();
        private String config_network_path = "";
        private User appUser;
        private String channel = "";

        ConnectionPoolFactory(User appUser, String channel) {
            this.config_network_path = config.getConfigNetworkPath();
            this.appUser = appUser;
            this.channel = channel;
        }
        //创建fabric客户端连接的方法
		@Override
        public FabricConnection create() throws Exception {
            FabricConnectionImpl myConnection;
            CryptoSuite cryptoSuite = CryptoSuite.Factory.getCryptoSuite();
            HFClient hfclient = HFClient.createNewInstance();
            hfclient.setCryptoSuite(cryptoSuite);
            NetworkConfig networkConfig = NetworkConfig.fromJsonFile(new File(config_network_path));
            hfclient.setUserContext(appUser);
            hfclient.loadChannelFromConfig(channel, networkConfig);
            Channel myChannel = hfclient.getChannel(channel);
            myChannel.initialize();
            //这一步,创建连接池中连接
            myConnection = new FabricConnectionImpl(hfclient, myChannel, appUser);
            //这一步很关键,是否使用缓存
            if (config.isUseCache()) {
                FabricConnectionImplCacheProxy proxy = new FabricConnectionImplCacheProxy(myConnection, config.getCacheURL(), appUser.getName(), channel, config.getCacheTimeout());
                return (FabricConnection) Proxy.newProxyInstance(FabricConnectionImpl.class.getClassLoader(), new Class[]{FabricConnection.class}, proxy);
            } else {
                return myConnection;
            }

        }

        @Override
        public PooledObject<FabricConnection> wrap(FabricConnection obj) {
            return new DefaultPooledObject<>(obj);
        }
    }
}

3. 获取Fabric连接

/**
此方法如果队列中没有存在连接对象,那就调用ConnectionPoolFactory 的create方法
*/
FabricConnection myConnection = fabricJavaPool.borrowObject();

4. 查询

ExecuteResult result = myConnection.query("mycc", "query","a");
rs = result.getResult();

5. 回收Fabric连接

fabricJavaPool.returnObject(myConnection);

缓存实现分析

  • 缓存实现关键代码
FabricConnectionImplCacheProxy proxy = new FabricConnectionImplCacheProxy(myConnection, config.getCacheURL(), appUser.getName(), channel, config.getCacheTimeout());
return (FabricConnection) Proxy.newProxyInstance(FabricConnectionImpl.class.getClassLoader(), new Class[]{FabricConnection.class}, proxy);
  • FabricConnectionImplCacheProxy 类
public class FabricConnectionImplCacheProxy extends FabricContractConnectImplCacheProxy implements InvocationHandler {

	public FabricConnectionImplCacheProxy(Object obj, String cacheURL, String userName, String channelName, int timeout) {
        super(obj, cacheURL, userName, channelName, timeout);
    }

	//父类构造方法
	public FabricContractConnectImplCacheProxy(Object obj, String cacheURL, String userName, String channelName, int timeout) {
        this.timeout = timeout;
        this.channelName = channelName;
        this.userName = userName;
        this.cacheURL = cacheURL;
        //使用memcache对查询结果进行缓存
        MemcachedClientBuilder memcachedClientBuilder = new XMemcachedClientBuilder(AddrUtil.getAddresses(this.cacheURL));
        try {
            memcachedClient = memcachedClientBuilder.build();
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.obj = obj;
    }

	@Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        if (method.getName().equals("query")) {
            //查询时,根据查询方法参数用户通道拼接成唯一key
            String key = genericKey(userName, channelName, args);
            //先去缓存中查询,查询到结果直接返回
            result = memcachedClient.get(key);
            if (result != null) {
                //System.out.println("hit");
                return result;
            }
            //如果没有查询到结果,调用合约查询
            result = method.invoke(obj, args);
            ExecuteResult executeResult = (ExecuteResult) result;
            if (executeResult.getPropResp() == null) {
                return result;
            }
            //查询出请求参数,将请求参数作为key,将上面生成的key作为value,保存到缓存中
            //此步骤的作用是,在invoke是,如果对相同条件的链码和数据key作操作,就会从缓冲中将所有相关数据删除
            for (ProposalResponse p : executeResult.getPropResp()) {
                TxReadWriteSetInfo txReadWriteSetInfo = p.getChaincodeActionResponseReadWriteSetInfo();
                for (TxReadWriteSetInfo.NsRwsetInfo nsRwsetInfo : txReadWriteSetInfo.getNsRwsetInfos()) {
                    KvRwset.KVRWSet rws = nsRwsetInfo.getRwset();
                    for (KvRwset.KVRead readList : rws.getReadsList()) {
                        String blockKey = readList.getKey();
                        memcachedClient.set(blockKey, timeout, key);
                    }
                }
            }
            //将查询结果保存到缓冲中
            memcachedClient.set(key, timeout, result);
            return result;
        }
        if (method.getName().equals("invoke")) {
            result = method.invoke(obj, args);
            ExecuteResult executeResult = (ExecuteResult) result;
            if (executeResult.getPropResp() == null) {
                return result;
            }
            //获取读写集合, 以读参数为key查询缓存,如果缓冲中有值,则删除
            for (ProposalResponse p : executeResult.getPropResp()) {
                TxReadWriteSetInfo txReadWriteSetInfo = p.getChaincodeActionResponseReadWriteSetInfo();
                for (TxReadWriteSetInfo.NsRwsetInfo nsRwsetInfo : txReadWriteSetInfo.getNsRwsetInfos()) {
                    KvRwset.KVRWSet rws = nsRwsetInfo.getRwset();
                    for (KvRwset.KVRead readList : rws.getReadsList()) {
                        String blockKey = readList.getKey();
                        String blockCache = memcachedClient.get(blockKey);
                        if (!blockCache.equals(null)) {
                            memcachedClient.delete(blockCache);
                            memcachedClient.delete(blockKey);
                        }
                    }
                }
            }
            return result;
        }
        result = method.invoke(obj, args);
        return result;
    }

}

简单总结:

  • 如果使用缓存,那么连接池中的连接对象将是动态生成的代理连接对象;
  • 在查询前会先查询缓存,如果存在就直接返回结果,如果不存在,再去查询;
  • 将查询后的结果存到缓存中,并且将数据关键信息为key,查询结果缓冲key为value保存到缓冲中,以应对数据变动问题;
  • 当有数据变动时,会查询缓存中是否有数据,如果有则删除.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值