The Hollywood Principle
Tutorial - Introduction to CDI - Contexts and Dependency Injection for Java EE (JSR 299) - Part 2
Sometimes it's very helpful to look behind the scenes of a framework to understand at least the very basic mechanisms. Thus we like to explain a few of those techniques first.
Dependency Injection: DI is sometimes described as the ‘Hollywood Principle’ – “don't call us, we call you”. It means that we let the container manage the creation of instances and inject it instead of creating them ourselves with the new operator. Of course, even in DI containers, nothing happens without anyone triggering this process. For a JSR-299 container, this trigger is a call to one of the method
T BeanManager#getReference(Bean<T> type, Qualifier... qualifiers);
which returns an instance of the given type T. By doing so, it will not only create the returned instance, but also all of its @Inject-annotated children in a recursive way.
Usually the getReference(Bean<T>) method is not called manually, but internally by the Expression Language Resolver. By writing something like
the ELResolver will look for the Bean<T> with the name “mailForm” and resolve the instance.
Scopes, contexts, singletons: Each of a CDI container’s managed objects is a ‘singleton’ in the original sense specified by Ward Cunningham, who invented not only the Wiki but also, together with Kent Beck, introduced design patterns into computer science in 1987. A ‘singleton’ in this sense means that there is exactly one instance in a well-specified context. In a comment on „Refactoring to Patterns“ by Joshua Kerievsky, Ward noted:
There is a proper context for every computation. So much of object-oriented programming is about establishing context, about balancing the lifetimes of variables, causing them to live the right length of time and then die gracefully.
CDI is all about creating singletons in a well-specified context. In our case, the lifecycle of instances is defined by their scopes. A @SessionScoped-annotated bean exists exactly once per session. We could also name it a “session singleton”. If a user accesses our @SessionScoped bean for the first time, it will get created and stored inside the session. Every subsequent access will return exactly this same instance. When the session ends, all the CDI-managed instances stored inside it will also be properly destroyed.
If we have a @RequestScoped bean, we could call it a ‘request singleton’, a @ConversationScoped bean is a ‘conversation singleton’, etc.
Terminus ‘Managed Bean’: There are a few terms used in the CDI specification which need a short explanation. The term ‘Bean’ in Java is already pretty well-established and means a POJO (Plain Old Java Object) with getters and setters. The terminus technicus ‘Managed Bean’ now means something completely different. It doesn't refer to instances of a class but meta-information which can be used to create those instances. It is represented by the interface Bean<T> and will be gathered on container startup via classpath scanning.
Terminus ‘Contextual Instance’: Contextual Instances are exactly our singleton instances per scope, our ‘session singletons’, ‘request singletons’, etc. Usually a user never uses a Contextual Instance directly, but only via its ‘Contextual Reference’
Terminus ‘Contextual Reference’: By default, a CDI container wraps all Contextual Instances via a proxy and only injects those proxies instead of the real instances. In the CDI specification those proxies are called ‘Contextual Reference’. There are plenty of reasons why CDI uses proxies by default:
- Serialisation: Instead of serialising the full object, we only need to serialise the proxy. On de-serialisation, it will automatically ‘connect’ to the right Contextual Instance again.
- Scope differences: With proxies, it is possible to inject a @SessionScoped UserSettings into an @ApplicationScoped MailService because the Proxy will ‘connect’ to the right UserSettings itself.
- Interceptors and Decorators: a proxy is the perfect way to implement interceptors and decorators in a non-intrusive way.