Jersey and Netty Together Again For The First Time Once More

I had some time and put together a Jersey-and-Netty integration that I think is pretty interesting.

Its Github repository is here: https://github.com/microbean/microbean-jersey-netty.  Its website is here: https://microbean.github.io/microbean-jersey-netty/.

It lets you run Jersey as a Java SE application using Netty to front it.  It supports HTTP and HTTP/2, including upgrades.

Jersey itself ships with a Netty integration, but it seems to have some problems and parts of it are designated by its author as very experimental.  I wanted to see if I could do a decent integration myself, both to learn more about Netty and to solve a real problem that I’ve had.

The main challenge with Netty is to ensure that its event loop is never blocked.  But the very nature of JAX-RS, with its InputStreams supplying inbound payloads, means that some blocking in general is necessary, so immediately you’re talking about offloading that blocking onto extra threads or executors to free up the event loop, and therefore coordination of IO activity between the Jersey side of the house and the Netty side of the house.

This in itself is not terribly difficult on the face of it and can be addressed in many different ways.  The Jersey-supplied integration accomplishes this by passing InputStreams to Jersey using blocking queues.  This is fine, but now the integration author has to deal with queue capacity, and rejecting submissions, and so forth.  As you might expect there is at least one issue around this that turns out to be somewhat severe (apparently).  This also involves creating a fair number of objects.

But of course Netty already has a really nice system of queues that it uses to do this same sort of thing, and you can easily get access to it: it’s the event loop itself, which lets you submit things to it.

Netty also has its ByteBuf construct, which is a better cheaper faster ByteBufferByteBufs are sort of Netty’s “coin of the realm”.  Netty goes to extraordinary lengths to ensure a minimum of object allocations and garbage generation occur when you’re working with ByteBufs, so they seem like a good thing to center any integration strategy around.  They are not thread-safe, but if you mutate them only on the event loop, you’re good.

So the general approach I take is: instead of making extra queues to shuttle byte arrays or other Java-objects-wrapping-byte-arrays back and forth between Jersey land and Netty land, I use a CompositeByteBuf that gets the ByteBuf messages that Netty supplies in its HTTP message constructs added to it as they come in on the Netty event loop, and use the Netty event loop task queue to ensure that all ByteBuf operations of any kind always take place on the event loop.

This means that I can take advantage of everything Netty gives me under the covers in terms of memory efficiency and potential transparent usage of off-heap buffers and such, while also gleefully punting any task queue saturation issues to Netty itself, which already has customizable strategies for dealing with them.  A lower chance of bugs for you, since Netty has to deal with this sort of problem all day every day, and a lower chance of bugs for me, since it is their code, not mine, doing this coordination.  Win-win!

On the outbound side, I take advantage of Netty’s ChunkedWriteHandler, which, contrary to how it might appear at first, has nothing to do with Transfer-Encoding: chunked.  Instead, it is a nice little handler that deals with user-supplied-but-Netty-managed hunks of arbitrarily-typed data, writing them when their contents are available, and doing other things when it can’t.  The upshot: your Jersey OutputStreams are chunked up and enqueued on the event loop using a single ByteBuf implementation that is optimized for IO as data is written to them.

The net effect is a nice little as-nonblocking-as-JAX-RS-can-get tango that Netty and Jersey perform together, coordinated by Netty’s and Jersey’s own constructs.

microBean™ Jersey Netty has extensive Javadocs and is available on Maven Central.

Advertisements

A CDI Primer: Part 4

In the previous post, we learned that the only Contextuals that matter, really, are Beans, and we learned a little bit about injection points and loosely how they’re filled.

In this post we’ll look at how CDI actually discovers things, and how it normalizes them into Bean implementations, and how it marries them with Context implementations to figure out what their lifecycles are going to be.

The Container Lifecycle

CDI has a very well-specified lifecycle.  There is a general startup phase during which all the raw materials in the world are discovered, arranged and pared down to form a network of Bean implementations that produce and consume each other.  Once that startup phase has completed, the actual application—whatever it might be, that makes use of all these producers and consumers—starts, and runs, and does its thing.  Then there is a shutdown free-for-all where all Bean implementations can, indirectly, get a chance to clean up, and that’s all there is to it.

But what are you, the end-user, the ordinary developer, supposed to do with all this?  In your hand, you have a class that has some injection points in it (fields or methods annotated with Inject), and you want them filled.  What does this have to do with Bean implementations?  After all, your class doesn’t implement Bean.  We’ll see how internally, in a way, it sort of does.

Discovering Things

As part of the startup phase, CDI performs type discovery and bean discovery.

Type discovery is a fancy name for taking stock of what classes exist on the classpath.  Plugins, called portable extensions, can affect this; that’s a subject for another day.  For now, know that CDI will scan the classpath for particular classes and will add them to a set of such classes that represents its type world.

Once types have been discovered, CDI performs bean discovery, where some of those types it found lying around are normalized into Bean implementations internally.

