fabric sdk go 提供的官方文档少之又少,要想入门,主要就靠研究官方的e2e系列示例,这真的是一件挺无奈的事情。没法子,只能硬着头皮上了。研究发现,e2e这个例子是通过cryptogen生成网络所需的所有证书及密钥的。一旦你按着操作后,你会发现你被大堆目录淹没,不知所措,根本不知道他们都是干嘛的。

那么,这篇文章的作用,就是告诉你,他们都是干嘛的,哪些是初始化sdk所需的。

让我们开始吧!

生成证书配置

首先,用于生成证书目录的配置文件crypto-config.yaml内容如下所示

# "OrdererOrgs" - Definition of organizations managing orderer nodes
OrdererOrgs:
- Name: Mango
Domain: mango.com
# Specs is an array of Spec entries. Each Spec entry consists of two fields : Hostname and CommonName
Specs:
- Hostname: orderer
# "PeerOrgs" - Definition of organizations managing peer nodes
PeerOrgs:
- Name: Mango
Domain: mango.com
# Allows for the definition of 1 or more hosts that are created sequentially
# from a template. By default, this looks like "peer%d" from 0 to Count-1.
# You may override the number of nodes (Count), the starting index (Start)
# or the template used to construct the name (Hostname).
Template:
Count: 2

证书目录解析

我们根据上述配置来生成证书

mkdir -p crypto-config
./bin/cryptogen generate --config=./crypto-config.yaml

每个目录和对应文件的功能如下:

