亚洲AV无码久久寂寞少妇,亚洲成在人线电影天堂色,人人狠狠综合久久亚洲http://www.tkk7.com/fool/堅持就是勝利!zh-cnFri, 09 May 2025 22:11:47 GMTFri, 09 May 2025 22:11:47 GMT60DDD小結http://www.tkk7.com/fool/archive/2019/07/08/434108.html傻 瓜傻 瓜Mon, 08 Jul 2019 08:49:00 GMThttp://www.tkk7.com/fool/archive/2019/07/08/434108.htmlhttp://www.tkk7.com/fool/comments/434108.htmlhttp://www.tkk7.com/fool/archive/2019/07/08/434108.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/434108.htmlhttp://www.tkk7.com/fool/services/trackbacks/434108.html閱讀全文

傻 瓜 2019-07-08 16:49 發(fā)表評論
]]>
優(yōu)秀代碼賞析http://www.tkk7.com/fool/archive/2019/07/06/434083.html傻 瓜傻 瓜Sat, 06 Jul 2019 04:06:00 GMThttp://www.tkk7.com/fool/archive/2019/07/06/434083.htmlhttp://www.tkk7.com/fool/comments/434083.htmlhttp://www.tkk7.com/fool/archive/2019/07/06/434083.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/434083.htmlhttp://www.tkk7.com/fool/services/trackbacks/434083.html看開源的源代碼,看到一個有意思的實現(xiàn) 。
/*
 * Copyright 2019 IBM All Rights Reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 */
package org.hyperledger.fabric.gateway;
import org.hyperledger.fabric.gateway.impl.AllCommitStrategy;
import org.hyperledger.fabric.gateway.impl.AnyCommitStrategy;
import org.hyperledger.fabric.gateway.impl.CommitHandlerImpl;
import org.hyperledger.fabric.gateway.impl.CommitStrategy;
import org.hyperledger.fabric.gateway.impl.NoOpCommitHandler;
import org.hyperledger.fabric.gateway.spi.CommitHandler;
import org.hyperledger.fabric.gateway.spi.CommitHandlerFactory;
import org.hyperledger.fabric.sdk.Peer;
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import java.util.Collection;
/**
 * Default commit handler implementations. Instances can be referenced directly or looked up by name, for example
 * {@code DefaultCommitHandlers.valueOf("NONE")}.
 */
public enum DefaultCommitHandlers implements CommitHandlerFactory {
    /**
     * Do not wait for any commit events to be received from peers after submitting a transaction.
     */
    NONE((transactionId, network) -> NoOpCommitHandler.INSTANCE),
    /**
     * Wait to receive commit events from all currently responding peers in the user's organization after submitting
     * a transaction.
     */
    MSPID_SCOPE_ALLFORTX((transactionId, network) -> {
        Collection<Peer> peers = getPeersForOrganization(network);
        CommitStrategy strategy = new AllCommitStrategy(peers);
        CommitHandler handler = new CommitHandlerImpl(transactionId, network, strategy);
        return handler;
    }),
    /**
     * Wait to receive commit events from all currently responding peers in the network after submitting a transaction.
     */
    NETWORK_SCOPE_ALLFORTX((transactionId, network) -> {
        Collection<Peer> peers = network.getChannel().getPeers();
        CommitStrategy strategy = new AllCommitStrategy(peers);
        CommitHandler handler = new CommitHandlerImpl(transactionId, network, strategy);
        return handler;
    }),
    /**
     * Wait to receive a commit event from any currently responding peer in the user's organization after submitting
     * a transaction.
     */
    MSPID_SCOPE_ANYFORTX((transactionId, network) -> {
        Collection<Peer> peers = getPeersForOrganization(network);
        CommitStrategy strategy = new AnyCommitStrategy(peers);
        CommitHandler handler = new CommitHandlerImpl(transactionId, network, strategy);
        return handler;
    }),
    /**
     * Wait to receive a commit event from any currently responding peer in the network after submitting a transaction.
     */
    NETWORK_SCOPE_ANYFORTX((transactionId, network) -> {
        Collection<Peer> peers = network.getChannel().getPeers();
        CommitStrategy strategy = new AnyCommitStrategy(peers);
        CommitHandler handler = new CommitHandlerImpl(transactionId, network, strategy);
        return handler;
    });
    private final CommitHandlerFactory factory;
    DefaultCommitHandlers(CommitHandlerFactory factory) {
        this.factory = factory;
    }
    private static Collection<Peer> getPeersForOrganization(Network network) {
        String mspId = network.getGateway().getIdentity().getMspId();
        try {
            return network.getChannel().getPeersForOrganization(mspId);
        } catch (InvalidArgumentException e) {
            // This should never happen as mspId should not be null
            throw new RuntimeException(e);
        }
    }

   //CommitHandlerFactory 接口定義 的方法,這里是其實現(xiàn) 
    public CommitHandler create(String transactionId, Network network) {
        return factory.create(transactionId, network);
    }
}

先看看enum類的構造函數(shù)
    DefaultCommitHandlers(CommitHandlerFactory factory) {
        this.factory = factory;
    }
需要一個 CommitHandlerFactory 是個接口,同時 enum類本身也實現(xiàn)了這個接口。
再來看調(diào)用過程 
CommitHandlerFactory commitHandlerFactory = DefaultCommitHandlers.MSPID_SCOPE_ALLFORTX;
這里會調(diào)用CommitHandlerFactory 構造函數(shù),其傳入?yún)?shù)是
(transactionId, network) -> {
        Collection<Peer> peers = network.getChannel().getPeers();
        CommitStrategy strategy = new AllCommitStrategy(peers);
        CommitHandler handler = new CommitHandlerImpl(transactionId, network, strategy);
        return handler;
    }
它是lamdba寫法,看看構造函數(shù)需要一個 CommitHandlerFactory 接口,這個lamdba 函數(shù)其實就是CommitHandlerFactory 的實現(xiàn)。
這樣MSPID_SCOPE_ALLFORTX 枚舉類型就有了一個  CommitHandlerFactory實現(xiàn)類的引用。

再看create調(diào)用。
CommitHandler commitHandler = commitHandlerFactory.create(transactionId, network);
這里enum類的create方法會執(zhí)行, return factory.create(transactionId, network);
返回一個 CommitHandler .這里才會真正執(zhí)行那個 lamdba定義的函數(shù)。
到這里只看到lamdb應用。。。
再分析一下create ,枚舉類里的每個枚舉變量都會實現(xiàn)一個這個方法。這里可以看到它其實是一個工廠類。
它創(chuàng)造的產(chǎn)品是CommitHandler ,其具體實現(xiàn)是CommitHandlerImpl類。
這里巧妙的使用一個enum當工廠類的實現(xiàn)。整個代碼用了工廠模式加策略模式的實現(xiàn)。
優(yōu)點:得宜于lamdb的應用,減少了具體工廠類的實現(xiàn)。
缺點:工廠模式可以實現(xiàn)不改動程序創(chuàng)建產(chǎn)品。那么這里如果要增一個產(chǎn)品,對這個enum類需要再添加一個枚舉變量。
這個enum類有改動。




傻 瓜 2019-07-06 12:06 發(fā)表評論
]]>
一個DDD示例代碼http://www.tkk7.com/fool/archive/2019/06/27/433990.html傻 瓜傻 瓜Thu, 27 Jun 2019 09:09:00 GMThttp://www.tkk7.com/fool/archive/2019/06/27/433990.htmlhttp://www.tkk7.com/fool/comments/433990.htmlhttp://www.tkk7.com/fool/archive/2019/06/27/433990.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/433990.htmlhttp://www.tkk7.com/fool/services/trackbacks/433990.htmlgithub上的一個java版的DDD實現(xiàn)的示例代碼. 學習DDD時看一下還是不錯的。
https://github.com/daoqidelv/community-ddd-demo.git
作者不是俺!

傻 瓜 2019-06-27 17:09 發(fā)表評論
]]>
Fabric 1.1源代碼分析(4) msp初始化過程http://www.tkk7.com/fool/archive/2018/06/25/433286.html傻 瓜傻 瓜Mon, 25 Jun 2018 01:00:00 GMThttp://www.tkk7.com/fool/archive/2018/06/25/433286.htmlhttp://www.tkk7.com/fool/comments/433286.htmlhttp://www.tkk7.com/fool/archive/2018/06/25/433286.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/433286.htmlhttp://www.tkk7.com/fool/services/trackbacks/433286.html

 (MSP)是一個提供虛擬成員操作的管理框架的組件。
MSP抽取出簽發(fā)和驗證證書以及用戶認證背后的所有加密機制和協(xié)議。 MSP可以定義自己的身份概念,以及這些身份管理的規(guī)則(身份驗證)和身份驗證(簽名生成和驗證)。

