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();
6. 獲取Fabric連接
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")) {
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;
}
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;
}
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;
}
}
簡單總結:
- 如果使用快取,那么連接池中的連接物件將是動態生成的代理連接物件;
- 在查詢前會先查詢快取,如果存在就直接回傳結果,如果不存在,再去查詢;
- 將查詢后的結果存到快取中
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/307366.html
標籤:區塊鏈