crypto-config
├── ordererOrganizations
│   └── mango.com # domain
│   ├── ca
│   │   ├── ca.mango.com-cert.pem
│   │   └── ed9854ea794ed178750ab5fff0b8f7a4c4938721e85de25a65e171dac4dadf41_sk
│   ├── msp
│   │   ├── admincerts
│   │   │   └── Admin@mango.com-cert.pem
│   │   ├── cacerts
│   │   │   └── ca.mango.com-cert.pem
│   │   └── tlscacerts
│   │   └── tlsca.mango.com-cert.pem
│   ├── orderers
│   │   └── orderer.mango.com
│   │   ├── msp
│   │   │   ├── admincerts
│   │   │   │   └── Admin@mango.com-cert.pem
│   │   │   ├── cacerts
│   │   │   │   └── ca.mango.com-cert.pem
│   │   │   ├── keystore
│   │   │   │   └── b1ee6269b624746f682843f566dcfdbb9b1318ea36d605becc13843f52d13e2c_sk
│   │   │   ├── signcerts
│   │   │   │   └── orderer.mango.com-cert.pem
│   │   │   └── tlscacerts
│   │   │   └── tlsca.mango.com-cert.pem
│   │   └── tls
│   │   ├── ca.crt
│   │   ├── server.crt
│   │   └── server.key
│   ├── tlsca
│   │   ├── 30fe7e37c6b416049d567b99d07d4d0fca282d28cf51819a8ba9cb12a4b1b5c1_sk
│   │   └── tlsca.mango.com-cert.pem
│   └── users
│   └── Admin@mango.com
│   ├── msp
│   │   ├── admincerts
│   │   │   └── Admin@mango.com-cert.pem
│   │   ├── cacerts
│   │   │   └── ca.mango.com-cert.pem
│   │   ├── keystore
│   │   │   └── 749735ce27f18879efa1ffdf76bf9d800ccb0298c826cee2c2d68217eb731610_sk
│   │   ├── signcerts
│   │   │   └── Admin@mango.com-cert.pem
│   │   └── tlscacerts
│   │   └── tlsca.mango.com-cert.pem
│   └── tls
│   ├── ca.crt
│   ├── client.crt
│   └── client.key
└── peerOrganizations
└── org1.mango.com
├── ca # 存放组织的根证书和对应的私钥文件,默认采用EC算法,证书为自签名。组织内的实体将基于该证书作为证书根。
│   ├── 2c3c2cde48c8f1b5eb0fd54e0b1865d6b5bc3269ebba8cb5ac5a7dfbbd303367_sk
│   └── ca.org1.mango.com-cert.pem
├── msp # 存放代表该组织的身份信息。
│   ├── admincerts # 组织管理员的身份验证证书,被根证书签名。
│   │   └── Admin@org1.mango.com-cert.pem
│   ├── cacerts # 组织的根证书,同ca目录下文件。
│   │   └── ca.org1.mango.com-cert.pem
│   └── tlscacerts # 用于TLS的ca证书,自签名。
│   └── tlsca.org1.mango.com-cert.pem
├── peers # 存放属于该组织的所有peer节点。
│   ├── peer0.org1.mango.com # 第一个peer的信息,包括其msp证书和TLS证书两类。
│   │   ├── msp
│   │   │   ├── admincerts # 组织管理员的身份验证证书。peer将基于这些证书来认证交易签署这是否为管理员身份。
│   │   │   │   └── Admin@org1.mango.com-cert.pem
│   │   │   ├── cacerts # 组织的根证书.
│   │   │   │   └── ca.org1.mango.com-cert.pem
│   │   │   ├── keystore # 本节点的身份私钥,用来签名。
│   │   │   │   └── d35fbb340c84ad06ffd6d58addaf694a62e23adf53066b9a287f86edbf6dd476_sk
│   │   │   ├── signcerts # 验证本节点签名的证书,被组织根证书签名。
│   │   │   │   └── peer0.org1.mango.com-cert.pem
│   │   │   └── tlscacerts # TLS连接用的身份证书,即组织TLS证书。
│   │   │   └── tlsca.org1.mango.com-cert.pem
│   │   └── tls # 存放tls相关的证书和私钥
│   │   ├── ca.crt # 组织的根证书
│   │   ├── server.crt # 验证本节点签名的证书,被组织根证书签名。
│   │   └── server.key # 本节点的身份私钥,用来签名。
│   └── peer1.org1.mango.com # 第二个peer的信息,结构类似。(省略)
│   ├── msp
│   │   ├── admincerts
│   │   │   └── Admin@org1.mango.com-cert.pem
│   │   ├── cacerts
│   │   │   └── ca.org1.mango.com-cert.pem
│   │   ├── keystore
│   │   │   └── ecfeefdab7f95113064a00227d7af5cb3ae448ec1334a932f768010b95dc32f3_sk
│   │   ├── signcerts
│   │   │   └── peer1.org1.mango.com-cert.pem
│   │   └── tlscacerts
│   │   └── tlsca.org1.mango.com-cert.pem
│   └── tls
│   ├── ca.crt
│   ├── server.crt
│   └── server.key
├── tlsca 存放组织tls连接用的根证书和私钥文件。(TLS是传输层安全协议,其实就是SSL,现在叫TLS了)
│   ├── 65b65931318b4aa19ae15d1da75413c68371d1506237311fc7244c8e46c1ba8a_sk
│   └── tlsca.org1.mango.com-cert.pem # TLS根证书
└── users 存放属于该组织的用户的实体。
└── Admin@org1.mango.com # 管理员用户的信息,包括其msp证书和tls证书两类。
├── msp
│   ├── admincerts # 组织根证书作为管理者身份验证证书。
│   │   └── Admin@org1.mango.com-cert.pem
│   ├── cacerts # 组织的根证书.
│   │   └── ca.org1.mango.com-cert.pem
│   ├── keystore # 本用户的身份私钥,用来签名。
│   │   └── 22e70042f7dd79f35ea92a285d2377a673163805f85c9bf160c87de82db52a4c_sk
│   ├── signcerts # 管理员用户的身份验证证书,被组织根证书签名。要被某个Peer认可,则必须放到该peer的msp/admincerts下。
│   │   └── Admin@org1.mango.com-cert.pem
│   └── tlscacerts # TLS连接用的身份证书,即组织TLS证书。
│   └── tlsca.org1.mango.com-cert.pem
└── tls # 存放tls相关的证书和私钥
├── ca.crt # 组织的根证书
├── client.crt # 管理员的用户身份验证证书,被组织根证书签名。
└── client.key # 管理员用户的身份私钥,用来签名。