1、MSP接口定義
// MSP is the minimal Membership Service Provider Interface to be implemented
// to accommodate peer functionality
//最基本成員服務接口 其實現(xiàn)在mspimp.go文件中
type MSP interface {
// IdentityDeserializer interface needs to be implemented by MSP
IdentityDeserializer
// Setup the MSP instance according to configuration information
Setup(config *msp.MSPConfig) error
// GetVersion returns the version of this MSP
GetVersion() MSPVersion
// GetType returns the provider type
GetType() ProviderType
// GetIdentifier returns the provider identifier
GetIdentifier() (string, error)
// GetSigningIdentity returns a signing identity corresponding to the provided identifier
GetSigningIdentity(identifier *IdentityIdentifier) (SigningIdentity, error)
// GetDefaultSigningIdentity returns the default signing identity
GetDefaultSigningIdentity() (SigningIdentity, error)
// GetTLSRootCerts returns the TLS root certificates for this MSP
GetTLSRootCerts() [][]byte
// GetTLSIntermediateCerts returns the TLS intermediate root certificates for this MSP
GetTLSIntermediateCerts() [][]byte
// Validate checks whether the supplied identity is valid
Validate(id Identity) error
// SatisfiesPrincipal checks whether the identity matches
// the description supplied in MSPPrincipal. The check may
// involve a byte-by-byte comparison (if the principal is
// a serialized identity) or may require MSP validation
SatisfiesPrincipal(id Identity, principal *msp.MSPPrincipal) error
}
2、 BCCSP接口定義 BCCSP是加、解密及簽名服務。 bccp.go文件中默認實現(xiàn)是sw/impl.go .
支持ecdsa、rsa以及aes算法 BCCSP的實現(xiàn)包括:
1,[sw]目錄為the software-based implementation of the BCCSP,即基于軟件的BCCSP實現(xiàn),通過調(diào)用go原生支持的密碼算法實現(xiàn),并提供keystore來保存密鑰
2,[pkcs11]目錄,為bccsp的pkcs11實現(xiàn),通過調(diào)用pkcs11接口實現(xiàn)相關加密操作,,密碼保存在pkcs11通過pin口令保護的數(shù)據(jù)庫或者硬件設備中。
type BCCSP interface {
    KeyGen(opts KeyGenOpts) (k Key, err error) //生成Key
    KeyDeriv(k Key, opts KeyDerivOpts) (dk Key, err error) //派生Key
    KeyImport(raw interface{}, opts KeyImportOpts) (k Key, err error) //導入Key
    GetKey(ski []byte) (k Key, err error) //獲取Key
    Hash(msg []byte, opts HashOpts) (hash []byte, err error) //哈希msg
    GetHash(opts HashOpts) (h hash.Hash, err error) //獲取哈希實例
    Sign(k Key, digest []byte, opts SignerOpts) (signature []byte, err error) //簽名
    Verify(k Key, signature, digest []byte, opts SignerOpts) (valid bool, err error) //校驗簽名
    Encrypt(k Key, plaintext []byte, opts EncrypterOpts) (ciphertext []byte, err error) //加密
    Decrypt(k Key, ciphertext []byte, opts DecrypterOpts) (plaintext []byte, err error) //解密
}
//代碼在bccsp/bccsp.go
3、KeyStore接口(密鑰存儲)定義如下: 其實現(xiàn)是bccsp/sw/fileks.go
type KeyStore interface {
    ReadOnly() bool //密鑰庫是否只讀,只讀時StoreKey將失敗
    GetKey(ski []byte) (k Key, err error) //如果SKI通過,返回Key.從相關文件中加載 
  StoreKey(k Key) (err error) //將Key存儲到密鑰庫中 sw實現(xiàn)是寫入相關文件
}
//代碼在bccsp/keystore.go
bccsp/sw/fileks.go中 StoreKey的實現(xiàn) 可見相關key寫入文件
func (ks *fileBasedKeyStore) StoreKey(k bccsp.Key) (err error) {
if ks.readOnly {
return errors.New("Read only KeyStore.")
}
if k == nil {
return errors.New("Invalid key. It must be different from nil.")
}
switch k.(type) {
case *ecdsaPrivateKey:
kk := k.(*ecdsaPrivateKey)
err = ks.storePrivateKey(hex.EncodeToString(k.SKI()), kk.privKey)
if err != nil {
return fmt.Errorf("Failed storing ECDSA private key [%s]", err)
}
case *ecdsaPublicKey:
kk := k.(*ecdsaPublicKey)
err = ks.storePublicKey(hex.EncodeToString(k.SKI()), kk.pubKey)
if err != nil {
return fmt.Errorf("Failed storing ECDSA public key [%s]", err)
}
case *rsaPrivateKey:
kk := k.(*rsaPrivateKey)
err = ks.storePrivateKey(hex.EncodeToString(k.SKI()), kk.privKey)
if err != nil {
return fmt.Errorf("Failed storing RSA private key [%s]", err)
}
case *rsaPublicKey:
kk := k.(*rsaPublicKey)
err = ks.storePublicKey(hex.EncodeToString(k.SKI()), kk.pubKey)
if err != nil {
return fmt.Errorf("Failed storing RSA public key [%s]", err)
}
case *aesPrivateKey:
kk := k.(*aesPrivateKey)
err = ks.storeKey(hex.EncodeToString(k.SKI()), kk.privKey)
if err != nil {
return fmt.Errorf("Failed storing AES key [%s]", err)
}
4、mspconfig的初始化流程圖
其中getMspConfig方法比較重要.也一目了然,加載相關證書存入byte[].最終串行化成json
func getMspConfig(dir string, ID string, sigid *msp.SigningIdentityInfo) (*msp.MSPConfig, error) {
///data/config/hyperledger/fabric/crypto-config/peerOrganizations/org1.ygsoft.com/peers/peer0.org1.ygsoft.com/msp/cacerts
cacertDir := filepath.Join(dir, cacerts)
///data/config/hyperledger/fabric/crypto-config/peerOrganizations/org1.ygsoft.com/peers/peer0.org1.ygsoft.com/msp/admincerts
admincertDir := filepath.Join(dir, admincerts)
// //data/config/hyperledger/fabric/crypto-config/peerOrganizations/org1.ygsoft.com/peers/peer0.org1.ygsoft.com/msp/ntermediatecerts
intermediatecertsDir := filepath.Join(dir, intermediatecerts)
///data/config/hyperledger/fabric/crypto-config/peerOrganizations/org1.ygsoft.com/peers/peer0.org1.ygsoft.com/msp/crls
crlsDir := filepath.Join(dir, crlsfolder)
configFile := filepath.Join(dir, configfilename)
///data/config/hyperledger/fabric/crypto-config/peerOrganizations/org1.ygsoft.com/peers/peer0.org1.ygsoft.com/msp/tlscacerts
tlscacertDir := filepath.Join(dir, tlscacerts)
tlsintermediatecertsDir := filepath.Join(dir, tlsintermediatecerts)
cacerts, err := getPemMaterialFromDir(cacertDir)
if err != nil || len(cacerts) == 0 {
return nil, errors.WithMessage(err, fmt.Sprintf("could not load a valid ca certificate from directory %s", cacertDir))
}
admincert, err := getPemMaterialFromDir(admincertDir)
if err != nil || len(admincert) == 0 {
return nil, errors.WithMessage(err, fmt.Sprintf("could not load a valid admin certificate from directory %s", admincertDir))
}
intermediatecerts, err := getPemMaterialFromDir(intermediatecertsDir)
if os.IsNotExist(err) {
mspLogger.Debugf("Intermediate certs folder not found at [%s]. Skipping. [%s]", intermediatecertsDir, err)
} else if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("failed loading intermediate ca certs at [%s]", intermediatecertsDir))
}
tlsCACerts, err := getPemMaterialFromDir(tlscacertDir)
tlsIntermediateCerts := [][]byte{}
if os.IsNotExist(err) {
mspLogger.Debugf("TLS CA certs folder not found at [%s]. Skipping and ignoring TLS intermediate CA folder. [%s]", tlsintermediatecertsDir, err)
} else if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("failed loading TLS ca certs at [%s]", tlsintermediatecertsDir))
} else if len(tlsCACerts) != 0 {
tlsIntermediateCerts, err = getPemMaterialFromDir(tlsintermediatecertsDir)
if os.IsNotExist(err) {
mspLogger.Debugf("TLS intermediate certs folder not found at [%s]. Skipping. [%s]", tlsintermediatecertsDir, err)
} else if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("failed loading TLS intermediate ca certs at [%s]", tlsintermediatecertsDir))
}
} else {
mspLogger.Debugf("TLS CA certs folder at [%s] is empty. Skipping.", tlsintermediatecertsDir)
}
crls, err := getPemMaterialFromDir(crlsDir)
if os.IsNotExist(err) {
mspLogger.Debugf("crls folder not found at [%s]. Skipping. [%s]", crlsDir, err)
} else if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("failed loading crls at [%s]", crlsDir))
}
// Load configuration file
// if the configuration file is there then load it
// otherwise skip it
//加載配置文件  ../msp/config.yaml 存在就加載,不存在就跳過
var ouis []*msp.FabricOUIdentifier
var nodeOUs *msp.FabricNodeOUs
_, err = os.Stat(configFile)
if err == nil {
// load the file, if there is a failure in loading it then
// return an error
raw, err := ioutil.ReadFile(configFile)
if err != nil {
return nil, errors.Wrapf(err, "failed loading configuration file at [%s]", configFile)
}
configuration := Configuration{}
err = yaml.Unmarshal(raw, &configuration)
if err != nil {
return nil, errors.Wrapf(err, "failed unmarshalling configuration file at [%s]", configFile)
}
// Prepare OrganizationalUnitIdentifiers
if len(configuration.OrganizationalUnitIdentifiers) > 0 {
for _, ouID := range configuration.OrganizationalUnitIdentifiers {
f := filepath.Join(dir, ouID.Certificate)
raw, err = readFile(f)
if err != nil {
return nil, errors.Wrapf(err, "failed loading OrganizationalUnit certificate at [%s]", f)
}
oui := &msp.FabricOUIdentifier{
Certificate:                  raw,
OrganizationalUnitIdentifier: ouID.OrganizationalUnitIdentifier,
}
ouis = append(ouis, oui)
}
}
// Prepare NodeOUs
if configuration.NodeOUs != nil && configuration.NodeOUs.Enable {
mspLogger.Info("Loading NodeOUs")
if configuration.NodeOUs.ClientOUIdentifier == nil || len(configuration.NodeOUs.ClientOUIdentifier.OrganizationalUnitIdentifier) == 0 {
return nil, errors.New("Failed loading NodeOUs. ClientOU must be different from nil.")
}
if configuration.NodeOUs.PeerOUIdentifier == nil || len(configuration.NodeOUs.PeerOUIdentifier.OrganizationalUnitIdentifier) == 0 {
return nil, errors.New("Failed loading NodeOUs. PeerOU must be different from nil.")
}
nodeOUs = &msp.FabricNodeOUs{
Enable:             configuration.NodeOUs.Enable,
ClientOUIdentifier: &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.ClientOUIdentifier.OrganizationalUnitIdentifier},
PeerOUIdentifier:   &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.PeerOUIdentifier.OrganizationalUnitIdentifier},
}
// Read certificates, if defined
// ClientOU
f := filepath.Join(dir, configuration.NodeOUs.ClientOUIdentifier.Certificate)
raw, err = readFile(f)
if err != nil {
mspLogger.Infof("Failed loading ClientOU certificate at [%s]: [%s]", f, err)
} else {
nodeOUs.ClientOUIdentifier.Certificate = raw
}
// PeerOU
f = filepath.Join(dir, configuration.NodeOUs.PeerOUIdentifier.Certificate)
raw, err = readFile(f)
if err != nil {
mspLogger.Debugf("Failed loading PeerOU certificate at [%s]: [%s]", f, err)
} else {
nodeOUs.PeerOUIdentifier.Certificate = raw
}
}
} else {
mspLogger.Debugf("MSP configuration file not found at [%s]: [%s]", configFile, err)
}
// Set FabricCryptoConfig
cryptoConfig := &msp.FabricCryptoConfig{
SignatureHashFamily:            bccsp.SHA2,
IdentityIdentifierHashFunction: bccsp.SHA256,
}
// Compose FabricMSPConfig
fmspconf := &msp.FabricMSPConfig{
Admins:            admincert,
RootCerts:         cacerts,
IntermediateCerts: intermediatecerts,
SigningIdentity:   sigid,
Name:              ID,
OrganizationalUnitIdentifiers: ouis,
RevocationList:                crls,
CryptoConfig:                  cryptoConfig,
TlsRootCerts:                  tlsCACerts,
TlsIntermediateCerts:          tlsIntermediateCerts,
FabricNodeOUs:                 nodeOUs,
}
    //串行化成json格式的byte[] 
