More Thoughts on Configuration

This is a distillation of the thoughts I had in my previous piece on configuration.

The key insight for me was that application configuration takes place within a configuration value space with one or more dimensions or axes.

Next, these dimensions or axes are not hierarchical (after all, how could a dimension or axis be hierarchical?) and have nothing to do with the name of the configuration setting (other than that it can be considered to be one of the dimensions or axes).

Following on from all of that, an application asks for configuration values suitable for where it sits in multidimensional configuration space.  (I know this sounds like I’m five miles above the earth, but I really think this is important.)  I like to call this location its configuration coordinates.  There are always more coordinates than you think (something like locale often slips through the cracks!) but the total number is still probably under 20 or 10 for almost any application.  Many simple applications probably have somewhere around only two or three.

Next, a (flexible, well-written) application is typically unaware of most (if not all) of its own configuration coordinates.  (An application, in other words, from the standpoint of its running code, doesn’t “know” whether it’s in the test environment or not.)  But these coordinates are always, whether you know it or not, implicit in a semantic configuration request.

Next, configuration systems or sources are capable of supplying configuration values that are more or less specific along one or more of the configuration space axes.  A configuration system might supply a value that is maximally specific along the name axis (db.url), and minimally specific along (but suitable for) all possible other axes (environment, phase, region, etc.).  The holy grail is a value that is exactly suited for all of and exactly those configuration coordinates expressed by the application. Non-holy grails are configuration values that are still suitable by virtue of applying to a wide range of configuration coordinates.  This is the only place where hierarchies come into play: for any given configuration axis, a more-specific configuration value always trumps (I hate that word) a less-specific configuration value, but if a more-specific value does not exist, then the less-specific value is suitable.

This lets us start theorizing clumsily about a procedure where an application can ask for configuration values suitable for its configuration coordinates:

  • The application asks the configuration system for a value for the db.url configuration key and expects a String back.
  • The configuration system figures out what the application’s coordinates are, and re-expresses the request in terms of those coordinates.  db.url becomes a value for the—I don’t know—configurationKey axis.
  • The configuration system grabs all of its sources or subsystems or providers or whatever they should be called.
    • For each one, it asks it for a configuration value suitable for the supplied coordinates—and expects back, in return, not just the value, but also the coordinates for which it is explicitly suited.  Also of note: if the subsystem returns a value with no coordinates, then this value matched, but minimally specifically.  It’s suitable, but as a last resort.
    • Each subsystem responds appropriately.
  • The configuration system loops through the results.  Any result is presumed or enforced to be a match for at least the (hypothetical) configurationKey axis!  (That is, if I ask for foo, and I get a value for bar back, regardless of other coordinates, something went wrong.)
    • If there are no results, then there are no matches, and either null is returned or an error is thrown.
    • If there is exactly one result, then the value is returned.
    • If there is exactly one exact match, then the value is returned.
    • If there is more than one exact match, then an error is thrown.
    • If there are no exact matches:
      • The configuration system sorts the results in terms of specificity.  There are some details to work out here, but loosely and hazily and sketchily speaking if a set of configuration coordinates is expressed as a Map, then a Map with a bigger size (assuming the same universe of possible keys) is more specific, let’s say, than a Map with a smaller size. For example, {a=b, c=d} is a more specific set of coordinates (let’s say) than {a=b}.  The mere presence of a value indicates some kind of match, so it is possible for a configuration subsystem to return a value with, say, empty configuration coordinates.  This would indicate that the match is least specific.  So the specificity of a configuration value can be said, I think, to be equal to the number of configuration coordinates it reports as having matched on.  Tersely, the greater the specificity, the greater the Map‘s size.
      • If there is exactly one value with a given specificity, then it is returned—it is a suitable match.
      • If there is more than one value with the same specificity of coordinates, then this represents a misconfiguration and an error is thrown. For example, one subsystem might report that it has a value for {b=c, d=e} and another might report that it has a value for {d=e, f=g} when asked for a value suitable for {b=c, d=e, f=g}. Since configuration axes are not (by definition) hierarchical, this represents a misconfiguration.

OK, I think I’ll leave it there for now and chew on this over the weekend.

Thoughts on Configuration

So my previous pieces on CDI qualifiers has somehow led me into thinking very deeply about configuration, so here’s some stream-of-consciousness on the subject.