证书目录精简

一大堆文件是不是?其实经过分析后,可以发现,很多目录的证书或者密钥都是重复的。真正用到的主要是

  • 组织中 Admin用户的证书和密钥
  • 组织中的tls证书

如果你启用了其他用户,比如User1之类的,就还会有User1@mango.com这样的目录

精简目录

让我们删除多余目录,精简后目录如下所示:

fixtures/crypto/
├── ordererOrganizations
│   └── mango.com
│   ├── tlsca
│      └── tlsca.org1.mango.com-cert.pem
└── peerOrganizations
└── org1.mango.com
├── tlsca
│   └── tlsca.org1.mango.com-cert.pem
└── users
└── Admin@org1.mango.com
└── msp
├── keystore
│   └── 22e70042f7dd79f35ea92a285d2377a673163805f85c9bf160c87de82db52a4c_sk
└── signcerts
└── Admin@org1.mango.com-cert.pem

怎么样,是不是清爽多了。

证书目录再精简

本节内容依个人业务差异,仅供参考

我们发现证书的路径六面都带有mango.com这样的ID字段,不方便重用,我们可以选择去除这些ID,精简目录。

此外,密钥文件22e70042f7dd79f35ea92a285d2377a673163805f85c9bf160c87de82db52a4c_sk名称前面还有一长串的字符,看上去很奇怪是不是。这个一长串的字符,其实就是ski。我们也可以去除这个ski。

当然,如果你直接去除这些东西,那么sdk会报找不到响应文件的错误,所以我们需要去修改sdk源码。

主要修改的文件如下:

fabric-go-sdk/pkg/msp/filecertstore.go

原先代码

// NewFileCertStore ...
func NewFileCertStore(cryptoConfigMSPPath string) (core.KVStore, error) {
_, orgName := path.Split(path.Dir(path.Dir(path.Dir(cryptoConfigMSPPath))))
opts := &keyvaluestore.FileKeyValueStoreOptions{
Path: cryptoConfigMSPPath,
KeySerializer: func(key interface{}) (string, error) {
ck, ok := key.(*msp.IdentityIdentifier)
if !ok {
return "", errors.New("converting key to CertKey failed")
}
if ck == nil || ck.MSPID == "" || ck.ID == "" {
return "", errors.New("invalid key")
} // TODO: refactor to case insensitive or remove eventually.
r := strings.NewReplacer("{userName}", ck.ID, "{username}", ck.ID)
certDir := path.Join(r.Replace(cryptoConfigMSPPath), "signcerts")
return path.Join(certDir, fmt.Sprintf("%s@%s-cert.pem", ck.ID, orgName)), nil
},
}
return keyvaluestore.New(opts)
}

修改后代码

// NewFileCertStore ...
func NewFileCertStore(cryptoConfigMSPPath string) (core.KVStore, error) {
opts := &keyvaluestore.FileKeyValueStoreOptions{
Path: cryptoConfigMSPPath,
KeySerializer: func(key interface{}) (string, error) {
ck, ok := key.(*msp.IdentityIdentifier)
if !ok {
return "", errors.New("converting key to CertKey failed")
}
if ck == nil || ck.MSPID == "" || ck.ID == "" {
return "", errors.New("invalid key")
}
// TODO: refactor to case insensitive or remove eventually.
// 文件夹去除Mspid名称
r := strings.NewReplacer("{userName}", ck.ID)
certDir := path.Join(r.Replace(cryptoConfigMSPPath), "signcerts")
// 文件名精简为cert.pem
return path.Join(certDir, "cert.pem"), nil
},
}
return keyvaluestore.New(opts)
}

fabric-go-sdk/pkg/msp/filecertstore.go

原先代码