fmpsjs, _ := proto.Marshal(fmspconf)
 
//MSPConfig的msp_config.pb.go文件中定義 
    //type MSPConfig struct {
//Type int32 `protobuf:"varint,1,opt,name=type" json:"type,omitempty"`
//Config []byte `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"`
    //}
mspconf := &msp.MSPConfig{Config: fmpsjs, Type: int32(FABRIC)}
return mspconf, nil
msp/mspimplsetup.go文件中根據(jù)上面生成的mspconf對證書進行了相關設置,結果保存
在/mspimpl.go中的結體bccspmsp中
func (msp *bccspmsp) preSetupV1(conf *m.FabricMSPConfig) error {
// setup crypto config
if err := msp.setupCrypto(conf); err != nil {
return err
}
// Setup CAs  //設置ca證書,中間證書等,涉及到x509包。并構建相關identity類。
//根據(jù)證書內(nèi)容加hash后生成identity類
if err := msp.setupCAs(conf); err != nil {
return err
}
// Setup Admins
if err := msp.setupAdmins(conf); err != nil {
return err
}
// Setup CRLs
if err := msp.setupCRLs(conf); err != nil {
return err
}
// Finalize setup of the CAs
if err := msp.finalizeSetupCAs(conf); err != nil {
return err
}
// setup the signer (if present)
if err := msp.setupSigningIdentity(conf); err != nil {
return err
}
// setup TLS CAs
if err := msp.setupTLSCAs(conf); err != nil {
return err
}
// setup the OUs
if err := msp.setupOUs(conf); err != nil {
return err
}
return nil
}


傻 瓜 2018-06-25 09:00 發(fā)表評論
]]>
Fabric 1.1源代碼分析(3) 系統(tǒng)鏈碼執(zhí)行過程示例(弟弟篇)http://www.tkk7.com/fool/archive/2018/06/13/433279.html傻 瓜傻 瓜Wed, 13 Jun 2018 06:37:00 GMThttp://www.tkk7.com/fool/archive/2018/06/13/433279.htmlhttp://www.tkk7.com/fool/comments/433279.htmlhttp://www.tkk7.com/fool/archive/2018/06/13/433279.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/433279.htmlhttp://www.tkk7.com/fool/services/trackbacks/433279.html
# Fabric 1.1源代碼分析(3) 系統(tǒng)鏈碼執(zhí)行過程
## 1、系統(tǒng)鏈碼執(zhí)行過程
* 以peer channel join -b gensis.block命令為例。該命令結果是peer節(jié)點加入通道.
這個命令會單獨啟一個進程.在該進程中會構建一個名稱為cscc的鏈碼消息傳到peer節(jié)點.
通過grpc調(diào)用最終會進到endorser.go中的ProcessProposal函數(shù)進行處理。
參考Fabric 1.1源代碼分析(2)http://www.tkk7.com/fool/archive/2018/06/12/433277.html
系統(tǒng)鏈碼初始化過程,可以找到../shim/handler.go中
的handleTransaction()函數(shù).最終會調(diào)用res := handler.cc.Invoke(stub).這里的
cc就是importsysccs.go文件中systemChaincodes數(shù)組中的cscc系統(tǒng)鏈碼的.    
Chaincode,其實例是&cscc.PeerConfiger{},實現(xiàn)在cscc/configure.go文件中。每個系統(tǒng)
鏈碼都實現(xiàn)了這個Chaincode接口()
```go
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 data
    Init(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
}
```

* 至此就可以清晰地看到每一個系統(tǒng)鏈碼都會啟動一對協(xié)程,通過chan通信。系統(tǒng)鏈碼消息由
shim/handler.go中的函數(shù)處理.并且這里最終調(diào)用各自的具體實現(xiàn)的Ivoke方法進行業(yè)務處理

## 2、peer channel join命令處理流程圖
* peer channel join命令會調(diào)用configure.go中的Excute方法。對應cscc系統(tǒng)鏈碼的處理,
原因如下,以下流程圖大致可以了解cscc都做了些什么
![](cscc.png)

## 3、小結

* 上面的流程圖也不是非常地強細,忽略掉了一些方法。但是有了整個流程的理解,就能理解其
它系統(tǒng)鏈碼的調(diào)用過程,需要時直接細讀其實現(xiàn)就好了。從上流程圖中可以看到文件末尾添加區(qū)
區(qū)塊,leveldb中記錄了區(qū)塊號,索引位置信息等等。另外因為系統(tǒng)鏈碼跟一般鏈碼雖然經(jīng)過
的文件基本一樣,但最終處理方式還是不一樣,一個是協(xié)程,一個是grpc.可能參考Fabric 1.1
源代碼分析之 Chaincode(鏈碼)初始化 http://www.tkk7.com/fool/archive/2018/06/12/433275.html


傻 瓜 2018-06-13 14:37 發(fā)表評論
]]>
Fabric 1.1源代碼分析之 系統(tǒng)鏈碼初始化過程(哥哥篇)http://www.tkk7.com/fool/archive/2018/06/12/433277.html傻 瓜傻 瓜Tue, 12 Jun 2018 07:00:00 GMThttp://www.tkk7.com/fool/archive/2018/06/12/433277.htmlhttp://www.tkk7.com/fool/comments/433277.htmlhttp://www.tkk7.com/fool/archive/2018/06/12/433277.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/433277.htmlhttp://www.tkk7.com/fool/services/trackbacks/433277.html
# Fabric 1.1源代碼分析之 Fabric 1.1源代碼分析 系統(tǒng)鏈碼初始化過程

* 鏈碼這一塊的代碼非常的繞?;旧暇褪且粋€大循環(huán)。限于水平或者其它原因,差露可能難免,各位看官包涵則個...

## 1、系統(tǒng)鏈碼

* 系統(tǒng)鏈碼跟智能合約鏈碼涉及到的文件差不多,流程也差不多。只是智能合約是grpc,系統(tǒng)鏈碼是chan實現(xiàn)調(diào)用.
LSCC Lifecycle system chaincode,處理生命周期請求。我理解的生命周期請求應該指的是一個chaincode的安裝,實例化,升級,
卸載等對其生命周期起關鍵作用的一系列操作請求。
CSCC Configuration system chaincode,處理在peer程序端的channel配置。
QSCC Query system chaincode,提供賬本查詢接口,如獲取塊和交易信息。
ESCC Endorsement system chaincode,通過對交易申請的應答信息進行簽名,來提供背書功能。
VSCC Validation system chaincode,處理交易校驗,包括檢查背書策略和版本在并發(fā)時的控制。

## 2、系統(tǒng)鏈碼注冊
* 在/core/chaincode/shim/interfaces_stable.go中實現(xiàn)了下面的接口
```go
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 data
    Init(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
}
```

* 在core/scc/sysccapi.go中定義了SystemChaincode結構體,其中定義了 Chaincode接口變量
```go
type SystemChaincode struct {
    //Unique name of the system chaincode
    Name string

    //Path to the system chaincode; currently not used
    Path string

    //InitArgs initialization arguments to startup the system chaincode
    InitArgs [][]byte

    // Chaincode is the actual chaincode object
    Chaincode shim.Chaincode

    // InvokableExternal keeps track of whether
    // this system chaincode can be invoked
    // through a proposal sent to this peer
    InvokableExternal bool

    // InvokableCC2CC keeps track of whether
    // this system chaincode can be invoked
    // by way of a chaincode-to-chaincode
    // invocation
    InvokableCC2CC bool

    // Enabled a convenient switch to enable/disable system chaincode without
    // having to remove entry from importsysccs.go
    Enabled bool
}
```

