开发环境

  • UBUNTU 16.04 LTS
  • docker
  • docker-compose
  • git
  • go 1.8以上

docker,docker-compose以及go的安装这里不再描述。

部署测试

新建fabric-sample目录(名字可以任意),进入目录执行:

curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap-1.0.0-beta.sh | bash

这个脚本会下载需要的docker镜像以及自动化脚本,执行完毕后,首先会在当前目录看到一个release的文件夹,里面有fabric运行环境的启动脚本。

其次,我们需要的docker镜像也会一并拉取过来,如下:

hyperledger/fabric-tools                 latest                ae6b0f53cb70        5 months ago        1.32GB
hyperledger/fabric-tools                 x86_64-1.0.0-beta     ae6b0f53cb70        5 months ago        1.32GB
hyperledger/fabric-couchdb               latest                31bbbec3d853        5 months ago        1.48GB
hyperledger/fabric-couchdb               x86_64-1.0.0-beta     31bbbec3d853        5 months ago        1.48GB
hyperledger/fabric-kafka                 latest                c4ac1c9a4797        5 months ago        1.3GB
hyperledger/fabric-kafka                 x86_64-1.0.0-beta     c4ac1c9a4797        5 months ago        1.3GB
hyperledger/fabric-zookeeper             latest                2c4ebacb6f00        5 months ago        1.31GB
hyperledger/fabric-zookeeper             x86_64-1.0.0-beta     2c4ebacb6f00        5 months ago        1.31GB
hyperledger/fabric-orderer               latest                11ff350dd297        5 months ago        179MB
hyperledger/fabric-orderer               x86_64-1.0.0-beta     11ff350dd297        5 months ago        179MB
hyperledger/fabric-peer                  latest                e01c2b645f11        5 months ago        182MB
hyperledger/fabric-peer                  x86_64-1.0.0-beta     e01c2b645f11        5 months ago        182MB
hyperledger/fabric-javaenv               latest                61c188dca542        5 months ago        1.42GB
hyperledger/fabric-javaenv               x86_64-1.0.0-beta     61c188dca542        5 months ago        1.42GB
hyperledger/fabric-ccenv                 latest                7034cca1918d        5 months ago        1.29GB
hyperledger/fabric-ccenv                 x86_64-1.0.0-beta     7034cca1918d        5 months ago        1.29GB
hyperledger/fabric-ca                    latest                e549e8c53c2e        5 months ago        238MB
hyperledger/fabric-ca                    x86_64-1.0.0-beta     e549e8c53c2e        5 months ago        238MB
hyperledger/fabric-ccenv                 x86_64-1.0.0-alpha2   8c360a57f805        5 months ago        1.29GB
hyperledger/fabric-baseos                x86_64-0.3.1          4b0cab202084        6 months ago        157MB
hyperledger/fabric-baseos                x86_64-0.3.2          4b0cab202084        6 months ago        157MB

这里有一点要注意,如果你的环境之前执行过其它的fabric测试,可能会存在其它版本的docker镜像,建议删除。我试过不删除结果后面各种错误,删除之后一切正常。

启动fabric

cd ~/fabric-sample/release/linux-amd64
./network_setup.sh up

注意看有没有报错,正常的话最后会有下面这样的界面。

Query Result: 90
2017-11-10 03:48:00.802 UTC [main] main -> INFO 008 Exiting.....
===================== Query on PEER3 on channel 'mychannel' is successful ===================== ===================== All GOOD, End-2-End execution completed ===================== _____   _   _   ____            _____   ____    _____
| ____| | \ | | |  _ \          | ____| |___ \  | ____|
|  _|   |  \| | | | | |  _____  |  _|     __) | |  _|
| |___  | |\  | | |_| | |_____| | |___   / __/  | |___
|_____| |_| \_| |____/          |_____| |_____| |_____|

启动成功后,我们用docker ps命令可以看到类似下面这样的信息,

