We’ve already shared how a Dubo-Go RPC request reaches the server. Now, we’ll explain how the Provider handles the received data. Before we get there, we need to understand how the Provider receives data. As you know, receiving network requests requires starting a Web Server and listening on a network port. Therefore, this article starts with how to start the Web Server of the Provider and conducts in-depth analysis.

Start the Provider

Before starting Dubbo-Go, you need to manually register the structure that provides the service (UserProvider in this case) and the structure that has non-basic parameters (User in this case) into Dubbo-Go.

` func init () {` ` / / registered Provider ` ` config. SetProviderService (new (UserProvider) ` ` / / registered hessian 2 structure, Func main() {// Start config.load () 'initSignal()'} 'from the configuration fileCopy the code

After calling the Provider’s startup method (config.load), Dubbo-Go starts the Web Server by reading the user-written configuration.

Start the Web Server

The Web Server is an important step for receiving network data. Therefore, before analyzing the Provider’s RPC process for receiving data, learn how to start the Web Server. (The specific process will be explained in detail in subsequent articles)

` / / Start dubbo service ` ` func (s * Server) Start () {` `... Tcpserver.runeventloop (s.newSession) ' 'logger.Debugf("s bind addr{%s} OK!" , s.addr)` `s.tcpServer = tcpServer` `}`Copy the code

After you know how to start the Web Server, the Web Server acts as a Provider listening port, provides interface services, and registers the Provider information with the registry (including: Application and service meta information), allowing the Consumer to pull it locally ready to initiate an RPC.

Transport

At this point, another question might arise: How does the Provider know what methods to execute? How to find the corresponding method?

In fact, in the transport layer, it will first receive the message sent by the Consumer and find the corresponding method according to the information contained in the packet. The code looks like this:

`func (s *session) handlePackage() {` `... If _, ok := s.connection.(*gettyTCPConn); ok {` `if s.reader == nil {` `errStr := fmt.Sprintf("session{name:%s, conn:%#v, reader:%#v}", s.name, s.Connection, S. ader) 'log.Error(errStr)' 'panic(errStr)' '// parsing TCP packets'' err = s.handletcppackage () ' '} '... ` ` `}Copy the code

When the data packet is obtained, it needs to be converted into a structure that can be executed by the interface provided by the Provider. This is the deserialization operation that the next serialization layer needs to perform.

Codec

The serialization layer S. Reader uses RpcServerPackageHandler to parse the stream information sent from the Consumer into remoting.DecodeResult, which contains the corresponding reflection method, request parameters and other information.

'// Generate the corresponding Dubbo package struct' 'func (s *session) handleTCPPackage() error {'... PKG, pkgLen, err = s.reader.read (s, pktbuf.bytes ()... '// The parsed package is placed in the service execution queue for execution. ` `s.addTask(pkg)` `... ` ` `}Copy the code

Read the network packet and interpret it into the corresponding structure.

`func (p *RpcServerPackageHandler) Read(ss getty.Session, data []byte) (interface{}, int, Req, length, err := (p.server.codec).Decode(data ' '... ` ` `}Copy the code

DecodeResult, then determine whether you need to queue to wait for the implementation of the specific Provider interface logic.

'func(s *session) addTask(PKG interface{}) {' f := func() {' s.listener.OnMessage(s, PKG ' 's.int creadpkgnum ('' add to queue or ' 'if s.pool! = nil {` ` s.t Pool. AddTask (f) < < < < < to queue ` ` return ` ` f () < < < < < < direct execution ` ` `}Copy the code

 

Finally, it comes to the final stage of the Provider, where the interface processing logic provided by the actual Provider is executed through listeners.

Listener

The listener invokes the Invocation Invocation using the result parsed by the serialization layer, finds the corresponding method using the Service key provided by the Consumer, and then executes the corresponding business method. Finally, the execution results are returned layer by layer and returned to the Consumer caller.

'// Get the request from Getty, Func (h *RpcServerHandler) OnMessage(session Getty.Session, PKG interface{}) {'... ` `invoc, ok := req.Data.(*invocation.RPCInvocation)` `... // execute the corresponding method to be called. Where does the requestHandler come from? ` `result := h.server.requestHandler(invoc)` `... ` ` `}Copy the code

When Providr starts, the broker handler is established. After deserializing the obtained network request, the corresponding method is found through the service key provided by the Consumer, and the corresponding business method is executed.

`func (dp *DubboProtocol) openServer(url *common.URL) {` `... ' '// New RPCInvocation method' 'handler := func(Invocation * Invocation.RPCInvocation) protocol.RPCResult {' // Pass Find the corresponding method for the service key provided by the Consumer, And then execute the corresponding business methods ` ` return doHandleRequest (invocation) ` ` / / set into a Web server instance ` ` SRV: = remoting. NewExchangeServer (url, getty.NewServer(url, handler)` `dp.serverMap[url.Location] = sr` `srv.Start()` `... ` ` `}Copy the code

This is how Dubbo-Go’s Provider handles RPC requests.

conclusion

You already know how the Provider gets the information, parses it layer by layer and calls the corresponding methods. There are still a lot of deep knowledge about it worth exploring and learning one by one. For example, how does Dubo-Go expose services in the whole RPC process? The answer to this question will need to be found in subsequent articles.

Welcome to the community

Pay attention to the public account [minister technology road], in the public account background reply keyword [dubbogo] to join the community.