* 在 core/scc/importsysccs.go文件中對系統(tǒng)鏈碼進行了初始化,并且每個Chainoce指定了具體實現(xiàn)
```go
//see systemchaincode_test.go for an example using "sample_syscc"
var systemChaincodes = []*SystemChaincode{
    {
        Enabled: true,
        Name: "cscc",
        Path: "github.com/hyperledger/fabric/core/scc/cscc",
        InitArgs: [][]byte{[]byte("")},
        Chaincode: &cscc.PeerConfiger{},
        InvokableExternal: true, // cscc is invoked to join a channel
    },
    {
        Enabled: true,
        Name: "lscc",
        Path: "github.com/hyperledger/fabric/core/scc/lscc",
        InitArgs: [][]byte{[]byte("")},
        Chaincode: lscc.NewLifeCycleSysCC(),
        InvokableExternal: true, // lscc is invoked to deploy new chaincodes
        InvokableCC2CC: true, // lscc can be invoked by other chaincodes
    },
    {
        Enabled: true,
        Name: "escc",
        Path: "github.com/hyperledger/fabric/core/scc/escc",
        InitArgs: [][]byte{[]byte("")},
        Chaincode: &escc.EndorserOneValidSignature{},
    },
    {
        Enabled: true,
        Name: "vscc",
        Path: "github.com/hyperledger/fabric/core/scc/vscc",
        InitArgs: [][]byte{[]byte("")},
        Chaincode: &vscc.ValidatorOneValidSignature{},
    },
    {
        Enabled: true,
        Name: "qscc",
        Path: "github.com/hyperledger/fabric/core/chaincode/qscc",
        InitArgs: [][]byte{[]byte("")},
        Chaincode: &qscc.LedgerQuerier{},
        InvokableExternal: true, // qscc can be invoked to retrieve blocks
        InvokableCC2CC: true, // qscc can be invoked to retrieve blocks also by a cc
    },
}
```
* 注冊流程圖
![](systemcoderegist.png)


## 3、系統(tǒng)鏈碼初始化
* 系統(tǒng)注冊完成后會對鏈碼初始化.跟一般chaincode稍有不同的是chaincode在合約里通過grpc與peer節(jié)點交互。
而系統(tǒng)鏈碼則是在協(xié)程里通過chan 實現(xiàn)交互.下面代碼創(chuàng)建兩個 peerRcvCCSend := make(chan *pb.ChaincodeMessage)
    ccRcvPeerSend := make(chan *pb.ChaincodeMessage) ,是客戶端和服務端共同的參數(shù)
```go

func (ipc *inprocContainer) launchInProc(ctxt context.Context, id string, args []string, env []string, ccSupport ccintf.CCSupport) error {
    peerRcvCCSend := make(chan *pb.ChaincodeMessage)
    ccRcvPeerSend := make(chan *pb.ChaincodeMessage)
    var err error
    ccchan := make(chan struct{}, 1)
    ccsupportchan := make(chan struct{}, 1)
    //啟動客戶端處理
    go func() {
        defer close(ccchan)
        inprocLogger.Debugf("chaincode started for %s", id)
        if args == nil {
            args = ipc.args
        }
        if env == nil {
            env = ipc.env
        }
        err := _shimStartInProc(env, args, ipc.chaincode, ccRcvPeerSend, peerRcvCCSend)
        if err != nil {
            err = fmt.Errorf("chaincode-support ended with err: %s", err)
            _inprocLoggerErrorf("%s", err)
        }
        inprocLogger.Debugf("chaincode ended with for %s with err: %s", id, err)
    }()
//啟動服務端處理
    go func() {
        defer close(ccsupportchan)
        inprocStream := newInProcStream(peerRcvCCSend, ccRcvPeerSend)
        inprocLogger.Debugf("chaincode-support started for %s", id)
        err := ccSupport.HandleChaincodeStream(ctxt, inprocStream)
        if err != nil {
            err = fmt.Errorf("chaincode ended with err: %s", err)
            _inprocLoggerErrorf("%s", err)
        }
        inprocLogger.Debugf("chaincode-support ended with for %s with err: %s", id, err)
    }()

    select {
    case <-ccchan:
        close(peerRcvCCSend)
        inprocLogger.Debugf("chaincode %s quit", id)
    case <-ccsupportchan:
        close(ccRcvPeerSend)
        inprocLogger.Debugf("chaincode support %s quit", id)
    case <-ipc.stopChan:
        close(ccRcvPeerSend)
        close(peerRcvCCSend)
        inprocLogger.Debugf("chaincode %s stopped", id)
    }
    return err
}

```


* 初始化流程圖
![](systemcodeinit.png)


## 4、系統(tǒng)鏈碼的執(zhí)行
...


傻 瓜 2018-06-12 15:00 發(fā)表評論
]]>
Fabric 1.1源代碼分析之 Chaincode(鏈碼)初始化http://www.tkk7.com/fool/archive/2018/06/12/433275.html傻 瓜傻 瓜Tue, 12 Jun 2018 06:51:00 GMThttp://www.tkk7.com/fool/archive/2018/06/12/433275.htmlhttp://www.tkk7.com/fool/comments/433275.htmlhttp://www.tkk7.com/fool/archive/2018/06/12/433275.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/433275.htmlhttp://www.tkk7.com/fool/services/trackbacks/433275.html閱讀全文

傻 瓜 2018-06-12 14:51 發(fā)表評論
]]>
開源區(qū)塊鏈Hyperleger Fabric之鏈碼開發(fā)調(diào)試模式在IDE里debug鏈碼http://www.tkk7.com/fool/archive/2018/05/23/433231.html傻 瓜傻 瓜Wed, 23 May 2018 06:17:00 GMThttp://www.tkk7.com/fool/archive/2018/05/23/433231.htmlhttp://www.tkk7.com/fool/comments/433231.htmlhttp://www.tkk7.com/fool/archive/2018/05/23/433231.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/433231.htmlhttp://www.tkk7.com/fool/services/trackbacks/433231.html1,啟動order
    orderer start
2, 使用開發(fā)模式啟動peer節(jié)點
   peer node start --peer-chaincodedev=true
3,創(chuàng)建通道
4,啟動鏈碼程序
這一步可以在IDE里啟動鏈碼,這樣就可以debug了
cd examples/chaincode/go/chaincode_example02
go build
CORE_CHAINCODE_LOGLEVEL=debug CORE_PEER_ADDRESS=127.0.0.1:7052 CORE_CHAINCODE_ID_NAME=mycc:0 ./chaincode_example02
5,安裝鏈碼
peer chaincode install -n mycc -v 0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02
6,初始化鏈碼
peer chaincode instantiate -n mycc -v 0 -c '{"Args":["init","a","100","b","200"]}' -o 127.0.0.1:7050 -C ch1
7,鏈碼調(diào)用和測試


傻 瓜 2018-05-23 14:17 發(fā)表評論
]]>
開源區(qū)塊鏈Hyperleger Fabric之通過Composer開發(fā)框架快速搭建開發(fā)環(huán)境http://www.tkk7.com/fool/archive/2018/03/12/433093.html傻 瓜傻 瓜Mon, 12 Mar 2018 08:44:00 GMThttp://www.tkk7.com/fool/archive/2018/03/12/433093.htmlhttp://www.tkk7.com/fool/comments/433093.htmlhttp://www.tkk7.com/fool/archive/2018/03/12/433093.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/433093.htmlhttp://www.tkk7.com/fool/services/trackbacks/433093.html
準備工作:(自行百度)

開發(fā)環(huán)境必備軟件:

 composer-cli

 generator-hyperledger-composr

composer-rest-server
Yeoman

安裝playground

 

Installing and running Hyperledger Composer Playground locally
docker ps -aq | xargs docker rm -f
docker images -aq | xargs docker rmi -f
curl -sSL https://hyperledger.github.io/composer/install-hlfv1.sh | bash   
執(zhí)行install-hlfv1.sh 安裝運行fabric1.06版.并運行 playground服務 打開流覽器http://xxxx:8080顯示如下



1,playgroundWeb Browser區(qū)域提供了在頁面定義模型、測試模型的能力。并不保存。但可以導出bna文件

2,connection區(qū)域提供了在開發(fā)環(huán)境布署合約,會生成一個智能合約的docker運行環(huán)境.
3,可以在上圖中上部分的My Business Networks 工作區(qū)點擊虛業(yè)部分Deploy a new business network

4,在接下來頁面中選中一個示例。如 marble neetworkd.  選擇 ID and Secret 填入admin 和 adminpw

5,點擊Deploy按鈕后會發(fā)布一個合約.并跳到測試頁如下圖:



6,在上圖中 Test Tab頁可以進行測試 ,在Define Tab頁可以導出bna文件.
7,在第一幅圖中點擊下載按鈕,會下載一個 .card文件,描述了連接fabric peer節(jié)點等相關連接信息.記得要導 
PeerAdmin@hlfv1的card和你自己測試用的card,及bna文件
8,分別執(zhí)行  composer card import -f PeerAdmin.card  ,composer card import -f admin.card  .composer card list 可以查看你導入的card的name信息.

       9,composer-rest-server -c admin@empty-business-network -n always -w true  啟動rest服務默認端口3000.

      10,好了,可以體驗一下fabric是個什么玩意了。:) 88!