// NewFileKeyStore ...
func NewFileKeyStore(cryptoConfigMSPPath string) (core.KVStore, error) {
opts := &keyvaluestore.FileKeyValueStoreOptions{
Path: cryptoConfigMSPPath,
KeySerializer: func(key interface{}) (string, error) {
pkk, ok := key.(*msp.PrivKeyKey)
if !ok {
return "", errors.New("converting key to PrivKeyKey failed")
}
if pkk == nil || pkk.MSPID == "" || pkk.ID == "" || pkk.SKI == nil {
return "", errors.New("invalid key")
} // TODO: refactor to case insensitive or remove eventually.
r := strings.NewReplacer("{userName}", pkk.ID, "{username}", pkk.ID)
keyDir := path.Join(r.Replace(cryptoConfigMSPPath), "keystore") return path.Join(keyDir, hex.EncodeToString(pkk.SKI)+"_sk"), nil
},
}
return keyvaluestore.New(opts)
}

修改后代码

// NewFileKeyStore ...
func NewFileKeyStore(cryptoConfigMSPPath string) (core.KVStore, error) {
opts := &keyvaluestore.FileKeyValueStoreOptions{
Path: cryptoConfigMSPPath,
KeySerializer: func(key interface{}) (string, error) {
pkk, ok := key.(*msp.PrivKeyKey)
if !ok {
return "", errors.New("converting key to PrivKeyKey failed")
}
if pkk == nil || pkk.MSPID == "" || pkk.ID == "" || pkk.SKI == nil {
return "", errors.New("invalid key")
} // TODO: refactor to case insensitive or remove eventually.
r := strings.NewReplacer("{userName}", pkk.ID, "{username}", pkk.ID)
keyDir := path.Join(r.Replace(cryptoConfigMSPPath), "keystore")
// 文件名统一为_sk
return path.Join(keyDir, "_sk"), nil
},
}
return keyvaluestore.New(opts)
}

再次精简后的目录

如此修改后,对应的证书目录,我们就可以改成如下所示:

fixtures/crypto/
├── ordererOrganizations
│   └── tlsca
│   └── tlsca-cert.pem
└── peerOrganizations
├── tlsca
│   └── tlsca-cert.pem
└── users
└── Admin
└── msp
├── keystore
│   └── _sk
└── signcerts
└── cert.pem

怎么样,是不是又精简了很多?

初始化SDK配置文件

最后附上相应的初始化sdk所需的config.yaml文件