root@pony-virtual-machine:~/gopath/src/fabric-sample# docker ps
CONTAINER ID        IMAGE                                    COMMAND                  CREATED             STATUS              PORTS                                              NAMES
e1f67091b0be        dev-peer1.org2.example.com-mycc-1.0      "chaincode -peer.a..."   2 hours ago         Up 2 hours                                                             dev-peer1.org2.example.com-mycc-1.0
c1c82b8269d1        dev-peer0.org1.example.com-mycc-1.0      "chaincode -peer.a..."   2 hours ago         Up 2 hours                                                             dev-peer0.org1.example.com-mycc-1.0
5610d9ef3dfa        dev-peer0.org2.example.com-mycc-1.0      "chaincode -peer.a..."   2 hours ago         Up 2 hours                                                             dev-peer0.org2.example.com-mycc-1.0
e5fee400df40        hyperledger/fabric-tools                 "/bin/bash -c './s..."   2 hours ago         Up 2 hours                                                             cli
12252e8c234e        hyperledger/fabric-peer                  "peer node start"        2 hours ago         Up 2 hours          0.0.0.0:8051->7051/tcp, 0.0.0.0:8053->7053/tcp     peer1.org1.example.com
82c82528a0e3        hyperledger/fabric-orderer               "orderer"                2 hours ago         Up 2 hours          0.0.0.0:7050->7050/tcp                             orderer.example.com
8e9ed0104cc9        hyperledger/fabric-peer                  "peer node start"        2 hours ago         Up 2 hours          0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp     peer0.org1.example.com
6475f787dd66        hyperledger/fabric-peer                  "peer node start"        2 hours ago         Up 2 hours          0.0.0.0:10051->7051/tcp, 0.0.0.0:10053->7053/tcp   peer1.org2.example.com
2c65a798dca2        hyperledger/fabric-peer                  "peer node start"        2 hours ago         Up 2 hours          0.0.0.0:9051->7051/tcp, 0.0.0.0:9053->7053/tcp     peer0.org2.example.com

也就是说,刚才的脚本为我们启动了一个cli客户端,一个orderer节点,4个普通的peer节点。而且,还有三个chaincode运行实例。

新开启一个终端,进入cli容器,

docker exec -it cli bash

下面我们首先安装Example02,并指定一个名字,比如我们这里就用devincc:

peer chaincode install -n devincc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02

这里安装指定的目录是docker容器中的gopath路径下的
github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02
目录中的chaincode程序。

下面有个专门的章节我会分析下这部分代码。

运行后可以看到提示运行成功,类似如下的信息:

2017-11-10 03:50:29.907 UTC [golang-platform] GetDeploymentPayload -> DEBU 00c done
2017-11-10 03:50:29.909 UTC [msp/identity] Sign -> DEBU 00d Sign: plaintext: 0AA6070A5C08031A0C0885C494D00510...98F1CF000000FFFF6430F69C001C0000
2017-11-10 03:50:29.909 UTC [msp/identity] Sign -> DEBU 00e Sign: digest: 5779AC7B30E7CFBAA5E698B90762616117CA8FA36144238F83C6A4A047D7A737
2017-11-10 03:50:29.914 UTC [chaincodeCmd] install -> DEBU 00f Installed remotely response:<status:200 payload:"OK" >
....

初始化实例,设置a账户有100元,b账户有200元。

root@e5fee400df40:/opt/gopath/src/github.com/hyperledger/fabric/peer# peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/cacerts/ca.example.com-cert.pem -C mychannel -n devincc -v 1.0 -c '{"Args":["init","a", "100", "b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')"

注意看有没有报错。

用Query命令来看一看a账户的余额:

