1. Preface
Section III describes some of the basic concepts of Netty, which describes the first concept of Netty bootstrap--startup class. Netty in the server and the client's startup class is not the same, this is not mistaken, the class is under the bootstrap package. All subsequent chapters are based on the current version of the Netty 4.1.24.Final version.
2. Detailed structure
There are two main contents in bootstrap: Bootstrap and CONFIG. ChannelFactory was moved to another place, this interface has been deprecated. Disorderly into a failedchannel, here for the moment no matter.
Config gives people the ambiguity that we are going to set this config,bootstrap read this setting to initialize. In fact, the effect of this class is to expose our settings for bootstrap, which is not set for the purpose of displaying the configuration. Setting up the relevant content or need to directly manipulate bootstrap. So config is not introduced, only Abstractbootstrap, Bootstrap and Serverbootstrap are left, this chapter mainly introduces these three content.
2.1 Abstractbootstrap
This is the abstract parent class for all startup classes and contains a series of underlying content.
This is the underlying field for this class:
Group: Thread Pool
ChannelFactory: Creating a factory class for channel
LocalAddress: Local Address
Options:socket and some of its property settings
Attrs: Additional property settings
Handler:channel Processing Class
The options and attrs in the example is not shown in the moment, the use of it is not complex, see the specific method can be. Here are some ways to focus.
Public B channel (CLASS<? extends c> Channelclass) { if (Channelclass = = null) { throw new Nullpointerexcepti On ("Channelclass"); } Return ChannelFactory (New reflectivechannelfactory<c> (Channelclass));
This method can be seen, after putting Channel.class, it is actually through a factory class generated channel object, reflectivechannelfactory approach is also very simple, is reflected by the way newinstance () An object of the class. In addition Bootstrap also directly provides a ChannelFactory method, from the field can also see that we need a channelfactory.
LocalAddress (..) The method is to set the Bind method to listen to the local address port, and bind () with the use of bind (..) is to use the incoming address directly, without localaddress the previously set.
Finally, the most important of the bind (address) method, this is for the service side of the listening port link, to see what this step actually did something:
Public channelfuture bind (socketaddress localaddress) {validate (); if (localaddress = = null) {throw new NullPointerException ("localaddress"); } return Dobind (localaddress); } Private Channelfuture Dobind (final socketaddress localaddress) {final Channelfuture regfuture = initandregist ER (); Final Channel channel = Regfuture.channel (); if (regfuture.cause () = null) {return regfuture; if (Regfuture.isdone ()) {//AT-this-point we know the registration is complete and successful. Channelpromise promise = Channel.newpromise (); DoBind0 (Regfuture, channel, localaddress, Promise); return promise; } else {//registration almost always fulfilled already and just in case it's not. Final Pendingregistrationpromise promise = new Pendingregistrationpromise (channel); Regfuture.addlistener (New ChannelfUturelistener () {@Override public void Operationcomplete (channelfuture) throws Excep tion {throwable cause = Future.cause (); if (cause! = NULL) {//Registration on the EventLoop failed so fail the channelpromise directly to Not cause a//illegalstateexception once we try to access the eventloop of the Channel. Promise.setfailure (cause); } else {//registration is successful, so set the correct executor to use. See https://github.com/netty/netty/issues/2586 promise.registered (); DoBind0 (Regfuture, channel, localaddress, Promise); } } }); return promise; } }
1, first check whether the basic configuration is complete, the main concern two content: thread pool and ChannelFactory.
2. Generate a channel object through ChannelFactory and initialize (init (Channel), method The method is an abstract method, the subclass completes the initialization action), fails to close the related resources, then registers the channel with the line Cheng ( That is, the thread pool provides a way to register the channel), clearing the associated resources as failed.
3, if the previous success, start binding port address, bind failed to automatically shut down, this is done by the channel itself, Channel.bind (address, promise).
Above the entire bind method is completed, the main attention is the following:
1. The startup class can decide the operation of channel initialization by itself;
2.channel must be registered in the thread pool, which provides the entry for channel access;
3. The specific monitoring port method is implemented by channel itself;
Other methods do not matter, so the abstract parent needs to focus on this point.
2.2 Serverbootstrap
This class is the starting class for the server, and according to section three, the connection thread pool is used to distinguish between the listener ports of the service side itself and the channel of the client. In fact, not just the thread pool, its inheritance of the abstract parent class is related to the server, the client's content is set in another set of fields, so we can see that we set the handler is Childhandler, the server itself is not required to set handler. The specific client-related settings are as follows:
Most of the content is set for the child, do not need one by one explanation, should be able to understand.
This class needs to pay attention to only one method, that is, the abstract parent class to the subclass implementation of the Init method, how to initialize the channel?
VOID Init (Channel channel) throws Exception {final map<channeloption<?>, object> options = Options 0 (); Synchronized (options) {setchanneloptions (channel, options, logger); } final Map<attributekey<?>, object> attrs = Attrs0 (); Synchronized (attrs) {for (entry<attributekey<?>, object> E:attrs.entryset ()) {@S Uppresswarnings ("unchecked") attributekey<object> key = (attributekey<object>) E.getKey (); Channel.attr (Key). Set (E.getvalue ()); }} channelpipeline P = Channel.pipeline (); Final Eventloopgroup currentchildgroup = Childgroup; Final Channelhandler currentchildhandler = Childhandler; Final entry<channeloption<?>, object>[] currentchildoptions; Final entry<attributekey<?>, object>[] currentchildattrs; Synchronized (childoptions) {currentChildoptions = Childoptions.entryset (). ToArray (Newoptionarray (Childoptions.size ())); } synchronized (childattrs) {currentchildattrs = Childattrs.entryset (). ToArray (Newattrarray (childattrs). Size ())); } p.addlast (New channelinitializer<channel> () {@Override public void Initchannel (final Channel ch) throws Exception {final Channelpipeline pipeline = Ch.pipeline (); Channelhandler handler = Config.handler (); if (handler! = null) {pipeline.addlast (handler); } ch.eventloop (). Execute (new Runnable () {@Override public void run () {Pipeline.addlast (New Serverbootstrapacceptor (CH, Currentchildgro Up, Currentchildhandler, Currentchildoptions, currentchildattrs)); } }); } }); }
1, the first is to set the channel socket parameters, this is the option parameter we set previously.
2, is set property, this property is bound with the channel, is also the previous set of attr parameters.
3, finally is the key step, obtained this channel Pipeline,pipeline concept channel that chapter again introduces, here only need to understand the channel management is through the pipeline complete. Before I said the server does not need to set the handler, does not mean that completely can not, here for the service side of the channel set handler. We can think about how to set properties on the channel of the client if we don't handle it. Here the Serverbootstrapacceptor is set when the channel is initialized.
public void Channelread (Channelhandlercontext ctx, Object msg) { Final Channel child = (Channel) msg; Child.pipeline (). AddLast (Childhandler); Setchanneloptions (Child, childoptions, logger); for (ENTRY<ATTRIBUTEKEY<?>, object> e:childattrs) {child.attr ((attributekey<object>) E. GetKey ()). Set (E.getvalue ()); try {childgroup.register (child). AddListener (New Channelfuturelistener () { @Override public void Operationcomplete (channelfuture) throws Exception { if (!future.issuccess ()) {Forceclose (Child, Future.cause ()); } } }); } catch (Throwable t) {forceclose (child, T); } }
The above is Serverbootstrapacceptor's Read method, which does the following:
1. Set Handler
2. Set socket properties
3. Set attr
4, the channel is registered to Childgroup, the client's thread pool.
Can you speculate about the logic here, because the Read method is not triggered when the data is read? According to the Java NiO example, this step should appear in the Accept event stage, so it can be inferred that the stage called the handler read method, passed the client channel of accept, here to deal with the channel, as to, right, To follow the code to verify (this is right, briefly, to NiO, for example, the main logic in the Nioeventloop call Unsafe.read (), for the server side is the Niomessageunsafe read () method, It calls the Doreadmessages method of Nioserversocketchannel, puts the Niosocketchannel object of the Accept in buf, and then returns to the Read () method, By pipeline call Firechannelread (Buf[i]), this will eventually be transmitted to the handler, the handler received is not a byte but a client's channel object, So this logic should be very careful when extending the connection method . But through the above instructions, you can understand why the server does not have to set up the handler, because it can do the same thing, unless you have other things to do, perhaps the statistics how long a connection come in? This has not been tested, but according to the principle, it should be possible unless other restrictions are made.
2.3 Bootstrap
The last setting for our client. The biggest difference between a client and a server is that it is connect, not bind, and it needs to know the address of the remote server. So the client field is more like this:
remote address, and translation of the remote address of resolver. Since the client is concerned with the Connect method, not the Bind method, we re-describe the Connect method:
Private Channelfuture doresolveandconnect (final socketaddress remoteaddress, final socketaddress localaddress) { Final Channelfuture regfuture = Initandregister (); Final Channel channel = Regfuture.channel (); if (Regfuture.isdone ()) {if (!regfuture.issuccess ()) {return regfuture; } return DoResolveAndConnect0 (channel, Remoteaddress, LocalAddress, Channel.newpromise ()); } else {//registration almost always fulfilled already and just in case it's not. Final Pendingregistrationpromise promise = new Pendingregistrationpromise (channel); Regfuture.addlistener (New Channelfuturelistener () {@Override public void Operationcomplete ( Channelfuture future) throws Exception {//Directly obtain the cause and does a null check so we only NE Ed one volatile read in case of A//failure. Throwable cause = Future.cause (); if (cause! = NULL) {//Registration on the EventLoop failed so fail the channelpromise directly to Not cause a//illegalstateexception once we try to access the eventloop of the Channel. Promise.setfailure (cause); } else {//registration is successful, so set the correct executor to use. See https://github.com/netty/netty/issues/2586 promise.registered (); DoResolveAndConnect0 (channel, Remoteaddress, localaddress, Promise); } } }); return promise; } }
1, the first step and bind operation, create a channel, initialize the channel (operation almost, register handler, set socket parameters, set attr) registered to the thread pool, failure to clear the resources.
2, according to the thread pool to obtain resolver, to different connections, translation of different addresses.
3. Connect and invoke the Connect method provided by the channel.
Roughly the same as the server side, there is no need to add additional content, just use the abstract parent class fields to complete.
3. PostScript
This section focuses on some of the contents of the bootstrap package, which are some of the actions that Netty initiates. The main contents are as follows:
1. Client and server execution logic is different, one is the connect one is bind, but ultimately through the channel to do the operation, that is, the channel determines the way to connect.
2. The server does not need to set the server side of the handler, its built-in a serverboostrapacceptor, mainly set the channel properties of the client, this logic is ultimately by the service side of the channel read-related method control, The Channel,read method on the service side receives a channel instead of a byte.
3. All channel needs to be registered with EventLoop.
The above points are related to the channel,eventloop, so it is proposed to facilitate the follow-up concept of mutual verification, and its specific work.
Netty Core Concept (4) of the bootstrap