傻 瓜 2018-03-12 16:44 發(fā)表評論
]]>
開源區(qū)塊鏈Hyperleger Fabric通過SDK-JAVA動態(tài)添加通道http://www.tkk7.com/fool/archive/2018/03/12/433090.html傻 瓜傻 瓜Mon, 12 Mar 2018 03:55:00 GMThttp://www.tkk7.com/fool/archive/2018/03/12/433090.htmlhttp://www.tkk7.com/fool/comments/433090.htmlhttp://www.tkk7.com/fool/archive/2018/03/12/433090.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/433090.htmlhttp://www.tkk7.com/fool/services/trackbacks/433090.html
在閱讀本篇之前需要理解
configtxgen工具使用原理.基本上能跑通
開源區(qū)塊鏈Hyperleger Fabric的SDK-JAVA新手上路指引
中的內(nèi)容。可以參考http://www.tkk7.com/fool/archive/2018/02/01/433032.html.
如果知道通過命令行工具進行智能合約的安裝測試就更好了。fabric中的channel可以理解為泳道。在這個泳道中可以布署
多個智能合約。當然也可以安裝多個channel. 順便多一嘴,在智能合約可以調(diào)用另一個channel中的智能合約中的查詢方法.
通過sdk動態(tài)安裝通道的步驟:
1,通過configtxgen命令生成交易通道初始文件.
configtxgen --profile TestSoft --outputCreateChannelTx testsoft.tx --channelID testsoft
2,下載testsoft.tx到本機.
3,sdk安裝通道代碼及解釋
@Override
public boolean installChannel(String channelName) throws IOException, InvalidArgumentException, TransactionException, ProposalException {
// TODO Auto-generated method stub
 String configPath = this.config.getConfigPath();
                         //初始化 ChannelConfiguration 對象.參數(shù)是通道初始化文件路徑
 ChannelConfiguration channelConfiguration = new ChannelConfiguration(new File(configPath + "/"+channelName + ".tx"));
  //構造orderder節(jié)點信息
   String ordererName = orderers.get().get(0).getOrdererName();
Properties ordererProperties = loadOrderProperty(ordererName);
Orderer anOrderer = client.newOrderer(
ordererName,
orderers.get().get(0).getOrdererLocation(), ordererProperties);
       //Create channel that has only one signer that is this orgs peer admin. If channel creation policy needed more signature they would need to be added too.
       Channel channel = client.newChannel(channelName, anOrderer, channelConfiguration, client.getChannelConfigurationSignature(channelConfiguration, fabricOrg.getPeerAdmin()));
                       //構造peer節(jié)點信息,并且將peer節(jié)點加入到通道中。peer節(jié)點加入通道后,才能通過該peer節(jié)點中訪問通道中的智能合約
       for (com.ygsoft.fabric.bean.Peers.Peer p : config.getInstallPeers().get()) {
Properties peerProperties = this.loadPeerProperties(p.getPeerName());
Peer peer = client.newPeer(p.getPeerName(),p.getPeerLocation(),peerProperties);
channel.joinPeer(peer);
}
for (int i = 0; i < orderers.get().size(); i++) {
Properties ordererProperties2 = loadOrderProperty(ordererName);
channel.addOrderer(client.newOrderer(
orderers.get().get(i).getOrdererName(),
orderers.get().get(i)
.getOrdererLocation(), ordererProperties2));
}
log.debug("channel.isInitialized() = " + channel.isInitialized());
  channel.initialize();
 return true;
}

知道了手工命令行安裝合約的過程,上面的理解還是比較簡單的。安裝通道后就可以調(diào)用sdk安裝合約了。













傻 瓜 2018-03-12 11:55 發(fā)表評論
]]>
開源區(qū)塊鏈Hyperleger Fabric的SDK-JAVA新手上路指引http://www.tkk7.com/fool/archive/2018/02/01/433032.html傻 瓜傻 瓜Thu, 01 Feb 2018 01:03:00 GMThttp://www.tkk7.com/fool/archive/2018/02/01/433032.htmlhttp://www.tkk7.com/fool/comments/433032.htmlhttp://www.tkk7.com/fool/archive/2018/02/01/433032.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/433032.htmlhttp://www.tkk7.com/fool/services/trackbacks/433032.html區(qū)塊鏈工程師。不久抱得美人歸。:)

閱讀本代碼前,先看看fabric的多機布署,參考下面的貼子1:
http://blog.csdn.net/songbin830/article/details/78778806 完成多機布署.

參考貼子2: http://www.cnblogs.com/aberic/p/8206551.html ,把代碼下到本地工程里。新手上路總會遇到
各種細節(jié)問題.重點來了:

使用git命令從github.com上拉下SDK-JAVA源碼.
1,源碼文件中有EclipseSetup.md的文件,介紹如何把源碼項目導入eclipse.
2,導入eclipse后發(fā)現(xiàn)缺少  org.hyperledger.fabric.protos.*文件。github上的源碼里也沒有。解決辦法:從
其它網(wǎng)站的 SDK-JAVA打包文件中找到源碼包,把org.hyperledger.fabric.protos包中的源碼copy到eclipse。
3,在orderer節(jié)點把  crypto-config文件夾中的內(nèi)容copy到本機.其中包含了用命令工具生成的證書,身份信息
等內(nèi)容
4,貼子2中代碼如何用,其實跟源碼中的測試用例中的代碼差不多.初始化示例如下:因為貼子2是個demo類代碼,
我作了些改動。有些代碼沒放ChaincodeManager()實例化??匆幌逻@個類的構造方法,構造對應的需要的實例類
也不難

public static ChaincodeManager init() throws Exception{
FabricConfig fabricConfig = new FabricConfig("E:/fabricConfig");  //fabricConfig文件夾中包含
                //crypto-config文件夾
Peers peers = new Peers();   //初始化peer節(jié)點
peers.setOrgDomainName("org1.ygsoft.com");
peers.setOrgMSPID("Org1MSP");
peers.setOrgName("Org1MSP");
//peers.addPeer("peer0.org1.ygsoft.com", "peer0.org1.ygsoft.com", "grpcs://10.121.60.2:7051", "grpcs://10.121.60.2:7053", null);
peers.addPeer("peer1.org1.ygsoft.com", "peer1.org1.ygsoft.com", "grpcs://10.121.60.3:7051", "grpcs://10.121.60.3:7053", null);
fabricConfig.setPeers(peers);
//初始化orderer節(jié)點
Orderers orders = new Orderers();
orders.setOrdererDomainName("ygsoft.com");
orders.addOrderer("orderer.ygsoft.com", "grpcs://10.121.60.1:7050");
fabricConfig.setOrderers(orders);
fabricConfig.setRegisterEvent(true);
ChaincodeManager chainManager = new ChaincodeManager(fabricConfig);
return chainManager;
}

5,其它參數(shù),比如chaincode相關信息可以在peer節(jié)點  peer chaincode list --installed 命令可以查看
可以調(diào)用這個ChaincodeManager 的query和invoke方法了.

6,補充內(nèi)容:需要shim-client.jar包,這個需要拉下fabric的源碼,在文件夾
\src\github.com\hyperledger\fabric\core\chaincode\shim\java 用gradle編譯一個jar包出來

7,如果grpc用了ssl的需要 grpcs://10.121.60.3:7051,grpcs開頭

因為網(wǎng)上有了fabric多機布署教程,和不完善的示例代碼,這里主要介紹一下其中容易遇到的問題,解決起
來也頗為頭痛和費時。
本貼原地址:http://www.tkk7.com/fool .下一篇區(qū)塊鏈貼子預告:Fabric的SDK-JAVA動態(tài)安裝
Channel













傻 瓜 2018-02-01 09:03 發(fā)表評論
]]>
springCloud、boot集成elkhttp://www.tkk7.com/fool/archive/2017/10/08/432851.html傻 瓜傻 瓜Sun, 08 Oct 2017 11:15:00 GMThttp://www.tkk7.com/fool/archive/2017/10/08/432851.htmlhttp://www.tkk7.com/fool/comments/432851.htmlhttp://www.tkk7.com/fool/archive/2017/10/08/432851.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/432851.htmlhttp://www.tkk7.com/fool/services/trackbacks/432851.html1,啟動elashticsearch
2,logstash/config目錄下新建log.conf文件,其內(nèi)容:
input {
  # For detail config for log4j as input, 
  # See: https://www.elastic.co/guide/en/logstash/current/plugins-inputs-log4j.html
      tcp { 
    mode => "server"
    host => "127.0.0.1"
        port => 4567
        codec => json_lines 
    }  
}
filter {
  #Only matched data are send to output.
}
output {
  # For detail config for elasticsearch as output, 
  # See: https://www.elastic.co/guide/en/logstash/current/plugins-outputs-elasticsearch.html
  elasticsearch {  
    hosts  => ["127.0.0.1:9200"]   #ElasticSearch host, can be array.
    index  => "applog"         #The index to write data to.
  }
}
3,kibana配置.修改kibana/config文件夾中的kibana.yml的配置文件
server.port: 5601
server.host: "localhost"
elasticsearch.url: "http://localhost:9200"
kibana.index: ".kibana"

4,springCload、springBoot中的logback-spring.xml文件配置將日志寫入logstash

    <appender name="logstash2" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <remoteHost>127.0.0.1</remoteHost>
        <port>4567</port>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <!-- Minimum logging level to be presented in the console logs-->
            <level>INFO</level> <!--寫入logstash的日志級別-->
        </filter>
        <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder"/>
    </appender>
    ​
    <root level="INFO">
        <appender-ref ref="console"/>
        <appender-ref ref="logstash"/>
        <appender-ref ref="logstash2"/>
        <!--<appender-ref ref="flatfile"/>-->
    </root>

后記:日志是直接寫入到elashticsearch,可以集成kafka或redis作為緩沖。