I’m aware that the de facto standard in this space is DeltaSpike’s configuration extension, and it works just fine as far as it goes.

I’ve also worked with Netflix’s Archaius, and way back in the day some of the Apache configuration libraries.

I’ve always been faintly bothered that at the heart of all these systems is (sometimes explicitly, sometimes just kind of present in “flavor”) a configuration hierarchy: you stack configurations and then different layers of the hierarchy supply different values.

But—and I might be wrong here—one thing that I’ve become more and more convinced of is that real world configuration is not a hierarchy.

We’ve already seen that there are some implicit qualifiers in a CDI application that end up being part of the configuration coordinates of the application.  That is, made up qualifiers like @Production (for environment or project stage), @Experimental (for phase or canary testing) and @UsWest (for something like region or datacenter) together with possibly other implicit qualifiers identify your application in configuration space.

Those things aren’t hierarchical. They’re cooperating aspects of the configuration space of the system.  Your configuration space may be one-dimensional (no test environment, no funky project stage, no data center things to worry about), or five- or sixteen-dimensional (your application can be deployed into all sorts of places within a huge configuration space).

Here’s how it seems to me that an interaction goes with such a configuration system:

My application: Hello, I would like a value for db.url please.
Configuration system: Certainly. I actually have several—some specific, some not.  Where are you?  Who are you?
My application: OK, well, I know that my configuration coordinates are phase=experimental, environment=production and region=uswest. Maybe that will help you.
Configuration system: Yes. Please hold. {Heads over to a remote corner of the office.} Hi, configuration source one?
Configuration source one: Yes?
Configuration system: Can you get me a value for db.url in the uswest region suitable for the production environment and the experimental phase?
Configuration source one: Let me see…no, but I could give you a value suitable for environment=production and phase=experimental…but I don’t have anything more specific than that (i.e. explicitly for region=uswest).  So the value I gave you might not be maximally specific, but that might be OK for you?
Configuration system: OK, that might work. Hang on. Configuration source two?
Configuration source two: Yeah, I heard you guys. I can give you a value for all three aspects!
Configuration system: Great! Thanks. Configuration source one, you’re off the hook.

The point here is not the witty dialogue, but the fact that the most specific value wins, not the value that has a particular place in a hierarchy.

You could conceive of a situation with that same dialogue above, but one configuration source can give you a value suitable for the region and phase, and another can give you a value suitable for the phase and environment, but none can give you a maximally specific value.  Which one of those (region, phase) is more primordial in a hierarchy?  Answer: neither!  They’re two axes of configuration.  This thought experiment means only that your configuration is basically underspecified, not that some arbitrary source in a hierarchy should win.  You might want to do different things in the case of an underspecified configuration.  Probably you actually want to notify someone that values aren’t set right.

Or, consider the same dialogue, but this time all you get is two out of three (region and environment, let’s say).  In that case, it might be perfectly reasonable to take the value offered (i.e. since there aren’t any conflicts (which is more primordial? region or environment?), you can just take the value knowing that it’s as specific as you’re going to get).  Maybe the db.url configuration value varies only along the environment and region axes and not along the phase axis.  That might be fine.

Anyway, where am I going with this?  I am not sure, but, again, it sounds like the germs of a configuration system that would plug nicely into CDI.  Stay tuned.

CDI Qualifiers are Values, Part 2

In a previous post I wrote that CDI qualifiers are values.

After some more thinking, there are two classes of CDI qualifiers: those that are values for implicit aspects (arbitrary examples: @Synchronous (a value for synchronicity), @Yellow (a value for color)), and rarer ones—those that are both aspects and values for those aspects (as an example, @Named is the aspect; the value of its value element is the qualification value).  There aren’t a lot of the latter, but they do exist.

If you want to write a producer method that works with the latter class of qualifiers, then you must look at the element of the qualifier that represents its value and see if it is meta-annotated with @Nonbinding or not.

If it is, then you are all set: you can just put the qualifier on your producer method, and now your producer method will be able to produce all possible values for that qualifier.

If it is not, then in order to write producer methods you must know in advance of all the members of the domain over which the qualifier’s value element can range.