root@e5fee400df40:/opt/gopath/src/github.com/hyperledger/fabric/peer# peer chaincode query -C mychannel -n devincc -c '{"Args":["query","a"]}'
2017-11-10 03:53:25.599 UTC [msp] getMspConfig -> INFO 001 intermediate certs folder not found at [/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/intermediatecerts]. Skipping.: [stat /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/intermediatecerts: no such file or directory]
2017-11-10 03:53:25.599 UTC [msp] getMspConfig -> INFO 002 crls folder not found at [/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/intermediatecerts]. Skipping.: [stat /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/crls: no such file or directory]
2017-11-10 03:53:25.599 UTC [msp] getMspConfig -> INFO 003 MSP configuration file not found at [/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/config.yaml]: [stat /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/config.yaml: no such file or directory]
2017-11-10 03:53:25.623 UTC [msp] GetLocalMSP -> DEBU 004 Returning existing local MSP
2017-11-10 03:53:25.623 UTC [msp] GetDefaultSigningIdentity -> DEBU 005 Obtaining default signing identity
2017-11-10 03:53:25.623 UTC [msp/identity] Sign -> DEBU 006 Sign: plaintext: 0AB4070A6A08031A0C08B5C594D00510...696E63631A0A0A0571756572790A0161
2017-11-10 03:53:25.623 UTC [msp/identity] Sign -> DEBU 007 Sign: digest: 00AA703102DBEA060C31B1E9FDD66143AD6454A27C2F1757ADE5265C992207A4
Query Result: 100

余额是100元。

接下来我们把a账户的10元转给b账户,需要调用invoke命令:

root@e5fee400df40:/opt/gopath/src/github.com/hyperledger/fabric/peer# peer chaincode invoke -o orderer.example.com:7050  --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/cacerts/ca.example.com-cert.pem  -C mychannel -n devincc -c '{"Args":["invoke","a","b","10"]}'
2017-11-10 03:54:06.834 UTC [msp] getMspConfig -> INFO 001 intermediate certs folder not found at [/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/intermediatecerts]. Skipping.: [stat /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/intermediatecerts: no such file or directory]
2017-11-10 03:54:06.834 UTC [msp] getMspConfig -> INFO 002 crls folder not found at [/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/intermediatecerts]. Skipping.: [stat /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/crls: no such file or directory]
2017-11-10 03:54:06.835 UTC [msp] getMspConfig -> INFO 003 MSP configuration file not found at [/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/config.yaml]: [stat /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/config.yaml: no such file or directory]
2017-11-10 03:54:06.882 UTC [msp] GetLocalMSP -> DEBU 004 Returning existing local MSP
2017-11-10 03:54:06.882 UTC [msp] GetDefaultSigningIdentity -> DEBU 005 Obtaining default signing identity
2017-11-10 03:54:06.887 UTC [msp/identity] Sign -> DEBU 006 Sign: plaintext: 0AB4070A6A08031A0C08DEC594D00510...696E766F6B650A01610A01620A023130
2017-11-10 03:54:06.887 UTC [msp/identity] Sign -> DEBU 007 Sign: digest: CD26EE32A303A100BE43D3CCDDA6403FAA35F497ACA0C96F8C46A95A2487BDFD
2017-11-10 03:54:06.902 UTC [msp/identity] Sign -> DEBU 008 Sign: plaintext: 0AB4070A6A08031A0C08DEC594D00510...82890A68992DCC72B079EC46631ECB78
2017-11-10 03:54:06.902 UTC [msp/identity] Sign -> DEBU 009 Sign: digest: 51965C0B97EEB31A296977BA323972119BC4BE62EE5F18BB70B1EC69CFDF787B
2017-11-10 03:54:06.920 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> DEBU 00a ESCC invoke result: version:1 response:<status:200 message:"OK" > payload:"\n \213<\t\264i\241\247\235\257W\230\242W\236\251\\\2234\256\214\265\243?\236\274Z\200\025AU\377\026\022b\nK\0220\n\007devincc\022%\n\007\n\001a\022\002\010\005\n\007\n\001b\022\002\010\005\032\007\n\001a\032\00290\032\010\n\001b\032\003210\022\027\n\004lscc\022\017\n\r\n\007devincc\022\002\010\005\032\003\010\310\001\"\016\022\007devincc\032\0031.0" endorsement:<endorser:"\n\007Org1MSP\022\325\006-----BEGIN -----\nMIICWTCCAgCgAwIBAgIQahOTRu7gpuR5AtIhNk3n1zAKBggqhkjOPQQDAjBzMQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eu\nb3JnMS5leGFtcGxlLmNvbTAeFw0xNzExMTAwMzQ2NDNaFw0yNzExMDgwMzQ2NDNa\nMFsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T\nYW4gRnJhbmNpc2NvMR8wHQYDVQQDExZwZWVyMC5vcmcxLmV4YW1wbGUuY29tMFkw\nEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEVn40lbdv6epcF1bx37dS9nbGJdRVCAkG\n7hsUKHdvjOi9fAsU0fatanSZjtv2gJq/fXB/f3huHUijTP9H413zsaOBjTCBijAO\nBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIw\nADArBgNVHSMEJDAigCBKiLTrKKZzBXbm3oXivXoLjt8WfFszW8Ca76+pGi+wQTAo\nBgNVHREEITAfghZwZWVyMC5vcmcxLmV4YW1wbGUuY29tggVwZWVyMDAKBggqhkjO\nPQQDAgNHADBEAiA1uMkgn7nAb3uk3C8sQG0jBNHbY09eDKqb3R6e2uagcwIgJg6w\nybzss2TAuaxqWMYX+JutKEJTlxSThiYjMaHcJds=\n-----END -----\n" signature:"0E\002!\000\341\334cR>\343\273\221\005E#\344[\032\377Q5IR\323qNH\3778\025,\243\243o(W\002 \013\036\220\234V\271\2651\005\254\301p\016&\254\216\202\211\nh\231-\314r\260y\354Fc\036\313x" >
2017-11-10 03:54:06.920 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 00b Chaincode invoke successful. result: status:200
2017-11-10 03:54:06.920 UTC [main] main -> INFO 00c Exiting.....