傻 瓜 2017-10-08 19:15 發(fā)表評論
]]>
springboot、mybatis、mycat分庫實踐http://www.tkk7.com/fool/archive/2017/10/01/432841.html傻 瓜傻 瓜Sun, 01 Oct 2017 09:40:00 GMThttp://www.tkk7.com/fool/archive/2017/10/01/432841.htmlhttp://www.tkk7.com/fool/comments/432841.htmlhttp://www.tkk7.com/fool/archive/2017/10/01/432841.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/432841.htmlhttp://www.tkk7.com/fool/services/trackbacks/432841.html1.pom文件中引入下面引入mybatis逆向工程插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.4</version>
<configuration>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
</plugins>
</build>
   2, src/main/resource 目錄下引入mybatis逆向工程配置文件,這樣就可以自動生成mybatis需要的xml及dao interface
<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE generatorConfiguration
   PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
   "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
 <generatorConfiguration>
     <!--數(shù)據(jù)庫驅動-->
     <classPathEntry    location="E:\\worksource\\springboot\\src\\main\\webapp\\WEB-INF\\lib\\mysql-connector-java-5.1.39.jar"/>
     <context id="DB2Tables"    targetRuntime="MyBatis3">
         <commentGenerator>
             <property name="suppressDate" value="true"/>
             <property name="suppressAllComments" value="true"/>
         </commentGenerator>
         <!--數(shù)據(jù)庫鏈接地址賬號密碼-->
         <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/jeeshop" userId="root" password="">
         </jdbcConnection>
         <javaTypeResolver>
             <property name="forceBigDecimals" value="false"/>
         </javaTypeResolver>
         <!--生成Model類存放位置-->
         <javaModelGenerator targetPackage="com.junjun.myblog.domain" targetProject="src/main/java">
             <property name="enableSubPackages" value="true"/>
             <property name="trimStrings" value="true"/>
         </javaModelGenerator>
         <!--生成映射文件存放位置-->
         <sqlMapGenerator targetPackage="src/main/resources/mapper" targetProject=".">
             <property name="enableSubPackages" value="true"/>
         </sqlMapGenerator>
         <!--生成Dao類存放位置-->
         <javaClientGenerator type="XMLMAPPER" targetPackage="com.junjun.myblog.dao" targetProject="src/main/java">
             <property name="enableSubPackages" value="true"/>
         </javaClientGenerator>
         <!--生成對應表及類名 mapperName="AreaDao"  工程右鍵 Debug As -> maven build... -> mybatis-generator:generate
         <table tableName="t_area"   domainObjectName="Area" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
    -->
</context>
 </generatorConfiguration>
3,application 中加上注解  @MapperScan("com.junjun") 
4,數(shù)據(jù)源連接mycat
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:8066/MYSQL?useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=123456
二,mycat配置
1,conf/server.xml中配置用戶 和schema
<user name="root">
<property name="password">123456</property>
<property name="schemas">MYSQL</property>
</user>
2,schema.xml配置數(shù)據(jù)庫和分片表分片規(guī)則
<schema name="MYSQL" checkSQLschema="false" sqlMaxLimit="100">
<table name="t_blogger" primaryKey="id" dataNode="dn1" >     </table> 
<!--按需配置分片規(guī)則-->
        <table name="t_area" primaryKey="id" dataNode="dn1,dn2,dn3" rule="mod-long1">     </table> 
<table name="t_blog" primaryKey="id" dataNode="dn1" >     </table> 
<table name="t_blogtype" primaryKey="id" dataNode="dn1" >     </table> 
</schema>
<!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743"
/> -->
<dataNode name="dn1" dataHost="localhost1" database="jeeshop" />
<dataNode name="dn2" dataHost="localhost2" database="jysystem" />
<dataNode name="dn3" dataHost="localhost3" database="dn3" />
<!--<dataNode name="dn4" dataHost="sequoiadb1" database="SAMPLE" />
<dataNode name="jdbc_dn1" dataHost="jdbchost" database="db1" />
<dataNode name="jdbc_dn2" dataHost="jdbchost" database="db2" />
<dataNode name="jdbc_dn3" dataHost="jdbchost" database="db3" /> -->
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="localhost:3306" user="root"
   password="">
<!-- can have multi read hosts 
<readHost host="hostS2" url="192.168.1.200:3306" user="root" password="" /> -->
</writeHost>
<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
</dataHost>
<dataHost name="localhost2" maxCon="1000" minCon="10" balance="0"
  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM2" url="127.0.0.1:3306" user="root"
   password="">
<!-- can have multi read hosts 
<readHost host="hostS2" url="192.168.1.200:3306" user="root" password="" /> -->
</writeHost>
<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
</dataHost>
<dataHost name="localhost3" maxCon="1000" minCon="10" balance="0"
  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM2" url="127.0.0.1:3306" user="root"
   password="">
<!-- can have multi read hosts 
<readHost host="hostS2" url="192.168.1.200:3306" user="root" password="" /> -->
</writeHost>
<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
</dataHost>
3,rule.xml配置分片規(guī)則
    添加如下規(guī)則 按表的name字段進行分片存儲
<tableRule name="mod-long1">
<rule>
<columns>name</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
備注:內(nèi)容太多,記一下重點. 分庫后連接查詢不在同一個庫是查不到數(shù)據(jù)的,真有這需要那就真需要考慮
設計是否合理了.


傻 瓜 2017-10-01 17:40 發(fā)表評論
]]>
springboot中action綁定ServletRequest的attirbute的值傳參http://www.tkk7.com/fool/archive/2017/09/29/432838.html傻 瓜傻 瓜Fri, 29 Sep 2017 03:58:00 GMThttp://www.tkk7.com/fool/archive/2017/09/29/432838.htmlhttp://www.tkk7.com/fool/comments/432838.htmlhttp://www.tkk7.com/fool/archive/2017/09/29/432838.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/432838.htmlhttp://www.tkk7.com/fool/services/trackbacks/432838.html根據(jù)token查找到對應的用戶信息。比如分布式框架中獲取用戶信息等.springboot中可以自
定義參數(shù)解析器來綁定參數(shù),通過它可以拿到ServletRequest中的attirbute中的值進行參數(shù)
綁定。

自定義一個annotation,通過這個注解中的 name查找attribute中的key對應的值 

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface AttributeResolve {
String name() default "user";
}

自定義一個解析器類

import javax.servlet.http.HttpServletRequest;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
public class AttributeArgumentResolver implements HandlerMethodArgumentResolver{
@Override
public Object resolveArgument(MethodParameter arg0, ModelAndViewContainer arg1, NativeWebRequest arg2,
WebDataBinderFactory arg3) throws Exception {
// TODO Auto-generated method stub
Object resultObj=null;
 AttributeResolve mp =  arg0.getParameterAnnotation(AttributeResolve.class);
 if(mp!=null) {
String attributeName= mp.name();
HttpServletRequest request = arg2.getNativeRequest(HttpServletRequest.class);
resultObj = request.getAttribute(attributeName);
 }
return resultObj;
}
@Override
public boolean supportsParameter(MethodParameter arg0) {
// TODO Auto-generated method stub
return  arg0.hasParameterAnnotation(AttributeResolve.class);
}

springboot中注冊自定義的參數(shù)解析器
@Configuration
public class MyWebMvcConfig extends WebMvcConfigurerAdapter{
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new AttributeArgumentResolver());
    }
}


使用方法.
需要在action調(diào)用前向HttpServletRequest中的attribute中注入值 ,可以自定義一個filter,在filter中進行處理
如在filter中處理app傳過來的token驗證后取得對應的用戶信息等.下面例子簡單放入一個對象
@WebFilter(filterName = "axssFilter", urlPatterns = "/*",
initParams = {
@WebInitParam(name = "ignores", value = "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*")// 忽略資源
}
)
public class XssFilter implements javax.servlet.Filter{
private Set<String> prefixIignores = new HashSet<String>();
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
            Blogger user = new Blogger();
          user.setUsername("asfdasdf");
         request.setAttribute("user", user);
               chain.doFilter(request, response);  
}
}

action獲取attribute中放入的對象
        @RequestMapping("/index")
public String index(@AttributeResolve(name="user") Bloggerbh, HttpServletRequest request,Model model) 

嗯,還算優(yōu)雅




傻 瓜 2017-09-29 11:58 發(fā)表評論
]]>
sbringboot異步執(zhí)行http://www.tkk7.com/fool/archive/2017/09/26/432832.html傻 瓜傻 瓜Tue, 26 Sep 2017 04:26:00 GMThttp://www.tkk7.com/fool/archive/2017/09/26/432832.htmlhttp://www.tkk7.com/fool/comments/432832.htmlhttp://www.tkk7.com/fool/archive/2017/09/26/432832.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/432832.htmlhttp://www.tkk7.com/fool/services/trackbacks/432832.html
import java.util.concurrent.Executor;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
@EnableAsync   //開啟異步任務支持
public class TaskExcutorConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
// TODO Auto-generated method stub
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setMaxPoolSize(10);
taskExecutor.setQueueCapacity(20);
taskExecutor.setCorePoolSize(5);
taskExecutor.initialize();
return taskExecutor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
// TODO Auto-generated method stub
return null;
}