Consider @Named as an example.  It is a qualifier that does not represent a value.  It represents an aspect.  Its value element holds the value that does the actual qualifying.  But its value element is not meta-annotated with @Nonbinding, so that means there’s no way to write one producer method that can produce items for injection points qualified with the @Named qualifier with arbitrary values.  That is, if your producer method is annotated with @Named(""), then the only injection point it will satisfy is one that is also  qualified with @Named("").  If it is annotated with @Named("fred"), then it will produce objects suitable only for injection points that are also annotated with @Named("fred").

So if you knew all the possible names your application could ever use, you could write a producer method for each of them, annotated appropriately (one annotated with @Named("fred"), one annotated with @Named("alice"), and so on).  Of course, if you knew that, you could just define your own “regular” qualifier annotations: @Fred, @Alice and so on, with an implicit aspect of name.

Whoa, you think; this is cumbersome and in some cases impossible!

Let’s invent a qualifier of the second class called @Labeled, with a single value element. It’s basically kind of like @Named, but with one important difference: on this qualifier we’ll add @Nonbinding to its value element.

Now all you have to do is mark your producer method with @Labeled, and you’ve effectively said, “I’ll take care of anything annotated with @Labeled, no matter what the requested value is.”  You’d better do that, because otherwise the container won’t start up.

This is of course very convenient and the way that a lot of configuration frameworks proceed.  Imagine a configuration framework backed by such a producer method: if someone asks for a String value to be injected at an injection point annotated with @Labeled("fred"), then it is easy for the producer method to go hunting for that value (however it does it) and return it.

There is a faint sense, though, in which this sort of thing doesn’t quite fit the CDI mindset. CDI “wants” you to know all your values in advance whenever possible: that’s why qualifiers are usually values themselves. Then the wiring is utterly explicit: the producer method annotated with @Yellow satisfies injection points also annotated with @Yellow. There is a way in which a producer method annotated with just @Labeled and an injection point annotated with @Labeled("fred") don’t quite plug into that way of thinking.  I have a hazy (possibly misguided) sense that there’s a better way of doing this sort of thing, but I don’t know what it is yet.

Anyway, all of this can serve as a helpful litmus test for clarifying your thinking and identifying which of your qualifiers need @Nonbinding on their elements and which do not.

CDI Qualifiers are Values

I had this realization today that I’m frankly not sure quite what to do with.

The realization, briefly put, is that CDI qualifiers are values for various unnamed aspects.  They are not those aspects themselves.

For example, the often-seen-in-CDI-examples qualifier @Synchronous is really a possible value for a hypothetical aspect called—I don’t know—synchronicity.  @Yellow is really a value for a hypothetical aspect called, presumably, color.  And yet we’re always left to infer what the aspect is from the qualifier itself (representing a possible value for that unnamed aspect).

We do this in English too: if you say “get me my yellow coat,” I don’t have to ask you about what aspect for which yellow serves as a value.  But that’s what’s going on.

This also led me to realize that, seen through a certain lens, there are other implicit qualifiers that are present everywhere, in an abstract sense (not actually in code).  For example, if I run my CDI application in a test environment, then there is this abstract sense in which all of my injection points (and their corresponding beans or producer methods) are semantically qualified with something like @Test, where @Test is a possible value for a hypothetical environment aspect.

What other aspects are there?  Well, there’s environment, I guess, and project stage, maybe, and data center ID, I guess, and region, and phase of the moon…and all of the other things that go into describing my application’s effective coordinates, all of which affect, potentially, what sorts of things are injected.

For non-configuration injection points, when you inject a Frobnicator, there’s only one choice (perhaps disambiguated from a set of alternatives via a META-INF/beans.xml file). So a lot of this just stays in thought experiment land: the Frobnicator you get is, well, the one you get. It’s not like there are dozens of them lying around.

But with configuration, you’re usually talking about plain types (String), indexed under names, suitable for certain worlds and not for others (“don’t use the production database url!”).

Standard procedure among the 34,472 CDI configuration “frameworks” out there is to make a “qualifier” called, say, @Config, with all @Nonbinding-annotated elements, thus rendering it not much of a qualifier at all (primarily so that a single producer method can use it), and then a producer method or a CDI extension or something that is actually in charge of figuring out what the name of the configuration item is whose value should be retrieved (thus turning the “qualifier” into a name, really). Note how using @Config here confuses the fact that a qualifier is a value, not an aspect.

(CDI itself (well, JSR-330 actually) gets confused in a similar way with its own annotations!  The javax.inject.Named “qualifier” is, note, not a value, but an aspect.  The value of the aspect is given by the annotation’s value() element.)