name: "mango-service-network"
#
# Schema version of the content. Used by the SDK to apply the corresponding parsing rules.
#
version: 1.0.0
#
# The client section used by GO SDK.
#
client: # Which organization does this application instance belong to? The value must be the name of an org
# defined under "organizations"
organization: org1 logging:
level: info # Global configuration for peer, event service and orderer timeouts
# if this this section is omitted, then default values will be used (same values as below)
# peer:
# timeout:
# connection: 10s
# response: 180s
# discovery:
# # Expiry period for discovery service greylist filter
# # The channel client will greylist peers that are found to be offline
# # to prevent re-selecting them in subsequent retries.
# # This interval will define how long a peer is greylisted
# greylistExpiry: 10s
# eventService:
# # Event service type (optional). If not specified then the type is automatically
# # determined from channel capabilities.
# type: (deliver|eventhub)
# the below timeouts are commented out to use the default values that are found in
# "pkg/fab/endpointconfig.go"
# the client is free to override the default values by uncommenting and resetting
# the values as they see fit in their config file
# timeout:
# connection: 15s
# registrationResponse: 15s
# orderer:
# timeout:
# connection: 15s
# response: 15s
# global:
# timeout:
# query: 180s
# execute: 180s
# resmgmt: 180s
# cache:
# connectionIdle: 30s
# eventServiceIdle: 2m
# channelConfig: 30m
# channelMembership: 30s
# discovery: 10s
# selection: 10m # Root of the MSP directories with keys and certs.
cryptoconfig:
path: ${GOPATH}/src/github.com/hyperledger/fabric-sdk-go-api/fixtures/crypto # Some SDKs support pluggable KV stores, the properties under "credentialStore"
# are implementation specific
credentialStore:
path: /tmp/mango-service-store # [Optional]. Specific to the CryptoSuite implementation used by GO SDK. Software-based implementations
# requiring a key store. PKCS#11 based implementations does not.
cryptoStore:
path: /tmp/mango-service-msp # BCCSP config for the client. Used by GO SDK.
BCCSP:
security:
enabled: true
default:
provider: "SW"
hashAlgorithm: "SHA2"
softVerify: true
level: 256 tlsCerts:
# [Optional]. Use system certificate pool when connecting to peers, orderers (for negotiating TLS) Default: false
systemCertPool: false # [Optional]. Client key and cert for TLS handshake with peers and orderers
client:
keyfile:
certfile: #
# [Optional]. But most apps would have this section so that channel objects can be constructed
# based on the content below. If an app is creating channels, then it likely will not need this
# section.
#
channels:
# name of the channel
mychannel:
# Required. list of orderers designated by the application to use for transactions on this
# channel. This list can be a result of access control ("org1" can only access "ordererA"), or
# operational decisions to share loads from applications among the orderers. The values must
# be "names" of orgs defined under "organizations/peers"
# deprecated: not recommended, to override any orderer configuration items, entity matchers should be used.
# orderers:
# - orderer.example.com # Required. list of peers from participating orgs
peers:
peer0.org1.mango.com:
# [Optional]. will this peer be sent transaction proposals for endorsement? The peer must
# have the chaincode installed. The app can also use this property to decide which peers
# to send the chaincode install request. Default: true
endorsingPeer: true # [Optional]. will this peer be sent query proposals? The peer must have the chaincode
# installed. The app can also use this property to decide which peers to send the
# chaincode install request. Default: true
chaincodeQuery: true # [Optional]. will this peer be sent query proposals that do not require chaincodes, like
# queryBlock(), queryTransaction(), etc. Default: true
ledgerQuery: true # [Optional]. will this peer be the target of the SDK's listener registration? All peers can
# produce events but the app typically only needs to connect to one to listen to events.
# Default: true
eventSource: true peer1.org1.mango.com: policies:
#[Optional] options for retrieving channel configuration blocks
queryChannelConfig:
#[Optional] min number of success responses (from targets/peers)
minResponses: 1
#[Optional] channel config will be retrieved for these number of random targets
maxTargets: 1
#[Optional] retry options for query config block
retryOpts:
#[Optional] number of retry attempts
attempts: 5
#[Optional] the back off interval for the first retry attempt
initialBackoff: 500ms
#[Optional] the maximum back off interval for any retry attempt
maxBackoff: 5s
#[Optional] he factor by which the initial back off period is exponentially incremented
backoffFactor: 2.0 #
# list of participating organizations in this network
#
organizations:
org1:
mspid: org1.mango.com
cryptoPath: peerOrganizations/users/{userName}/msp
peers:
- peer0.org1.mango.com
- peer1.org1.mango.com # [Optional]. Certificate Authorities issue certificates for identification purposes in a Fabric based
# network. Typically certificates provisioning is done in a separate process outside of the
# runtime network. Fabric-CA is a special certificate authority that provides a REST APIs for
# dynamic certificate management (enroll, revoke, re-enroll). The following section is only for
# Fabric-CA servers.
certificateAuthorities:
- ca.org1.mango.com #
# List of orderers to send transaction and channel create/update requests to. For the time
# being only one orderer is needed. If more than one is defined, which one get used by the
# SDK is implementation specific. Consult each SDK's documentation for its handling of orderers.
#
orderers:
orderer.mango.com:
url: localhost:7050 # these are standard properties defined by the gRPC library
# they will be passed in as-is to gRPC client constructor
grpcOptions:
ssl-target-name-override: orderer.mango.com
# These parameters should be set in coordination with the keepalive policy on the server,
# as incompatible settings can result in closing of connection.
# When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled
keep-alive-time: 0s
keep-alive-timeout: 20s
keep-alive-permit: false
fail-fast: false
# allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs
allow-insecure: false tlsCACerts:
# Certificate location absolute path
path: ${GOPATH}/src/github.com/hyperledger/fabric-sdk-go-api/fixtures/crypto/ordererOrganizations/tlsca/tlsca-cert.pem
#
# List of peers to send various requests to, including endorsement, query
# and event listener registration.
#
peers:
peer0.org1.mango.com:
# this URL is used to send endorsement and query requests
url: localhost:7051
# eventUrl is only needed when using eventhub (default is delivery service)
eventUrl: localhost:7053 grpcOptions:
ssl-target-name-override: peer0.org1.mango.com
# These parameters should be set in coordination with the keepalive policy on the server,
# as incompatible settings can result in closing of connection.
# When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled
keep-alive-time: 0s
keep-alive-timeout: 20s
keep-alive-permit: false
fail-fast: false
# allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs
allow-insecure: false tlsCACerts:
# Certificate location absolute path
path: ${GOPATH}/src/github.com/hyperledger/fabric-sdk-go-api/fixtures/crypto/peerOrganizations/tlsca/tlsca-cert.pem peer1.org1.mango.com:
# this URL is used to send endorsement and query requests
url: localhost:8051
# eventUrl is only needed when using eventhub (default is delivery service)
eventUrl: localhost:8053 grpcOptions:
ssl-target-name-override: peer1.org1.mango.com
# These parameters should be set in coordination with the keepalive policy on the server,
# as incompatible settings can result in closing of connection.
# When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled
keep-alive-time: 0s
keep-alive-timeout: 20s
keep-alive-permit: false
fail-fast: false
# allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs
allow-insecure: false tlsCACerts:
# Certificate location absolute path
path: ${GOPATH}/src/github.com/hyperledger/fabric-sdk-go-api/fixtures/crypto/peerOrganizations/tlsca/tlsca-cert.pem entityMatchers:
peer:
- pattern: (\w*)peer0.org1.mango.com(\w*)
urlSubstitutionExp: localhost:7051
eventUrlSubstitutionExp: localhost:7053
sslTargetOverrideUrlSubstitutionExp: peer0.org1.mango.com
mappedHost: peer0.org1.mango.com - pattern: (\w*)peer1.org1.mango.com(\w*)
urlSubstitutionExp: localhost:8051
eventUrlSubstitutionExp: localhost:8053
sslTargetOverrideUrlSubstitutionExp: peer1.org1.mango.com
mappedHost: peer1.org1.mango.com orderer:
- pattern: (\w*)orderer.mango.com(\w*)
urlSubstitutionExp: localhost:7050
sslTargetOverrideUrlSubstitutionExp: orderer.mango.com
mappedHost: orderer.mango.com

