Spring Tips: IO, IO, It's Off to Work We Go

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi spring fans welcome to another installment of spring tips in this installment we're going to take a look at the wonderful and wide world of network programming and reactive programming and relate them uh to blocking and non-blocking io in particular remember the goals when we write reactive code we want scalability we want ease of composition and we want robustness reactive programming supports that first goal scalability because it makes it easier to write code that handles a large number of requests let's take a look at a pathological example first suppose you run a restaurant and you have open a few open tables and let's also suppose for reasons completely unrelated to this example uh the restaurant is called food factory bean cafe and it's on spring street in springfield usa because that's exactly what i would do if i had a restaurant now you're the only waiter on staff at the moment and a party comes in and you the waiter sit down with them and wait for the entire duration of their time in the restaurant promptly handling any requests but ignoring any of the parties that happen to come in in this scenario the party you served is happy exceedingly happy they got your full attention and prompt courteous service the service for them was quick but for everybody else it was unavailable and so naturally people aren't happy this approach doesn't scale i mean just think about it right like the the restaurant tour would have to hire more staff every time they added tables you can make this arrangement work uh but it's expensive right you can add more instances of the server for example you can create more restaurants or add more waiters or whatever but it's expensive right in this example this is more or less blocking io with something like the java io packages we can look at a simple example to kind of see it in action but it's pretty simple let's start with a baseline traditional blocking i o example when i say blocking the client from the perspective of the client things come to a standstill until something else finishes this has the benefit of being very easy to reason about but it's also limiting in our scalability synchronous and blocking io uh however couldn't be more accessible let's give it credit where credits do it's very easy to understand the example was felt and approachable uh but again bad result so i do think it serves as a bit of like pseudo code you know we have server sockets which take sockets and then there's io right let's write a an example that uses traditional blocking i o and so this will just be very simple um we'll start this project and i'll just keep adding to it in my in my ide okay so uh we're just going to call this uh io sure why not right we don't care and i guess i want lumbac uh i want java 17 and perhaps the reactive web support although i'm not going to build a web application i just want to have the libraries uh that that that will import for us so we'll hit generate we'll open this up in the ide okay so our example uh is not going to be a web application we're going to build network services uh but obviously we don't want to actually create a web server so we'll say that the application type is none okay and then in the i o application we're going to create a um a few simple implementations of a given interface right so that that interface will be interface i see network file sync uh and basically we're just gonna consume we're gonna we're gonna start a service that consumes data and it'll we'll write it in such a way that it'll give us back the bytes that have been sent to it from a network call yeah so there's this maybe we can even just there you go uh no actually not like that it's better okay so there's our basic contract and i want to implement this i want to create an implementation using synchronous blocking io so this is the easiest one to get right we don't have to do a lot of work to make this work uh and you've probably written something like this in universal okay so class io network file sync implements network file sync okay and we're going to um it's just a spring bean we're gonna go ahead and just i'll just call it a service why not in order for this to work we're gonna need to use the java i o types we're gonna have um a server socket okay so try var ss equals new server socket socket and we want this socket on the port that we've been given and this service socket is um auto closable right and but it also it could it could throw an exception so we'll say uh at sneaky throws and why not okay there's that this will this is a lumbar annotation that'll sim it'll capture the uh it'll try catch our code basically um okay so we're gonna start and we have a surf socket and now we just wanna like busy wait busy loop waiting for new requests to arrive so we'll say while true then we want to say try var socket equals ss dot accept and there we go socket okay good so there's the um socket um as that comes in we're gonna get an input stream and an output stream so this will block right this operation is a blocking operation it won't proceed nothing will happen until a socket connection is made yeah so once that's true then we can say that in is equal to um you know the socket dot get input stream and out is equal to the socket get output stream so now we have our basic uh network loop our busy loop what we want to do is we want to read the data coming in from the request via the client right so let's get the bytes we'll call this byte new byte 102 4 and i'm going to read uh some bytes and the the basic pattern here is you know you read until you get negative one that means that there's no more to read so we'll say while uh read is equal to in dot read bytes uh and while that does not equal negative one um write out the data okay so write out right um and the data that we're gonna read right out is the data that's been read from the stream and put into the binder right now you might think of it like a stream and each byte array is like a scoop okay we're gonna take data from the stream of bites in our scoop and then we're going to pour it into another bucket but we don't want to you know we might have some sediment left over from the last time we scooped so what we want is to only get the stuff that we've scooped out this time around the other stuff might be from the last time we scooped and you know the metaphors it doesn't quite exactly work but the idea is that we don't want to copy from this array stuff that was from the last scoop we only want to copy what we got on this time through the loop uh in this scoop so we'll use out dot write zero and then read right the number of bytes i'm going to start off at the zeroth element of the bytes array and then continue until the number of red items read will never be larger than the array element you know length itself so it'll never be more than one or two four elements okay it'll be at most uh enough to fill the the array okay so while we've got that okay so we've got our abstraction let's create a simple example that uses the java io abstractions so class io network file sync implements network file sync okay here's that at component and um you know this is going to it's a very predictable skeleton right we're going to um try to listen for new requests on a server socket right so server socket port okay and it'll be sneaky throws good and for each uh once we have a socket once we're out there waiting for requests we'll say that you know what we want a busy weight what a busy loop so i'll say try var socket equals ss.accept uh and that'll give us a pointer to a socket the thing is that call there will block it'll block until we actually get the socket that we want right so until a client makes a request we won't get nothing it'll just sit there on that thread waiting for that to happen as soon as that happens the the the execution on the thread of execution will continue unblocked so the next thing we want to do is get the input stream representing the data coming from the client okay and we also want to have an output stream uh in which to accumulate to collect all the bytes i'm going to create a little byte away output stream and i'm going to create a little like a scoop as well i'm going to scoop bytes out of the stream of data so 1024 that'll be this okay and we'll say while in dot read uh bytes or you know uh let's say bytes let's call that bytes well index read bytes is not negative one but we also need to capture what this means is uh it says i want to read as many bytes as we can until we get no bytes back negative one bytes back but i need to capture how many were red so i'll say var red equals negative one and i'll say read equals does not equal to that okay and with that that value that that uh number uh we can then write out the data so we'll say out.right uh this array starting from 0 up until red and red is some number less than 1024 in this case because our array our array length is one to four and some number greater than zero presumably um and we're going to keep going until we reach the end of the stream which is donated by negative one uh and then we're just going to accept everything and write it out to the consumer okay so it's called the bytes handler i'm going to accept the byte array right so we'll say out dot 2 byte array good so that's that's the basic implementation yeah that's just a it's a pretty trivial implementation uh i think it's pretty easy to understand what are we doing we're creating a loop creating a service socket we're looping waiting for incoming requests getting an input stream getting an output stream and obviously the problem with this is that if for whatever reason the incoming request has like five hours worth of data to send us then this loop will never proceed to the next you know iteration until those five hours of data are all read in is i'm saying so if there are any other requests that arrive they'll just be ignored we'll never get a chance to process those they'll just be uh sent back so one obvious optimization here is to spin this out on the thread to use an executor service or a thread pool to launch the requests uh so that they can be processed so for each new request that comes in kick off a new thread obviously this has an upper bound you can't create an infinite number of threads all right so we have our implementation uh but obviously nothing is running this implementation this is just an interface that we created there's no contract anywhere here that indicates that spring will know what to do with it so i'm going to create a simple bean to run it okay so we're going to say um application runner process it i'll inject the implementation sync dot start and port equals let's say 808 so you know i will say one run on port and the bytes will be here and we'll just say there are bytes dot length bytes okay there we go there's our basic uh loop so our basic business logic we're just injecting the implementation and uh we're using it and so right now we've only got one so that only could it could resolve only to this particular one and actually you know this could be a service i suppose um okay so that's the first thing that we want to do um let's see if that works okay so it's running now i want to exercise it by sending some data so we'll say nc localhost 8008 and we're just going to read in the data from this file that i have on my desktop called content now in order before we do that let's take a quick look at the file and in particular you can see that there's 15 713 bytes okay so let's run this and there we go there's 15 713 bytes so we have something that is successfully able to capture all the bytes write them out to file and then hand them back to our our consumer this is using traditional blocking io and again what we mean by blocking is that whenever we do anything here we can't move to the next line until it completes and in this case we're executing on the main thread of execution what that means is that we can only handle one incoming request at a time i could create threads and that way i can handle as many requests as i have threads but even there within that thread i can't move forward until these operations things like in dot read and and so on complete they're going to block the thread of execution okay let's try again let's suppose a party comes in and you see them and take their order and then another parties and you see them there's no contention here um but there could be now you're able to handle one and then handle the other until you're able to satisfy both tables at the same time but what if both come in at the same time well here it's still not necessarily a problem because you can give one table their menus that disappear then come back and take the order and then meanwhile the other tables ready give them their menus and so on uh and you can keep doing this all night long until the restaurant uh closes at the end of night and everybody should be happy you're one waiter but you're able to ping pong between the two different parties uh and uh handle them as needed you spend time actively handling requests uh and this is sort of like being on the cpu you're actively handling things they're not just sitting there waiting having a smoke break in the back office this is kind of like the event loop pattern right you're constantly keeping the cpu busy by ping-ponging across different uh requests there's a reason why a good waiter can handle maybe 10 tables at a given restaurant right um and and if you want to handle 20 then you just hire another waiter this is kind of like the event loop pattern it's a great response to the c10k problem as well which wikipedia sums up as a problem of concurrent connections it's it's uh the idea that connections are and speed or related is not entirely true right the question here is can we handle 10 000 concurrent connections not requests per second right so you can have a slow service that still handles 10 000 concurrent requests thanks to efficient scheduling um you could have many threads and each of when each of them operates in event loop and ideally you'll keep your service saturated you don't want to log into your server and find that you've got this very expensive beefy machine but most of the cpu is idle because it's just waiting for io to happen right the event loop pattern implements the reactor pattern the pattern from which of course project reactor which we'll draw a lot on uh in all things reactive draws its name the benefit of this approach is that you can handle more requests not that any particular requests are going to be faster um if our hypothetical waiter were sat at the table listening attentively for instruction there'd be no delay at all however nobody else would be at service so we want we don't mind a little delay that's context switching uh in the name of availability okay we obviously want our infrastructure to be well used and to be able to withstand the daily traffic as well it's a good problem to have to imagine that someday will have more traffic so let's look at java and io java nioh is a different branch of the of java that was introduced in java 1.4 and that supports uh asynchronous and non-blocking io there's there's a difference here for now we're going to focus on just non-blocking i o what we mean by that is that you are never going to wait for bytes to be available all right now let's turn to nio okay i'm going to put the previous implementation under a profile i'll just call it i o so you can still run this example it's just that you have to say string that profiles that active equals io let's now build an nio implementation so create a new service class and io network file sync and it will implement network file sync as well it in turn is going to use non-blocking io nio can support both blocking and non-blocking input and output we've already looked at blocking input and output when we ask for something to happen we don't get the result until it's ready but we can't move on in the meantime with non-blocking i o all the operations that we make uh will either return immediately with the data that we've asked or some sort of error code or status code telling us that they couldn't give us the data that we asked for but you'll never sit there waiting for the data to be produced to manifest so we're never ever in a situation where we don't know when this method will return it'll return as fast as a method can return instantly you know typically zero of one right uh you don't want like log time anything like that you want key you know in and out access just like a cache and so with non-blocking io you you have that assurance that it's going to return in a finite predictable bounded time for everything all right let's use uh java nio to implement this new version java nio is very similar to java i o the names are basically the same the concepts are the same you've got a server socket thing that accepts sockets and then does input output with it the names are slightly different you'll see channels mentioned a lot unlike java io where you have an input stream for input and output streams for output you've got channels which are bi-directional you can write and read or read and write from both okay so let's say var socket server socket channel equals new equals server socket channel.open all right and we want this to be a non-blocking surface socket so we'll say uh it's false for that we'll do a sneaky throw as well as well to make sure that it doesn't ever um if it throws an exception we don't have to worry about it we're going to say server socket channel dot bind i'm going to give it an address so a new inet stock address port all right so now we're actually we have a network service on a port somewhere but nothing is happening right so we need to create we need to register an interest in accepting new sockets right so this is another thing that's kind of interesting is you have to this is another thing that's very interesting compared to java io you need to tell the run time what operations you would like to do and to register an interest in being able to do that because it won't let you just start writing if it if the thing that you're writing to can't handle it yet so it'll schedule you it'll say okay i'll call you back i'll tell you when i can accept the right or when i can do a read and not block right if i can do it right because my network buffers are empty and i can just send data and it'll go out on the network as soon as i'm done with it and i can do that instantaneously then i'll schedule you for rights if i can give you a if i can give you a bite array full of bytes instantly without blocking i'll schedule you for reading right um there's another operation you can do here of course which is accepting incoming requests this is one of those things where usually it's just the service login that does this right the service socket accepts new requests from which you get just a regular socket so we need to create a thing that's going to monitor all these different channels for us and we can that we can then ask for availability so we're going to create a selector and if this if you've ever used the select function in posix then this is pretty familiar if you ever use something like e-poller or aio the idea is the same it's a it's a way given a number of file descriptors to get a status code that tells you that something can be read or written or whatever okay so i'm going to say var selector equal selector dot open and we're going to register the selector and uh selection key dot op accept okay so i'm i'm saying i would like for this selector to tell me for all the channels under its watch when one of them is ready to accept or to do a socket exception okay and of course it's a server socket channel so it's probably the only thing that we want to accept requests uh the rest of them we're just gonna use to read write from okay now we'll just busy loop as well we can do while true another thing we could have done and you know this is a pretty common thread is to say while not is interrupted right uh but they're both the results is the same it's effectively well true right while true if you hit control c will just it's the same both things will result in the jv i'm not working okay okay so um let's say so select that select notice that i just did a blocking operation this actually returns values but we don't care about the values right it tells me how many keys are available that i can then work with but this will block right this is a blocking operation this is this will block this is a blocking operation you could do selector dot select now right or now and this will tell you all the things that are available right now um uh for processing and you could use that if you wanted but i really i'm okay in this case with just blocking so selector done select okay good and once that's finished then because remember by the way if it's blocking there's nothing to do there's nothing on the server so there's no reason having the while loop do anything i can just sit there and wait there's no reason to busy loop it's inefficient right so but if there is something then i want to start doing non-blocking io because i want to make sure i'm not wasting resources while they're being engaged and satisfying the the requests that are coming in okay so um so then i want to get all the keys now keys are basically little types that tell us when something is possible what operation is possible and on what channel it's possible okay so we can use that we can constantly iterate over all these different um uh you know channels we can use those keys to figure out what is possible and not where on which channel is possible so we'll say selector dot dot selected keys and now we're going to iterate over each key so var i t equals selection keys dot iterator and i t dot has next okay and var key equals it dot next and then we're going to remove it from the collection we don't this key we don't want to see it again right it shouldn't get reprocessed we want to make sure it only gets delivered to us one time okay so we have the key we're gonna remove it from our we don't want it to be redelivered so we're gonna remove it and then now we're gonna go through the different states and kind of see in what state they are right so if um key dot is acceptable then this must be our service socket right and indeed this will be the very first branch of our loop uh that will be true right so if it's true then we want to get a socket we'll say service like a channel that accept um and that'll return instantly and then i want to get data about this request okay um i'm going to store data about this request so when a socket comes in remember i'm going to get callbacks i'm going to go through this loop many many times and only when a socket when a channel is ready to be used for reading and writing only then will i actually do something but that means that i'll you know i might be like several seconds down the line i might be a minute later right it might i don't know when that will happen and uh and because of that i can't afford to just keep state in this method because i might be in another thread i might be somewhere else you just don't know so what we want is some way to get a reminder of what we're trying to do with a particular socket we want some state we want context associated with a given socket and so there's this concept in java and io of an attachment an attachment is just a it's an object that you can it's an arbitrary object any object you can put a map you can put your own custom class you can put whatever but it gets passed around so whenever you are doing an operation you can ask for the attachment for that operation you can use that to to to say oh okay now i'm processing this request for for josh versus dr cyr versus maduro whatever right okay so i'm going to read uh the data and then i'm going to create an attachment okay so i'll say attachment and here i need something don't i need a a type that i can use to pass around but this is of course the perfect use case uh for java records aren't they so we're going to create a type here called weed attachment and we'll store some uh what do we do we want to say store some data in a byte array output stream so we're going to create a record which i think is a perfect use for this uh so i'm going to call this a read attachment basically we're going to keep an array of the the byte buffers that we read so copy on right arraylist bytebuffer but buffers okay so it's just an attachment just a short just to stash things across the different reads until we're done and then we'll accumulate all the resulting byte buffers into we'll concatenate them all basically into one big array and then deliver that in in total to the uh to the consumer okay so we have this attachment so we'll say new read attachment new copy and write arraylist good and we want to configure this socket to be non-blocking as well right and then we'll say socket.register on the same selector so it's shared now but this time i'm looking to read data and i'm passing along this attachment so that it gets handed back to me you know it's already been initialized but i can keep adding to that correct that arraylist next time now of course i could just for my attachment i could just pass along the arraylist i don't need to necessarily have the record but it's nice to have that record you can stash things associated with the context of this particular request maybe the user id or some payload or whatever okay so there's my first branch so it's going to read it's got it's now been registered i'm registering uh interested reading so the next time i come to this loop i can say if key is readable right and that might be the case it might be that this is readable now so i'll say that i want to get the attachment again and it's the read attachment from the key attachment okay there's my attachment and i want to get a thousand bytes or maybe just 102 4 bytes all right i'm going to create a byte buffer this is a kind of like a byte array but it's a java and i o type and it will have one or two four bytes length the channel is a socket channel okay and it'll be a key dot channel it'll be key that channel now i'm going to read the data and again it's negative 1 just like last time and i'll say if read channel dot read bb greater than or equal to zero then i'll get the attachment get the buffers and i'll add the bite buffer so i'll say add bb okay so i'm basically saying if the read operation returns more than um zero bytes then take the byte buffer in which those bytes live and append them to the collection of byte buffers that i've got there okay and finally once i've done that i want to register interest in reading again right so who knows if i have more to do so i'll say channel.register selector um selection key dot ops read and i'll pass in the very same attachment so we might come back this way through the loop yet again all right okay so down here however if read should equal negative one well here i wanna i'm done right we've got all the data so if that's the case then i'm gonna send the data to our bytes handler right so i'll say by handler dot accept okay um and uh i want to accept it but in order to just accept it i need to arrive at all the bytes i need to get all the bytes in one place so i'll say try var baos new byte array output stream remember a binary output stream is an in memory output stream and it's a great way to accumulate bytes um so i'll say okay create the new battery output stream and i'll say m4 bar bb buffers right so buffers is the attachment dot buffers and each byte buffer okay so for each one of those i want to read the data i'll say each bytebuffer.flip right now those byte buffers are primed so you can write to them if you want to read them you have to flip uh the the precision so it goes back to the beginning and that you read from them as though you're reading from the first time i want to get the bytes new byte b b or each bytebuffer.limit and and then what now i want to read that i want to read the data um from the bite buffer so i'll say get the bytes and uh transplant them basically transfer them from the bite buffer into the bite array and then the byte array well we can write that out we can say um baos dot right okay so bytes good okay it seems a little twisted but you know such as life on the you know in il world okay so we have now accumulated all the bytes into the byte array output stream okay so now we've got um all the writes to the byte array output stream finished now i want to collect all the bytes so uh response equals baos dot 2 byte array and i want to send that to our bytes handler like so accept response and then finally what i want to do is i want to um dispose of the channel i'm done with it i've already satisfied the request so i'll say to please close okay so let's go ahead and run this now keep in mind i've already uh commented out it in effect the existing implementation it's under a profile you have to activate that spring profile for it to work so the only implementation that we have in the application context is this nio network file sync so um this should still work let's go ahead and run this okay it's up and running and now we can send another request and there's our one five seven one three bytes just as before so we've looked at a very simple example using nio it worked it wasn't pretty but it does work right uh and this is you know we've got two classes at least um you know i haven't done anything smart here i haven't done any you know parts this is not a very interesting protocol it's not even an echo server i'm not even responding with the same payload back i'm just taking the data in and logging it basically um but yeah the code is line 47 all the way down to 104 so call that 60 something lines almost and um and that doesn't even include the attachment so yeah basically 60 lines for that compared to the traditional blocking one which you know tons of space so line 128 to 108 so 20 lines of code you know 22 lines right it's a there's a difference there right there's a significant difference in readability ease of understanding etc uh and yet this is the better code this is the code you want in production if you can trust it and that's i think part of the problem is that i don't trust it so this stuff is it's hard right it's hard even in the simple cases it can be downright mind-bending in the hard cases in the corner cases were java a city nio is the neighborhood i would never dare venture into after dark right um so let's talk about something else that makes it a little easier nedi is a project that was created by trust trusted lee in 2001 or something like that it's become a de facto standard it's a tool for building fast robust approachable services and it makes writing correct code easier and more consistent and if you don't believe me just take a look at the adapters right there's a huge list including apple alibaba apache spark bachelor couch base ebay fit base firebase red hat splunk sprint uber squarespace spotify zynga vmware and of course the spring team and all of our reactive support uses neti neti simplifies writing non-blocking uh base network services dramatically it handles things like the state machine uh that's required for message framing and handles writing uh code that can scale and that doesn't block very elegantly it's amazing and i cannot wait for you to try it out um once i don't want you to keep using it because again you shouldn't be working at that level of abstraction you should be thinking about it in terms of the higher order business logic in your application so you should be thinking about it in terms of something like your domain types and for that reactive programming is invaluable it gives you a way to write code in such a way that the smart underlying scheduler of something like java and io or neti uh can keep the cpu busy while also making it very clean what you're trying to do you're not dealing with the world in terms of pipes and bite buffers and all that right you can just deal with data that comes from something and goes to something and this because you've got the single abstraction also supports those other two goals ease of composition and robustness okay so we've looked at nio and we've looked at traditional io let's create another profile here called nioh and now we've effectively got no implementations now we can turn to our our next implementation so this one will use neti okay so we'll say that this is also a service class nitty uh network file sync class neti network file sync implements network file sync [Music] implement that and we have already some uh you know we know what we got to do we have to start a service that runs on that particular port of ours um so let's see here this will be sneaky throws and we're going to create a event loop group so um nio event loop group equals new nio event loop group all right now we're going to create a handler i'm going to come back to this in a second but for now this is a server handler is it i think whatever we'll come back to that in a second okay um and uh and then let's set up the basic skeleton of the application so try finally and uh we want to do what we want to create a server bootstrap and this is the nice thing about neti is that you just have to know this one incantation and it's the same for every network app you write and it's it's you can see the obvious opportunities for uh improving it and so on so you know it's just there's like little slots that you can plug in code i love that about this the channel that we want to use is the nio server socket channel um i'm going to send some options so channel option there's a lot of good options here that you should definitely spend a few decades memorizing and learning but for our purposes we're just going to specify how much data can be kept on the socket in memory uh before being purged okay then we're going to specify the handler and this is just going to be a logging handler um okay so logging handler log level info and then the child handler and here's where we can actually initialize things channel initializer and we're going to work with our socket channel implementation implement those methods okay so what we're doing here with nettie is we've got this pipeline yeah and this pipeline you can configure to do whatever you want basically it's a message in message out you can have a bunch of fill they're called handlers but they're they're basically filters they get a chance to act on the request and then act on the response that gets created and they can each contribute or punt on that process on that that contribution so here um i want to get the channel pipeline uh from socket channel dot pipeline and i want to configure my server handler right so that's this business up here server handler okay we're going to come back to that in a second it's null for the moment okay and um we're going to kick it off so future so channel future equals server bootstrap.bind to the port and then we want to sync okay so i'm blocking on that and then channel future.channel dot close future dot sync okay and to be honest with you i don't really understand what this stuff does i've just kind of always written it that way i assume it's just waiting for us to be able to bind to a socket that doesn't need to be non-black and we the process we need to bind to a socket that's fair right we can do nothing in the the rest of the program means nothing if we aren't bound to a socket so it's fair that that one little thing be blocking um but it's important that we don't keep the system running if there's no reason and if something for for whatever reason the system needs to shut down we want to shut down the event loop group so we're going to call shutdown gracefully okay okay let's talk about that handler that handlers were our business logic links and there's a number of different handlers that come out of the box but we want to create our own here so i'm going to say neti network file sync server handler implements channel inbound handler adapter and a contract fairly straightforward we want to implement the channel read callback you can see we get just very easy clean convenient callbacks that we can use uh to process the data we don't have to worry about you know writing a loop and should be concurrent or not or whatever just just go with what they tell you right okay so we have a channel handler a channel handler context and a message that message could be anything so what we want to do so what we want to do is we want to read all the data in from the the request um and then accumulate it in our byte array output stream so first things first i'm going to create a atomic reference to the byte array output stream okay uh reference new atomic reference good so that'll be passed in in the constructor here we'll say that and i'm going to take the data i'll say if the incoming message is an instance of an abstract buff then i'll give it a you know i can use smart casting so now i have a reference to the down casted type i don't have to do the downcast anymore myself and then i'm gonna read the data just like i would in java nio basically so i'll say var bytes equals new byte and uh here i'm gonna do buffer.readablebytes readable okay and no i don't want to say goodbye i want to say bites no bye it's okay good and uh with that i want to read the data so read bytes and again you know fairly straightforward and i want to read the i want to get the reference uh to the output stream i want to write so bytes okay not bad good so if that works great the next thing we want to do is when the read is complete channel read complete then uh i want to make make sure we we actually you know take the bytes that we've accumulated and write them out okay so here i'll say uh var baos equals this dot reference dot get um if null does not equal bos okay try we want to get the data from the bytes so var bytes equals bos.2 byte array and if bytes.length does not equal zero right then um we want to send them out don't we so we can say uh we're going to have the consumer here as well so we need the consumer private final consumer of bite bites okay there's that and we say bytes no i say this dot bytes dot accept bytes goody there's our writer we've written the data out um and of course we might have more use for this so this dot reference dot set new byte array output stream we want to like shut down things if they're if we're done with them okay so um we'll do the if and all that stuff instead of a try catch so try catch exception e and uh we don't actually care about catch we want finally that's what i want i want to be able to guarantee that certain things get disposed of no matter what so context dot flush and i want to close the about stream by array output stream okay good so there's a cleanup we've reset the reference to the battery output stream as well um so now the only thing is um to to actually plug this in we want this to be an empty binary output stream we want to initialize it with a valid reference right it'll get it reset uh the reason we're using an atomic reference is because that's thread safe so i can i could just do synchronized or whatever but this is it's fine right this will this i can do this atomically i can get a reference and then comparably send it or whatever and the very least i know that if i'm reading and writing in the same thread i won't i won't have any issues um okay so let's actually go ahead and plug this thing back in to our code upstairs here so where's my server equals new one of these right and again we can pass in the bytes handler and we can use this in the implementation right here okay so i'm using the channel initializer i'm using the server bootstrap the this is pretty mundane stuff this is actually like unless you have something to say about which options to use and which particular channel type to use and which event loop and you might by the way like i said there are some pluggable bits here that there's a lot of uh there's actually a lot to talk about when we talk about event groups for example you could use one supporting epoll or eu rings or whatever and there's some stuff that they do in the nitty product that uses native code that only works on linux that makes the experience on linux just second to none it's just amazing so once you get it right that's it you don't need to worry about it really the business logic the part where we distinguish this many projects from every other one that's ever been written is um in the the handler adapter right this is an inbound handler adapter but there's outbound ones as well okay so let's go ahead and try it right let's go ahead and run this one okay so it's up and running um let's go ahead and send some data and there we are one five seven three bytes so we have used regular traditional blocking out non-blocking io and neti now these days if i were to build a network service or anything like that i would start with neti uh or the very least non-blocking io right neti is uh really actually i think the better choice because um it does more than just regular nio it's not like it's just a different way of structuring a program so as to take advantage of uh nio is actually actually have support for stuff that just isn't in the jdk and really should be alright my friends i hope you got something out of this as always thanks for watching and we'll we'll see you next time
Info
Channel: SpringDeveloper
Views: 19,702
Rating: undefined out of 5
Keywords: Web Development (Interest), spring, pivotal, Web Application (Industry) Web Application Framework (Software Genre), Java (Programming Language), Spring Framework, Software Developer (Project Role), Java (Software), Weblogic, IBM WebSphere Application Server (Software), IBM WebSphere (Software), WildFly (Software), JBoss (Venture Funded Company), cloud foundry, spring boot, spring cloud
Id: eKfNoT07k_s
Channel Id: undefined
Length: 47min 4sec (2824 seconds)
Published: Wed Feb 09 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.