任務類或方法

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
//@Async 寫在這里則整個類的方法都 是異步執(zhí)行
@Service
public class AsynTestService {
@Async   //需要異步執(zhí)行的方法
public void asyncTest() {
for(int i = 0; i < 10;i++) {
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}


傻 瓜 2017-09-26 12:26 發(fā)表評論
]]>
springboot文件上傳等雜項http://www.tkk7.com/fool/archive/2017/09/18/432826.html傻 瓜傻 瓜Mon, 18 Sep 2017 03:01:00 GMThttp://www.tkk7.com/fool/archive/2017/09/18/432826.htmlhttp://www.tkk7.com/fool/comments/432826.htmlhttp://www.tkk7.com/fool/archive/2017/09/18/432826.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/432826.htmlhttp://www.tkk7.com/fool/services/trackbacks/432826.htmlspringmvc中配置文件上傳寫法在boot并不支持
@Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(100000000);
return multipartResolver;
}
得這樣寫
  @Bean
   public MultipartConfigElement multipartConfigElement() {
       MultipartConfigFactory factory = new MultipartConfigFactory();
       factory.setMaxFileSize("128KB");
       factory.setMaxRequestSize("128KB");
       return factory.createMultipartConfig();
   }

2,攔截器
繼承HandlerInterceptorAdapter確實可以攔截,但是afterCompletion在preHandle方法返回false后并
不執(zhí)行,那么只能在preHandle中處理了,比如轉向,ajax請求返回內(nèi)容

3,關于快速跳轉
有時候只是做一個簡單的跳轉,可以集中寫在這里
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/index").setViewName("/index");
       registry.addViewController("/converter").setViewName("/converter");
}