当然,这部分内容,也是存在优化空间的,还没研究那么深入,后面有空再改。

参考文章

搭建基于hyperledger fabric的联盟社区(八) --Fabric证书解析

Fabric go sdk初始化所需证书解析的更多相关文章

  1. 使用Fabric Node SDK进行Invoke和Query

    前面的文章都是在讲解Fabric网络的搭建和ChainCode的开发,那么在ChainCode开发完毕后,我们就需要使用Fabric SDK做应用程序的开发了.官方虽然提供了Node.JS,Java, ...

  2. Hyperledger Fabric Node SDK和应用开发

    Hyperledger Fabric 提供了多种语言的SDK版本,其中提出比较早.比较稳定而全面的是Node.js版本的SDK. 前面提到的fabric示例(如first-network和e2e-cl ...

  3. 转:Eclipse ADT的Custom debug keystore所需证书规格

    转:http://blog.k-res.net/archives/1229.html Eclipse ADT的Custom debug keystore所需证书规格 三月 8, 2013  |  Po ...

  4. Hyperledger Fabric 实战(十): Fabric node SDK 样例 - 投票DAPP

    Fabric node SDK 样例 - 投票DAPP 参考 fabric-samples 下的 fabcar 加以实现 目录结构 . ├── app │ ├── controllers │ │ └─ ...

  5. 搭建基于hyperledger fabric的联盟社区(八) --Fabric证书解析

    一.证书目录解析   通过cryptogen生成所有证书文件后,以peerOrgannizations的第一个组织树org1为例,每个目录和对应文件的功能如下:   ca: 存放组织的根证书和对应的私 ...

  6. Fabric证书解析

    一.证书目录解析   通过cryptogen生成所有证书文件后,以peerOrgannizations的第一个组织树org1为例,每个目录和对应文件的功能如下:   ca: 存放组织的根证书和对应的私 ...

  7. 搭建RESTful API来使用Fabric Node SDK 开篇

    在Balance-Transfer中,有关于Node SDK比较完备的例子. SDK的官方文档在这里:https://fabric-sdk-node.github.io/ Balance-Transf ...

  8. Linux内核(11) - 子系统的初始化之内核选项解析

    首先感谢国家.其次感谢上大的钟莉颖,让我知道了大学不仅有校花,还有校鸡,而且很多时候这两者其实没什么差别.最后感谢清华女刘静,让我深刻体会到了素质教育的重要性,让我感到有责任写写子系统的初始化. 各个 ...

  9. 基于Spring注解的上下文初始化过程源码解析(一)

    最近工作之余有时间和精力,加上平时对源码比较感兴趣,就开始啃起了Spring源码.为加深印象写了这篇博客,如有错误,望各位大佬不吝指正. 我看的是Spring5的源码,从同性社区download下来后 ...

随机推荐

  1. PL/SQL Developer import and export database method and illustrate

    PL/SQL Developer import and export database method and illustrate   HOW WELL DO YOU KNOW THE APPLE U ...

  2. 利用Surfingkeys和tampermonkey效率操作网页

    tampermonkey可以实现网页载入后自动进行某些操作,适合有规律的操作,实现完全自动化. 而Surfingkeys可以实现用各种按键实现各种功能,功能全部用JavaScript写,自定义性更强.

  3. *Amazon problem: 234. Palindrome Linked List (reverse the linked list with n time)

    Given a singly linked list, determine if it is a palindrome. Example 1: Input: 1->2 Output: false ...

  4. CSU计算机研究生推免

    考研复习 一开始,我是没有想到能够拿到研究生推免资格的,从今年3月份到整个暑假过完,一共6个月的时间,我一直在准备考研. 具体来说,我是在准备考研数学,整整6个月时间的数学复习,给我一种感觉,把大一大 ...

  5. mac下登录服务器

    1.先通过帐号密码登录到服务器: ssh 用户名@服务器地址 https://jingyan.baidu.com/article/546ae1853132bf1148f28c42.html 2.登录后 ...

  6. Hibernate注解开发示例

    -------------------------------------------------------------------customer------------------------- ...

  7. 学大伟业 Day 3 培训总结

    今天讲的字符串: 不多说,直接看题 一.表达式求值 题目大意: 输入一行一个表达式,计算其答案 表达式包含非负整数.加减乘除.括号 两种做法 ·栈 ·表达式树 这里更推荐表达式树,因为栈是先压进去,逆 ...

  8. SQL Error: 1064, SQLState: 42000 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version

    -- ::, WARN [org.hibernate.util.JDBCExceptionReporter:] - SQL Error: , SQLState: -- ::, ERROR [org.h ...

  9. POJ 2533 Longest Ordered Subsequence(裸LIS)

    传送门: http://poj.org/problem?id=2533 Longest Ordered Subsequence Time Limit: 2000MS   Memory Limit: 6 ...

  10. ImportError: No module named lmdb

    why? 具体原因没有查清楚.安装caffe时,按照要求安装了包,caffe用的好好的,而且我也用打好包的lmdb跑了程序了.可我今天想看一下我的打包数据是不是漏掉数据了,直接开个python窗口,i ...