So what to do with all this?  I am not sure as of this writing, but I have this nagging sense that there’s the germ of a more powerful, more properly-aligned-with-the-spirit-of-CDI configuration extension brewing in here.

Interesting Things About Kubernetes And Ports

After decades of Java, I am now reduced to a rank rookie as I work on Kubernetes-related tasks.  It’s fun being the Dumb New Guy again.

It was in that spirit that I started asking some questions on the #kubernetes-users Slack channel.

I learned that the Dockerfile of an image referred to by a Kubernetes Deployment is basically advisory.  Where ports are concerned, specifically, any EXPOSE directive is basically ignored or superfluous. That makes a certain amount of sense.

Instead I was advised that containerPorts are where you state definitively what ports to open on your Container.

As it turns out, this isn’t strictly speaking correct. I found from some careful reading of the Container documentation that the containerPorts directive is also advisory (well, “primarily informational”, whatever that means).

So that all means that you could, conceivably, have a Dockerfile in the mix that never uses EXPOSE, and a Deployment that never uses containerPorts, and you could write a program running on the Docker container in question on whatever port it wants (let’s say 9000), and assuming that you defined a Kubernetes Service with a targetPort of 9000, connections would go through just fine.

Changing Annotations at Startup in CDI 2.0

Today’s CDI 2.0 topic is actually about features that have been in there for a long while, but that I don’t see much evidence of out in the wild.

A lot of people are used to injection as provided by Jersey.  This is implemented under the covers by the excellent little underappreciated HK2 project, not by CDI.

HK2 can do really neat things with annotations.  In today’s blog, I want to show you how I took an annotation that was being used by an HK2-based system to provide configuration injection and, using the sledgehammer of the CDI portable extension API, made it usable in a CDI project.

The annotation looks like this, more or less:

As you can see, it is a simple Qualifier annotation that can be applied to fields and parameters only.  It has a value element, which ends up being the name of a particular piece of configuration you want.

So you could see it being used like this:

@Inject
@Config.Key("frobnicationInterval")
private int frobnicationInterval;

Or like this:

@Inject
public Frobnicator(@Config.Key("frobnicationInterval") final int frobnicationInterval) {
  super();
  this.frobnicationInterval = frobnicationInterval;
}

HK2 has a concept somewhat analogous to CDI’s producer.  While a CDI producer can be a method or a field, it can’t be a class.  HK2, on the other hand, defines only one kind of thing-that-can-make-other-things, and calls it a Factory.  Factory‘s provide method returns the thing it can make, and you annotate the provide method in much the same way as you do a CDI producer method.

Unless, of course, you’re working with this particular annotation, as its Target meta-annotation does not allow it to be placed on methods of any kind.

In the HK2 project I was looking at, then, the Factory in question behind this Config.Key annotation simply declared that it provides Object.  No qualifiers.  Hmm.

Now, to get a Factory to be treated as a Factory by HK2, you have to mark it as such, or otherwise instruct HK2 to treat it as a Factory.  Otherwise it’s just another object that happens to implement the Factory interface.  None of those markings or instructions were immediately apparent.

The other thing you can do, though, is define something called an InjectionResolver.  If you do that, then inside that class you can do whatever you like to resolve the given injection point.  As I looked at this project, I found one for Config.Key.  It delegated its work off to the Factory I found, and other various internal configuration engines and whatnot, and the end result is that any class inside this project could do something like the examples I showed above.

I thought I’d cobble together some CDI constructs to do the same thing.

I knew that I couldn’t make any use of managed beans, because of course int and String are not managed beans.  Short of really convoluted potential other solutions, obviously I’d need a producer method.  I would just need to make a producer method that returned Object and that is qualified by Confi

Oops.  The annotation doesn’t have ElementType.METHOD as one of the places listed where it can be used. So my producer method code won’t compile, because I can’t put the Config.Key annotation on it.

Off to the portable extension toolbox.

First, I wrote a private annotation (I named it Property) that looks like this:

This private annotation (an inner annotation) is solely for my bean-housing-the-producer-method’s use, and the use of the extension that installs it.

You’ll note it looks almost the same as Config.Key, but this time it has ElementType.METHOD in its Target annotation.  It also features the Nonbinding annotation applied to its value element, and the value element now has a default value of "".  We’ll talk about those things in a bit.