再调用query命令来查一下b账户的余额,如果没有计算错,应该是210元。

root@e5fee400df40:/opt/gopath/src/github.com/hyperledger/fabric/peer# peer chaincode query -C mychannel -n devincc -c '{"Args":["query","b"]}'
2017-11-10 03:54:24.515 UTC [msp] getMspConfig -> INFO 001 intermediate certs folder not found at [/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/intermediatecerts]. Skipping.: [stat /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/intermediatecerts: no such file or directory]
2017-11-10 03:54:24.515 UTC [msp] getMspConfig -> INFO 002 crls folder not found at [/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/intermediatecerts]. Skipping.: [stat /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/crls: no such file or directory]
2017-11-10 03:54:24.515 UTC [msp] getMspConfig -> INFO 003 MSP configuration file not found at [/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/config.yaml]: [stat /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/config.yaml: no such file or directory]
2017-11-10 03:54:24.554 UTC [msp] GetLocalMSP -> DEBU 004 Returning existing local MSP
2017-11-10 03:54:24.554 UTC [msp] GetDefaultSigningIdentity -> DEBU 005 Obtaining default signing identity
2017-11-10 03:54:24.555 UTC [msp/identity] Sign -> DEBU 006 Sign: plaintext: 0AB4070A6A08031A0C08F0C594D00510...696E63631A0A0A0571756572790A0162
2017-11-10 03:54:24.555 UTC [msp/identity] Sign -> DEBU 007 Sign: digest: 97999F9BEFEAB1D7976AA68ABF2199668568D00C6EC1CB6C7F2C83C4DF6CAA06
Query Result: 210

测试成功。退出docker容器,然后执行下面的指令退出fabric环境。

root@pony-virtual-machine:~/gopath/src/fabric-sample/release/linux-amd64# ./network_setup.sh down

源码剖析

上面说了,源码目录在$GOPATH/src/github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02目录下。

下面开始分析下这个示例chaincode。