完整示例:
package com.example.demo.config;
import java.util.List;
import javax.servlet.MultipartConfigElement;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
//其中默認配置的 /** 映射到 /static (或/public、/resources、/META-INF/resources) 
//其中默認配置的 /webjars/** 映射到 classpath:/META-INF/resources/webjars/ 
/*
spring.mvc.static-path-pattern=
@Configuration
public class MyWebAppConfigurer extends WebMvcConfigurerAdapter {
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/myres/**").addResourceLocations("classpath:/myres/");
//使用外部目錄 registry.addResourceHandler("/api_files/**").addResourceLocations("file:D:/data/api_files");
super.addResourceHandlers(registry);
}
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
viewResolver.setViewClass(JstlView.class);
return viewResolver;
}
//攔截器
@Override
public void addInterceptors(InterceptorRegistry registry) {// 2
InterceptorRegistration i=registry.addInterceptor(demoInterceptor());
i.addPathPatterns("/jsp/*");//只攔截 /jsp/* 的action
}
@Bean
// 1  配置攔截器
public DemoInterceptor demoInterceptor() {
return new DemoInterceptor();
}
//快速轉向
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// registry.addViewController("/index").setViewName("/index");
registry.addViewController("/toUpload").setViewName("/upload");
registry.addViewController("/converter").setViewName("/converter");
registry.addViewController("/sse").setViewName("/sse");
registry.addViewController("/async").setViewName("/async");
}
   @Bean
   public MultipartConfigElement multipartConfigElement() {
       MultipartConfigFactory factory = new MultipartConfigFactory();
       factory.setMaxFileSize("128KB");
       factory.setMaxRequestSize("128KB");
       return factory.createMultipartConfig();
   }
}
攔截器類
public class DemoInterceptor extends HandlerInterceptorAdapter {// 1
@Override
public boolean preHandle(HttpServletRequest request, // 2
HttpServletResponse response, Object handler) throws Exception {
long startTime = System.currentTimeMillis();
System.out.println("本次始請求處理時間為:" + startTime + "ms");
request.setAttribute("startTime", startTime);
if (request.getHeader("x-requested-with") != null
&& request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) {
response.setHeader("sessionstatus", "timeout"); // 響應頭設置session狀態(tài)
} else {
response.sendRedirect("/");
}
return false;
}
@Override
public void postHandle(HttpServletRequest request, // 3
HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
long startTime = (Long) request.getAttribute("startTime");
request.removeAttribute("startTime");
long endTime = System.currentTimeMillis();
System.out.println("本次請求處理時間??:" + new Long(endTime - startTime) + "ms");
request.setAttribute("handlingTime", endTime - startTime);
}
}
文件上傳頁面upload.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>upload page</title>
</head>
<body>
<div class="upload">
<form action="upload" enctype="multipart/form-data" method="post">
<input type="file" name="file"/><br/>
<input type="submit" value="上傳">
</form>
</div>
</body>
</html>

文件上傳控制器類

@Controller
public class UploadController {
@RequestMapping(value = "/upload",method = RequestMethod.POST)
//MultipartFile[] ,涓婁紶澶氫釜鏂囦歡
public @ResponseBody String upload(@RequestParam("file") MultipartFile file) {//1
try {
FileUtils.writeByteArrayToFile(new File("e:/upload/"+file.getOriginalFilename()),
file.getBytes()); //2
return "ok";
} catch (IOException e) {
e.printStackTrace();
return "wrong";
}
}
}


傻 瓜 2017-09-18 11:01 發(fā)表評論
]]>
springboot中的jsp支持http://www.tkk7.com/fool/archive/2017/09/18/432823.html傻 瓜傻 瓜Mon, 18 Sep 2017 01:22:00 GMThttp://www.tkk7.com/fool/archive/2017/09/18/432823.htmlhttp://www.tkk7.com/fool/comments/432823.htmlhttp://www.tkk7.com/fool/archive/2017/09/18/432823.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/432823.htmlhttp://www.tkk7.com/fool/services/trackbacks/432823.html
       <dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
      </dependency>
   <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>

寫配置類配置jsp支持
@Configuration
public class MyWebAppConfigurer extends WebMvcConfigurerAdapter {

@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
viewResolver.setViewClass(JstlView.class);
return viewResolver;
}

}

所謂零配置。。。 一言難盡


傻 瓜 2017-09-18 09:22 發(fā)表評論
]]>
js外部調(diào)用更新angularjs的ng-repeat視圖問題 http://www.tkk7.com/fool/archive/2017/09/11/432808.html傻 瓜傻 瓜Mon, 11 Sep 2017 13:37:00 GMThttp://www.tkk7.com/fool/archive/2017/09/11/432808.htmlhttp://www.tkk7.com/fool/comments/432808.htmlhttp://www.tkk7.com/fool/archive/2017/09/11/432808.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/432808.htmlhttp://www.tkk7.com/fool/services/trackbacks/432808.html新table中數(shù)據(jù)就有些麻煩。所以用angularjs重構一下。
頁面中angularjs展示數(shù)據(jù)  
<body   ng-controller="multi"> 
  <table id="baseTable" class="table table-striped table-bordered table-hover" >
<thead>
<tr><th style="width:10%" class="center">標題</th>
</tr>
</thead>
               <body   ng-controller="multi">   
                <tbody>  
                         <tr ng-repeat="item in defaultData " >
                             <td class='center hidden-480'>{{item.title}}</td>    
               </tr> 
  </tbody>
            </body>
  </table>
</body>
外部jquery的ajax調(diào)用更新數(shù)據(jù) 
                    var controllerScope = $('body[ng-controller="multi"]').scope();
            controllerScope.defaultData=results;
            controllerScope.$apply();
          
注意:外部js不要刪除了下面這段代碼塊。
                        <tr ng-repeat="item in defaultData " >
                             <td class='center hidden-480'>{{item.title}}</td>    
                 </tr> 


傻 瓜 2017-09-11 21:37 發(fā)表評論
]]>
業(yè)務規(guī)則與自定義規(guī)則處理庫http://www.tkk7.com/fool/archive/2017/08/20/432763.html傻 瓜傻 瓜Sun, 20 Aug 2017 06:52:00 GMThttp://www.tkk7.com/fool/archive/2017/08/20/432763.htmlhttp://www.tkk7.com/fool/comments/432763.htmlhttp://www.tkk7.com/fool/archive/2017/08/20/432763.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/432763.htmlhttp://www.tkk7.com/fool/services/trackbacks/432763.html更改或者新增新的業(yè)務規(guī)則.尤其是在某些場合如促銷,積分商城等場景。正因為規(guī)則如此重要,建議使用單獨的文檔
維護,規(guī)則名稱編號可以與用例名稱編對一一對應。
業(yè)務規(guī)則分類:
一,內(nèi)稟規(guī)則:業(yè)務實體本身的規(guī)則。如訂單中銷售記錄不能為空,數(shù)量不能為等。
二,全局規(guī)則:一般與所有用例相關而不是某個特定用例相關。例如系統(tǒng)安全方面的sql注入,ddos攻擊等。
三,交互規(guī)則:用于用例當中。它們規(guī)定了滿足什么條件后業(yè)務將如何反應。有些規(guī)則需要開發(fā)成系統(tǒng)用例。比如人事
管理系統(tǒng)中請假業(yè)務只有工作日才計入請假天數(shù),那么這個工作日就需要電腦來維護了,會作為一個系統(tǒng)用例存在,并
且作為請假用例的前置條件。 交互規(guī)則又是最容易引起.
交互規(guī)則如此靈活多變,需要良好的設計才能保證系統(tǒng)的擴展性和可維護性。如何做:
思路一:
    在 j
avax.swing.border包提供了Border接口和幾個不同的Boder的實現(xiàn)。在swing中每個組件提供了paint方法,每
個組件知道怎么畫自己展示自己的外觀。那么我們可以提供業(yè)務規(guī)則處理接口,每個具體業(yè)務規(guī)則自己知道怎么處理業(yè)務。
可以用簡單工廠來決定調(diào)用哪一個具體業(yè)務規(guī)則。這個是策略模式的使用,缺點是新增具體業(yè)務時工廠類會修改。也可以
用觀察者模式來實現(xiàn),所有的具體業(yè)務類都來觀察這個業(yè)務規(guī)則,自己判斷是不是自己可以處理的,不是就不理會。
基于策略模式的規(guī)則實現(xiàn)類圖:

思路二:
     規(guī)則引擎比如drools處理一些問題 。
規(guī)則引擎適合于做業(yè)務規(guī)則頻繁變化的場景.把業(yè)務規(guī)則抽出來通過規(guī)則引擎來
處理。類似工作流系統(tǒng)的概念。

自定義規(guī)則處理庫:
     一些動態(tài)的語言很適合來做這樣的事情。java支持script.Mvel是一個表達式語言,drools也支持mvel來處理業(yè)務規(guī)則.
這里自定義規(guī)則引擎使用Mvel表達式語言.
      規(guī)則文件示例:
     
<rules>
       <!--rule-set 是一個規(guī)則集,執(zhí)行規(guī)則 rule1時會迭代規(guī)則集里面所有的規(guī)則(mvel-rule)-->
<rule-set name="rule1">
<!-- id是規(guī)則的標識,也是默認的排序處理順序。exclusive 是排它。如果為true,則當前規(guī)則執(zhí)行后,不再執(zhí)行后面的規(guī)則-->
<mvel-rule id="step1"  exclusive="false">
<block><![CDATA[
if(salary<=3500) {result=0;}
]]></block>
</mvel-rule>
<mvel-rule id="step2" exclusive="false">
<block><![CDATA[if(salary>3500) {result=1};]]></block>
</mvel-rule>
</rule-set>
<rule-set name="rule2">
<mvel-rule id="step1"  exclusive="false">
<block><![CDATA[ 
             import  com.custom.rule.*;
             rs = new RuleSet(); 
             rs.name="asdf";
              rs.print();
         ]]></block>
</mvel-rule>
</rule-set>
</rules>
rule2中可見mvel可以導入未知jar包并進行處理,確實強大,就有了足夠的靈活性. 自定義規(guī)則庫源碼及使用示例下載.
本例依賴xstream
1.4.9 ,mvel2.0
自定義規(guī)則庫除了可以應用于一般系統(tǒng)業(yè)務處理,當然也還可以用于大數(shù)據(jù)處理。比如hadoop/spark統(tǒng)計用戶積分等
如果再定義一套配置規(guī)則的UI。。。好的,業(yè)務人員可以自己設置計算規(guī)則了。








傻 瓜 2017-08-20 14:52 發(fā)表評論
]]>
架構設計過程分析小結http://www.tkk7.com/fool/archive/2017/04/28/432490.html傻 瓜傻 瓜Fri, 28 Apr 2017 06:22:00 GMThttp://www.tkk7.com/fool/archive/2017/04/28/432490.htmlhttp://www.tkk7.com/fool/comments/432490.htmlhttp://www.tkk7.com/fool/archive/2017/04/28/432490.html#Feedback0http://www.tkk7.com/fool/comments/commentRss/432490.htmlhttp://www.tkk7.com/fool/services/trackbacks/432490.html架構設計過程簡單總結:架構設計的驅動力=功能+質(zhì)量+約束.功能即系統(tǒng)要滿足的業(yè)務需求。質(zhì)量包括運行期質(zhì)量和開發(fā)期質(zhì)量. 常見的運行期質(zhì)量屬性包括軟件系統(tǒng)的易用性、性能、可伸縮性、持續(xù)可用性、魯棒性、安全性等。開發(fā)期質(zhì)量屬性是開發(fā)人員最為關心的,要達到怎樣的目標應根據(jù)項目的具體情況而定。約束可能是商業(yè)預算,運行環(huán)境,使用人員水平,開發(fā)團隊水平等。架構設計過程如下:

一,需求收集,分析。

此處省略2000字。。。 見前篇 《需求收集、分析小結http://www.tkk7.com/fool/archive/2017/04/28/432489.html

二,概念架構/概念模型

從需求中找出關健、重大需求,進行概念建模.下面三個圖稱之魯棒圖。其中控制對象理解為mvc模式中的控制器和model。使用魯棒圖可以建立概念模型,約等于初步設計。初步設計并不關心細節(jié)。

 

 魯棒圖建立概念模型語法:

概念設計舉例:


上次談到超市小票如何分析實體對象,本次接著舉例如何對收銀進行概念建模



如上圖:具備基本收銀功能的概念模型。概念模型建??梢允窃隽康?。比如商品折扣或其它

促銷活動等。


概念架構的用途:

1) 可以幫助我們找出領域模型中的實體對象。

2) 檢查需求用例是否正確和完善。

3)初步設計,魯棒圖是一種初步設計技術。

4)根據(jù)用例和概念設計劃分系統(tǒng)、子系統(tǒng)、模塊或者包。借助魯棒圖,初步識別功能背后的職責,規(guī)劃切分系統(tǒng)的方式。

 

三,關注非功能性需求,包括運行期質(zhì)量和開發(fā)期質(zhì)量。

運用目標場景決策表對非功能性需求作出決策.小舉例:

目標

場景

決策

易用性

銷售員需要輸入條碼檢索商品,繁瑣且速度慢

根據(jù)條碼,品名模糊匹配檢索商品,提供輔助錄入。

性能

長時間穩(wěn)定運行

數(shù)據(jù)庫集群,服務應用集群                                        

        技術選型                             需要管理錢箱、打印機、響應速    pos系統(tǒng)使用c/s
                                                度快

 

 

 

四,細化架構。RUP 4+1視圖法則將架構需要關注的不同的點使用不同的視圖表示.從不同的維度對系統(tǒng)進行解讀,從而形成統(tǒng)一軟件過程架構描述。

運行架構:

關心進程、線程、同步的相關設計,捕捉并發(fā)和同步特征

邏輯架構:

關心邏輯層(layer)的劃分,系統(tǒng)/子系統(tǒng)的劃分,劃分模塊及其接口的定義。功能組劃分也屬于邏輯架構.功能:不僅包括用戶可見的功能,還包括為實現(xiàn)用戶功能而必須提供的"輔助功能模塊";它們可能是邏輯層、功能模塊等。

物理架構:

關心服務器選型,物理層劃分(tier)。 描述如何部署機器和網(wǎng)絡來配合軟件系統(tǒng)的可靠性、可伸縮性等要求.layer就運行在tier上。Tier反映系統(tǒng)伸縮能力。

開發(fā)架構:

描述了在開發(fā)環(huán)境中軟件的靜態(tài)組織結構。即開發(fā)工具下的開發(fā)視圖,描述文件編譯及其依賴關系。而使用maven管理開發(fā)的項目編譯及依賴關系結構更加分明。

數(shù)據(jù)架構:

關心數(shù)據(jù)的存儲、分布和文件的存放及數(shù)據(jù)的復制,傳遞,同步。數(shù)據(jù)的存放包括sql,內(nèi)存數(shù)據(jù)庫,nosql數(shù)據(jù)庫等.

 

邏輯架構設計舉例:

還是用收銀系統(tǒng)簡單舉例,收銀系統(tǒng)邏輯架構圖如下:



整個系統(tǒng)劃系統(tǒng)為系統(tǒng),切為兩個系統(tǒng),一個收銀員角色處理的業(yè)務,收銀系統(tǒng)。

一個后臺管理系統(tǒng)。后臺管理系統(tǒng)包括用戶管理模塊,基礎資料模塊(產(chǎn)品資料等)

銷售模塊(本例對銷售單)。另外,因為收銀系統(tǒng)需要和后臺系統(tǒng)交互,把收銀系統(tǒng)需要使用到的相關的各模塊封裝成一個接口模塊,專門處理和收銀系統(tǒng)交互的模塊。系統(tǒng)、模塊之間的通訊方式應當盡量避免雙向。相互依賴可能會引發(fā)很多問題。

 

物理架構設計舉例:

物理架構和邏輯架構可以相互印證。描述軟件系統(tǒng)的物理布署。



如果考慮運行期質(zhì)量比如長時間運行布署圖可能應用做集群。數(shù)據(jù)庫做集群等。邏輯層layer運行在物理層tier之上

 

運行架構和數(shù)據(jù)架構視圖根據(jù)實際情況可選設計





傻 瓜 2017-04-28 14:22 發(fā)表評論
]]>
主站蜘蛛池模板: 亚洲欧洲国产精品香蕉网| AV大片在线无码永久免费| 免费无码国产在线观国内自拍中文字幕 | 99亚洲精品卡2卡三卡4卡2卡| 亚洲AV无码专区在线亚| 亚洲一级毛片免费观看| 亚洲中文字幕日本无线码| 亚洲色欲啪啪久久WWW综合网| 国产亚洲精品影视在线| 亚洲人成人伊人成综合网无码| 亚洲一线产品二线产品| 天堂亚洲国产中文在线| 亚洲av无码专区青青草原| 国产成人精品亚洲| 一级毛片免费不卡| 97无码人妻福利免费公开在线视频 | 亚洲人成在线精品| 亚洲日韩国产欧美一区二区三区| 亚洲日本一线产区和二线| 久久亚洲精品高潮综合色a片| 日韩在线观看免费| 一个人看的www免费视频在线观看 一个人免费视频观看在线www | 亚洲一区二区视频在线观看| 日韩亚洲变态另类中文| 久久久久无码精品亚洲日韩 | 久久精品国产精品亚洲下载| 国产成人A亚洲精V品无码| 久久亚洲国产中v天仙www| 亚洲综合激情六月婷婷在线观看| 亚洲国产系列一区二区三区| 国产精品亚洲а∨天堂2021| 美女网站在线观看视频免费的| 97国产在线公开免费观看| 99国产精品永久免费视频| 国产精品无码素人福利免费| 亚洲中文字幕久久精品无码APP | 日韩毛片无码永久免费看| 亚洲无码日韩精品第一页| 亚洲天天在线日亚洲洲精| 亚洲中文无码卡通动漫野外| 一级做a爱过程免费视频高清|