Then, for reasons to be clear in a bit, I wrote an AnnotationLiteral implementation for it:

The new Property annotation will let me write a producer method like this:

…now that I can use @Property on methods and not just on parameters and fields.

But who cares? No user code can use my new, private inner Property annotation!  So who the heck is ever going to cause this method to be invoked?

Enter portable extensions.  Now we need a portable extension that will search for injection points that feature @Config.Key and make them behave as though they were written with @Property instead.  Once we do that, then we have a linkage: the user’s code says that it wants a particular kind of Object to be injected—namely a @Config.Key-ish one—but we know that for our purposes this should be translated into a desire for a @Property-ish one, and that will be satisfied by the CDI typesafe resolution algorithm and this producer method will be invoked.

There is a container event for just this sort of thing.  It’s called ProcessInjectionPoint, and you can do things with it like this:

This (private!) method will be called on every injection point found by the container (or created by other portable extensions!).  You can restrict the types of points you’re interested in by using something other than wildcards, but this will do for our purposes.

Here, you can see that we ask the InjectionPoint directly for its qualifiers, and we effectively remove the Config.Key qualifier and replace it with an equivalent Property qualifier.

So under the covers it now looks like all client code is using Property, not Config.Key in its injection points.  Cool!

Let’s circle back to the producer method, now that we know it will be invoked.

In CDI, a producer method can take parameters.  If it does, then the parameters are supplied to it by the container as if the method had been marked with @Inject.  So our producer method is handed an InjectionPoint object and a BigCoConfigurationEngine object.  (Let’s pretend for the sake of this article that an instance of BigCoConfigurationEngine has already been found by the container.  We’ll just assume it’s there so will be successfully injected here.)

The InjectionPoint unsurprisingly represents the site of the injection that the producer method will be called upon to implement as needed (as determined by the scope, in our case Dependent).  You can get lots of useful things from it: the parameter or field being injected “into”, the class housing the injection point, and so on.

So we should be able to get the actual Property instance that caused our producer method to fire, and, using the value of its value element, ask the BigCoConfigurationEngine to get us the right configuration value.

There is one very important thing to note here.

There are a couple of “paths” to the information we would like.  Only one of them is valid.

The first path looks like an easy one: we could just call injectionPoint.getAnnotated(), and then call getAnnotation(Class) on it and pass it our Property class.

But we’ll get back no such annotation!  How can that be?  Didn’t our portable extension munge things at startup so that all Config.Key qualifiers got effectively replaced by Property qualifiers?

Yes, but on the injection point itself, not on the objects reachable from the injection point.

That gives us path #2, which is the right one, though it is more cumbersome.  We need to call injectionPoint.getQualifiers(), and then find the Property annotation in there.  That is, our portable extension affected the contents of the return value of the InjectionPoint::getQualifiers method, not the contents of the return value of injectionPoint.getAnnotated().getAnnotations().  Sit and think about that for a moment.  I’ll wait.

So our producer method ends up looking like this:

The takeaway for me here was: in your producer method, if you want to be maximally flexible and a good citizen of the CDI multiverse, make sure you investigate the InjectionPoint metadata itself as much as possible for information, not the Annotated instances reachable from it.

Starting CDI beans eagerly and portably

There are several web resources out there that describe how to get a CDI bean (usually ApplicationScoped) to be instantiated when the CDI container comes up.  Here’s an arbitrarily selected one from Dan Allen:

Let’s look at the extension immediately above.

The AfterDeploymentValidation event is the only event a portable extension can observe in a portable manner that indicates that the container is open for business. It is guaranteed to fire last in the dance that the container performs as it starts up.

In the extension above, then, you can see that it has saved off the beans it has discovered that have been annotated with a Startup annotation (which isn’t defined in the gist, so it could be javax.ejb.Startup or a Startup annotation that Dan has defined himself). Then, for these beans, it uses the BeanManager‘s getReference() method to get an actual Java object representing those beans.

So what’s the toString() call for?

The short answer is: this is the only method that could conceivably cause the container-managed client proxy that is the object reference here to call the actual constructor of the actual underlying object that the user and everyone else is actually interested in.

For more detail, let’s look at the specification, section 6.5.3, which concerns contextual references—the return value of the getReference() method above—and which reads in part:

