In the previous post, we learned about typesafe resolution (the process of matching producers (
Contextual implementations) with consumers) and where, exactly,
Contexts fit in.
We also learned that you can “label” a
Context with a scope, an annotation class standing in for the kind of lifecycle you want a
getScope method returns it to implement.
We also learned that in some unspecified way you can apply the same annotation to a
The net result was that we sketched out our first hazy picture of how a
Gorp-typed slot in a consumer (
Backpack) might receive a singleton
Gorp produced by a
Contextual implementation whose type parameter is
Gorp. (If you’re wondering what all this is about, I heartily recommend you start at the beginning with part 0.)
Nevertheless, as we did this, we waved our hands furiously over certain details. Specifically, while describing typesafe resolution, we made many references to CDI linking together producers and consumers without describing exactly how this happens, and we spoke a lot about
Contextuals, but never really covered what they are, exactly. We’ll look into that in some detail in this article.
Throughout this series of articles, we’ve talked about
Contextuals as being CDI’s implementation of producers in the dependency injection mindset (which we described in part 0).
Contextuals produce contextual instances. And contextual instances are what
Contexts supply to fill
@Inject-annotated slots. You get all that by this point I’m sure. But we haven’t discussed what
Strictly speaking, of course, a
Contextual implementation only has to implement the
destroy methods. Great.
Let’s say you write a two-method-long class that does that. Now what? Nothing, that’s what.
It turns out that CDI doesn’t really give you an “in” using this interface: you can compile a
Contextual implementation, stick it somewhere, and it will happily sit there until the end of time waiting to be discovered and used, which will never happen.
But a subclass (subinterface) of
Bean, and we’ve all heard that term before.
As it turns out, the only direct subtype of
Contextual that CDI inherently knows about is
So in most cases where I’ve written about
Contextuals, you can substitute
Beans, and be just fine. A
Bean “is a”
Contextual, and CDI deals primarily in
Beans. (There are mechanisms throughout CDI for getting
Bean implementations “into” the system, but none for directly getting “raw”
Contextuals that are not
Beans into the system. We’ll cover this interesting structural fiesta below.)
So if that’s all true, why have I been talking about
Contextuals all this time, and not
Contextual is the part of the
Bean interface that deals with production (it consists solely of
destroy methods, after all). The rest of the
Bean interface, as we’ll see, deals with other things.
We’ve backed into this series of articles from the production end: we have been shining a light on exactly how “CDI makes
@Inject work”. So production has been front and center, and that’s what
Contextuals give you.
Now with the production facet of
Beans under our belts, we can turn our attention to the other facets.
Let’s start with one such facet—the
CDI was defined originally back in an era where inheritance was used a lot, and composition…not so much. As a result some compositional concerns in CDI are expressed—conveniently but a little opaquely—in terms of inheritance. This is true of the trio formed by
Contextual. Luckily we can tease them apart.
Here is a class diagram showing that
Bean inherits from both
This is certainly obviously how the interfaces are actually structured, but it hides the more important fact that each of the collections of methods defined by each interface is really a facet of the same underlying object. With only a few rare exceptions, CDI assumes that the object “behind the curtain” of a
Contextual interface, for example, will also implement
That is, a
Bean “is a”
Contextual, sure, but really a
Bean “has a”
Contextual facet: it has a facet that deals with production. We’ve covered
Bean also “is a”
BeanAttributes, but really, again,
Bean “has a”
BeanAttributes facet: it has a facet that deals only with discovery- and typesafe resolution-related concerns. (You’ll note in particular that the
T type parameter used by
destroy is not used anywhere in the
BeanAttributes is a facet of a
Bean that is concerned with its overall place in the CDI world. We’ll look at its methods selectively and carefully, ignoring those that don’t yet make any sense.
(And finally the collection of methods defined by the
Bean interface itself is a facet of a
Bean implementation that is concerned with its role as a consumer. We’ll cover this below.)
BeanAttributes method of interest we’ll consider is
getScope(), which returns an annotation class representing a scope.
Here we can finally see explicitly what we handwaved over in part 2: effectively in CDI, every
Contextual implementation is always also a
BeanAttributes implementation, so every
Contextual is capable of essentially reporting which
Context manages the lifecycle of its produced objects. See part 2 for more on this.
BeanAttributes that are producers (which is to say all of them, since in CDI’s ecosystem they’re all also effectively
Contextuals) still have a say in the lifecycle management of their produced objects, but they don’t actually have to implement that management themselves. Nice.
The next one is
getTypes(), which reports the
Types that a producer can make. Again, this method only makes sense when it is tacitly understood that
Contextual are always facets of the same underlying object, i.e. that all
BeanAttributes are always producers (
So, for example, if your
Contextual implementation gets instantiated with a type parameter value of
Object, then if your
Contextual implementation is also a
BeanAttributes implementation, as it should be, you can specify with this method exactly what subtypes of
create method produces.
CDI calls this method to gain insight into how to “fill” a consumer’s
@Inject-annotated slot with an appropriately-typed contextual instance. When trying to locate a suitable producer it can winnow the field by looking at the return value from this method and perform typesafe resolution using the results. (For more on typesafe resolution, see part 2.)
We’re going to table discussion of the other
BeanAttributes methods for now, as they’re really another layer on top of these fundamentals. We’ll come back to them in a later article.
Finally, the third facet of the
Bean interface consists of the methods it defines itself apart from those defined by
BeanAttributes. These methods are related to a producer’s also being a consumer.
On Consuming Producers, Producer Classes and
Back in part 0, we saw that there’s nothing wrong with a producer also being a consumer! Producers frequently need to consume raw materials to do their jobs.
We also saw that producers come in many abstract flavors: methods, fields and constructors.
A producer also needs a “host class” (a method, field or constructor has to “live in” a class, after all), and in part 0 we decided to call such host classes producer classes for want of a better term. (CDI calls them “bean classes” for reasons we are only now capable of understanding and which we’ll look into below.)
We’ve also talked throughout this article series about consumers and producers in terms of “slots” and “filling slots”. I have a
Backpack; it has an
Gorp-typed “slot”; CDI performs automatic wiring and “fills” the “slot” with a contextual instance of
Gorp sourced from the right
Context by way of a
Contextual implementation. (We went into some detail on this example in part 1.)
In the spirit of less handwaving, let’s call these slots what they’re actually called in CDI: injection points.
An injection point is a slot that can be filled with a contextual instance. It is a point at which CDI performs (dependency) injection. Injection points are represented in CDI by the appropriately-named interface
InjectionPoints have a type (and some other stuff, which we’ll cover another day).
Backpack consumer has a
Gorp-typed injection point.
While it does not explicitly use these terms, CDI says that a consumer simply is something with
InjectionPoints: it is a Thing With Slots That Have To Be Filled.
As we’ve seen, effectively all
Contextuals—all producers—are also
And we’ve seen that a producer can be a consumer.
And finally we’ve seen that a producer is housed in a producer class, which I’ve told you CDI calls a bean class.
So it should come as no surprise that this consumer facet of a
Bean is represented by two methods:
getInjectionPoints is pretty simple: it returns the set of “slots” that the producer needs values for in order to do its job. If the producer is a method, for example, then the injection points will represent the method’s parameters. If the producer is ultimately represented by a constructor, for a more complicated example, the injection points will represent possibly the constructor itself as well as any other
@Inject-annotated fields and methods in the class.
getBeanClass is a little trickier, and is in my experience one of the most misunderstood methods in all of CDI.
getBeanClass returns the producer class, not the class of the thing being produced.
That is, if you have a producer that is a method,
getBeanClass returns its “host class”—its declaring class—not the class of its return type. This will become important when we talk about CDI producer methods.
Similarly, if you have a producer that is a field,
getBeanClass returns its declaring class, not the class of the field. This will become important when we talk about CDI producer fields.
Finally, if you have a producer that is fundamentally a constructor, obviously a constructor makes instances of its own declaring class, so
getBeanClass will return the producer class, sure, but that will also be the class of the thing being constructed! This will become important when we talk about the most common kind of
Bean implementation found in CDI: the managed bean.
The most important things to take away from these CDI internals so far are:
- CDI has many ways of discovering things, but all producers and consumers from the dependency injection mindset can be represented in CDI as
Beanis fundamentally a producer of things, not the things produced, and a consumer only secondarily
Contextualimplementations normally found in a CDI application are
Automatic Wiring (Almost Entirely) Demystified
Our picture of how CDI accomplishes automatic wiring just got a little clearer. Every producer in the system now has a facility for reporting:
- what kinds of things it makes (
Contextthe things it makes should “belong” to (
- what it needs to do its job (
- what class it “lives in”, of which an instance might need to be produced for the producer to be invoked (
If CDI could find
Bean implementations in various flavors lying around, and then normalize them into true
Bean implementations in memory, it could match the
InjectionPoint of the
Bean implementation to hopefully the one
Bean implementation whose
getTypes method contains
Gorp.class in its return value. It could then locate the appropriate
Context implementation, by looking at the return value of the
getScope method, and could ask that
Gorp. It could then use the
InjectionPoint to set the actual
That is, of course, exactly what CDI does.
In the next post, we’ll get rid of the remaining handwavy bits and will look at how CDI:
- “normalizes” “
Beanimplementations in various flavors lying around” into “true
Beanimplementations in memory”
- “locate[s] the appropriate
- Uses “the
InjectionPointto set the actual
Thanks for reading along so far!
One thought on “A CDI Primer: Part 3”
Comments are closed.