type SimpleChaincode struct {
}func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {fmt.Println("ex02 Init")_, args := stub.GetFunctionAndParameters()var A, B string    // Entitiesvar Aval, Bval int // Asset holdingsvar err errorif len(args) != 4 {return shim.Error("Incorrect number of arguments. Expecting 4")}// Initialize the chaincodeA = args[0]Aval, err = strconv.Atoi(args[1])if err != nil {return shim.Error("Expecting integer value for asset holding")}B = args[2]Bval, err = strconv.Atoi(args[3])if err != nil {return shim.Error("Expecting integer value for asset holding")}fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)// Write the state to the ledgererr = stub.PutState(A, []byte(strconv.Itoa(Aval)))if err != nil {return shim.Error(err.Error())}err = stub.PutState(B, []byte(strconv.Itoa(Bval)))if err != nil {return shim.Error(err.Error())}return shim.Success(nil)
}

这里首先定义了一个SimpleChaincode类,并且实现了该类的一个方法Init

这个Init方法不是随便定义的,根据fabric官方指引,一个chaincode需要实现如下的接口,

type Chaincode interface {// Init is called during Instantiate transaction after the chaincode container// has been established for the first time, allowing the chaincode to// initialize its internal dataInit(stub ChaincodeStubInterface) pb.Response// Invoke is called to update or query the ledger in a proposal transaction.// Updated state variables are not committed to the ledger until the// transaction is committed.Invoke(stub ChaincodeStubInterface) pb.Response
}

当我们执行peer chaincode instantiate命令时,系统回调用我们实现的Init方法完成智能合约的初始化动作。

这里Init的实现其实比较简单,首先我们用GetFunctionAndParameters获取实例化传递过来的所有参数,并且要求参数的个数是四个。根据上面的instantiate指令我们知道传递的参数是

["init","a", "100", "b","200"]

可能有人会有疑问,这里不是5个参数吗?

其实GetFunctionAndParameters会返回两个值,第一个值是函数名,就是这里的”init”,第二个值就是后面的4个参数。

a和b这里我们表示两个账户(或者是两个人也可以),数字是他们对应的账户余额。然后我们用

strconv.Atoi把数字有字符串转化为整型方便后面打印处理。

PutState会把key和value先放入fabric的写集,并不会马上更新账本。(更新账本由节点完成,chaincode后续不需要参与)

再看看接口里的另外一个方法,