It’s important to realize what’s going on here.  For the typical developer scenario, most classes that are discovered are turned into producers.  This can be a little counterintuitive—I don’t know about you, but that’s not usually what I think of when I have a class in my hand named with a noun, like Person or Customer.  Really?  Customer is a producer?  A producer of what?  Well, of instances of itself, it turns out.  Which of course we all actually know, because it has a constructor.

Managed Beans

So consider our ongoing stupid example of a Backpack class, with a simple zero-argument constructor, annotated with Singleton, and a Gorp-typed field annotated with Inject.  Let’s say that CDI discovers it.  Internally during bean discovery CDI creates a Bean to represent it:

A Bean implementation built internally like this is called a managed bean, and the class itself is frequently called a managed bean as well.

It’s important to realize that for a given managed bean one of its bean types and its bean class are always identical.

Producer Methods

Another very common kind of bean is a producer method.  In this case, CDI has done its type discovery, and has found a class called CandyShop also annotated with Singleton (I’m picking Singleton because it is a scope that everyone is intuitively familiar with.)  Let’s say this class has a method in it declared like this:

@Produces
@Singleton
public Candy produceCandy() {
  return new Candy();
}

This time, CDI will create a Bean internally for CandyShop that looks a lot like the one above, namely:

But then it will also create a Bean internally that represents the producer method:

Do you see that the bean class here is CandyShop but the getTypes() method returns a Set of bean types that includes Candy.class, not CandyShop.class?  The takeaway here is that usually when you’re considering a true CDI bean you are, as a normal developer, interested in one of its bean types, not its bean class.  In other words, you’re interested in (in this example) Candy.class, and normally not so interested in the fact that the producer method that creates its instances happens to be housed in a class called CandyShop.  The terminology in the documentation certainly does its best to make this about as clear as mud.

Producer Fields

Just as you can have a producer method whose bean class is one thing while its bean types are another, you can have a producer field.  Let’s say our CandyShop class from the example above also has a field in it declared like this:

@Produces
@Singleton
private PeanutButter peanutButter;

Once again, CDI will create a Bean for CandyShop, just as it did before, and here it will also create another Bean:

In practice, producer fields are comparatively rare.  They exist primarily to bridge the worlds of Java EE, where you might have a field that is annotated with Resource (so is being set by some kind of JNDI-aware machinery), and CDI where you can have the very same field annotated with Produces.  This lets CDI set up a Bean implementation under the covers that creates instances from Java EE-land without any other aspects of the CDI ecosystem really being aware that Java EE is even in the picture.

Decorators and Interceptors

Two other primary Bean implementations are Decorators and Interceptors.  I’m not going to talk about them because although it may look like it by this point I’m not writing a book.  Suffice it to say they are represented in the CDI ecosystem by Beans, and so are inherently producers of things, which can also be counterintuitive.

Custom Beans

Finally, without digging deep into portable extensions, we can at least say that portable extensions have a variety of ways to cause a Bean implementation to be created by hand at container startup time.  When Beans are added into the system this way, the portable extension has absolute full control over them.

Putting It Together

The biggest takeaway here is that everything in CDI is a Bean.  In the documentation, almost everything is a little-b bean.  A bean, represented by a Bean, is fundamentally a producer of something.  There are recipes that we’ve just enumerated that translate ordinary Java constructs into Bean implementations when bean discovery is performed: a creator and a destroyer (Contextual) together with bean types and a scope (BeanAttributes), a hosting bean class and a set of injection points (Bean).

There’s another thing that falls out of this.  Bean is a parameterized type: you have a Bean<T>.  The <T> is, however, always usage-specific, because it comes by way of Contextual, whose usage of its type parameter is the return type from its create method.  That is, <T> represents one of a Bean‘s bean types—one of the kinds of things it can make—not its bean class—the class hosting the producer method or constructor.

Consider a Bean<Person>.  Because a Bean<Person> is a Contextual<Person>, it follows that you can call its create method and get a Person back.  But it does not follow that calling its getBeanClass() method will return Person.class!  Perhaps the Bean<Person> you are looking at represents a producer method, or a producer field, for example.

Finally

So finally we can see how CDI makes @Inject work, which was what we set out to do in part 0:

  • CDI discovers types
  • For each type found during type discovery, CDI creates a Bean to represent it, or at least tries to
  • For each producer method and producer field (and other cases), CDI creates another Bean to represent it
  • For every InjectionPoint found in this pile of Beans, CDI performs typesafe resolution to see what Beans have bean types that “match” the InjectionPoint‘s type
  • Assuming that all slots get matched up to producers, whenever CDI needs to obtain an instance of something, it does so through the right Context which is in the business of handing out contextual instances
  • CDI can find the right Context by checking out the scope available from each Bean
  • Ultimately the Context, when asked to produce an instance of something, will call through to a Bean‘s create method

I’ve deliberately left out qualifiers, which are extremely important, but are deserving of their own article later.

There’s much more to say about CDI, but I think I’ll stop there for now.

Thanks for reading this primer!