If the bean has a normal scope [e.g. not Dependent or Singleton], then the contextual reference for the bean is a client proxy, as defined in Client proxies, created by the container, that implements the given bean type and all bean types of the bean which are Java interfaces.

OK, so whatever the getReference() method returns is a client proxy. That means it’s going to forward any method invocation it receives to the object that it’s proxying (known as the bean’s contextual instance. CDI containers try to be efficient, so that object may not have been created yet—the proxy, in other words, might be lazy. So here, the contextual reference returned is a contextual reference (a client proxy) of type Object, and the toString() invocation causes the contextual reference (client proxy) to realize that oh, hey, the underlying contextual instance of whatever bean this is doesn’t yet exist, and to therefore invoke the “real” constructor, so that the “real” object (the contextual instance) can return something from its toString() method.

As a happy side effect, the container is of course the one causing the instantiation of the “real” object, so it is going to perform dependency injection, invoke initializer methods, invoke any PostConstruct-annotated methods, and so on.  Presto: you have a portable way for your bean to be instantiated when the container comes up.

(Side note: toString() in particular is used because there is a little nugget at the bottom of the Client Proxies section of the specification that says, innocuously (emphasis mine):

The behavior of all methods declared by java.lang.Object, except for toString(), is undefined for a client proxy. Portable applications should not invoke any method declared by java.lang.Object, except for toString(), on a client proxy.

File that one away: among other things that might mean don’t put your CDI-managed objects in Maps or Collections, since doing so will use client proxy equals(Object) and hashCode() methods!)

So.  If you’re feeling like this whole thing is a bit of a steaming hack—you call toString(), and a whole lot of very sophisticated magic happens (!)—I can’t disagree.

Fortunately, there’s a better way.

Instead of the toString() hack above, you can do the same thing in the extension in a more sanctioned, more explicit manner.

The first thing to understand is: who is doing the actual creation?  If we can understand that, then we can understand how to do it eagerly and idiomatically.

The ultimate answer is: the bean itself, via the create() method it implements from the Contextual interface. So if you ever get a Bean in your hand (or any other Contextual), you can call create() on it all day long and get new instances (this should sound scary, because it is).  For example, suppose you have an ApplicationScoped-annotated bean in your hand in the form of a Bean object.  If you call create() on it three times, you will create three instances of this object, hopefully surprising and gently horrifying you. Those instances may be wrapped in proxies (for interception and such), but they won’t be wrapped in client proxies.  Don’t do this!

Still, scary or not, we’ve found the method that some part of the container somewhere at some point will invoke when a contextual instance is needed (to further wrap in a contextual reference). But obviously when you inject an ApplicationScoped-annotated bean into, say, three different locations in your code somewhere, everything behaves as though there’s only one instance, not three. So clearly the container is not running around rampantly calling create() every time it needs an object.  It’s acquiring them from somewhere, and having them created if necessary.

The container is actually calling a particular get() method on the bean’s associated Context, the machinery that implements its scope. This method’s contract basically says that the Context implementation should decide whether to return an existing contextual instance, or a new one. So you can see that the Context underlying application scope will (hopefully!) return the One True Instance™ of the bean in question, whereas the Context implementation underlying some other scope may create new instances each time.

OK, so what do we know?  Let’s step back.

So to eagerly instantiate beans at startup while respecting their scopes, we should follow this approach in the extension as well—we’ll do basically what a lazy contextual reference (client proxy) does, in other words, when a toString() method is invoked on it.  We’ll need to effectively ask the right Context for a contextual instance of the bean in question, creating it if necessary.  This also would allow for custom-scoped beans to be instantiated eagerly, provided of course that the Context backing the custom scope is actually active.

If you have a BeanManager handy, and a Bean object of a particular type (say Bean<Object>), then you can get the relevant Context quite easily:

final Context context = beanManager.getContext(bean.getScope());

Then you need a CreationalContext, the somewhat opaque object that assists the Context with creation, should the Context decide that creation is necessary:

final CreationalContext<Object> cc = beanManager.createCreationalContext(bean);

Finally, we can ask the Context for a contextual instance directly:

final Object contextualInstanceNotContextualReference = context.get(bean, cc);

Note, as the variable name makes clear, this is a contextual instance, not a contextual reference!  This is not a client proxy!  So you really don’t want to use it after this point.

So if you replace Dan’s line 19 above with these code snippets, you will eagerly instantiate beans at startup without relying on magic side effects.