func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {fmt.Println("ex02 Invoke")function, args := stub.GetFunctionAndParameters()if function == "invoke" { // Make payment of X units from A to Breturn t.invoke(stub, args)} else if function == "delete" { // Deletes an entity from its statereturn t.delete(stub, args)} else if function == "query" { // the old "Query" is now implemtned in invokereturn t.query(stub, args)}return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"")
}

可以看到Invoke并没有做具体的事情,而是根据函数名分发到子函数处理。先来看看query查询的操作。当我们执行

peer chaincode query -C mychannel -n devincc -c '{"Args":["query","a"]}'

系统调用Invoke,function是”query”,参数是”a”, 进入query方法,

func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {var A string // Entitiesvar err errorif len(args) != 1 {return shim.Error("Incorrect number of arguments. Expecting name of the person to query")}A = args[0]// Get the state from the ledgerAvalbytes, err := stub.GetState(A)if err != nil {jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"return shim.Error(jsonResp)}if Avalbytes == nil {jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"return shim.Error(jsonResp)}jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"fmt.Printf("Query Response:%s\n", jsonResp)return shim.Success(Avalbytes)
}

关键的代码就是GetState这里,从账本获取指定key的value值,返回的是[]byte类型的值,然后通过shim.Sucess返回。

invoke和delete也都比较简单,这里就不多说了。

参考

http://www.cnblogs.com/studyzy/p/6973334.html

部署测试fabric1.0及源码解析相关推荐

  1. Android8.0 bindService源码解析

    1.AMS的bindService 我们从调用bindService方法开始来看 bindService(intent,serviceConnection, Context.BIND_AUTO_CRE ...

  2. Android7.0 bindService源码解析

    看到标题的时候,有些同学可能会有些质疑:现在都Android12了,你讲Android7,是不是太过时了.这里有两个原因: (1)Android8.0和Android7.0的源码有些不同,但是Andr ...

  3. EventBus1.0.1源码解析

    很久没有更新过源码解析类文章,以下内容作为源码分析类的笔记.分析方法适用于其它源码分析. 分析工具说明 许久以来,阅读源代码最得力的工具就非Source Insight莫属了.然,后来微软出了一款轻量 ...

  4. android9.0 UsbService源码解析

    文章目录 前言 一.服务启动 二.服务创建 三.系统就绪 四.系统启动完毕 前言 USBManager作为一接口类,客户端,当然要有一个服务端来支持工作,这个服务就是UsbService.我这里先从他 ...

  5. YYModel V1.0.4源码解析

    YYKit出现了很长时间了,一直想要详细解析一下它的源码,都是各种缘由推迟了. 最近稍微闲了一点,决定先从最简单的YYModel开始吧. 首先,我也先去搜索了一下YYModel相关的文章,解析主要AP ...

  6. android9.0 UsbManager源码解析

    文章目录 前言 一.UsbManager是什么? 二.每个类的简介 总结 前言 安卓手机可以通过USB连接外设,比如键盘,鼠标,摄像头.还可以与电脑互联进行数据传输,加强了对外扩展的能力. 这功能无疑 ...

  7. react native 0.50 源码解析 再出发 持续更新

    1.核心类 1.1 RCTRootView 一个RCTRootView持有一个RCTBridge成员变量 RCTRootView : UIViewRCTBridge *bridge;UIViewCon ...

  8. [Dubbo3.0.8源码解析系列]-12-全局视野来看Dubbo3.0.8的服务启动生命周期

    目录 12 全局视野来看Dubbo3的服务启动生命周期 12.1 启动方法简介 12.2 启动器启动方法的调用逻辑start() 12.3 应用程序发布器DefaultApplicationDeplo ...

  9. MyBatis源码- SqlSession门面模式 selectList 源码解析

    文章目录 Pre 工程概览 pom.xml mybatis-config.xml UserMapper 测试类 selectList 源码解析 附 SQL log4j.properties app.p ...

最新文章

  1. python eval 入门_Python学习笔记整理3之输入输出、python eval函数
  2. 智能风控平台核心之风控决策引擎(二)
  3. [css] css的属性content有什么作用呢?有哪些场景可以用到?
  4. 五、分治法应用--矩阵乘法
  5. sql server跨服务器修改数据,SQL Server跨数据库服务器查询和跨表更新的详细操作...
  6. 资深开发者告诉你“页游转手游”应注意的五大点
  7. cent os7 安装dubbo-admin 管理控制台
  8. c++编写手机小游戏代码_24个c++游戏源码
  9. Tomcat 修改启动端口号
  10. 地图制作:Google Earth Pro的下载及功能介绍(详细介绍)(上)
  11. u盘容量足够,但是提示目标文件过大无法复制的解决办法
  12. 小程序的转发分享功能
  13. android 陀螺仪滤波_高精度MEMS陀螺仪的滤波算法研究
  14. Jupyterhub batchspawner on PBS
  15. mysql脏读和幻读区别_数据库的脏读、不可重复读和幻读区别
  16. 深度 | 苹果略胜微软一筹,为什么说 ARKit 是 AR 的最好选择?
  17. 提供几个与Replika类似的聊天机器人
  18. seata xid是什么_急:IDMA是什么?SDMA又是什么?
  19. Java后端程序员1年工作经验总结
  20. 计算机高级语言与型号是否有关,高级语言与cPU型号无关吗?

热门文章

  1. 上海财经计算机专业考研,考研择校:魔都的复旦、同济、上财哪个更有前途?看网友怎么说!...
  2. 牛客-js练习|错题本+知识点总结-break、try...catch...finally(01)
  3. linux中 777,755等用户权限说明
  4. cocos2dx画扇形
  5. 开源办公的五个法律问题 ——以“新型冠状病毒”防控期间企业在线远程运营为视角...
  6. Java程序,判断一个字母是元音还是辅音
  7. Win11桌面右键菜单栏怎么回到Win10的样子(直接命令执行便可完成,简单快捷)
  8. MFC基础知识与课程设计思路
  9. 程序员如何找对象(1)
  10. 【2018年7月英语学习】--零散中星星点点