The course is part of this learning path
This course provides you with a deep dive into the various JDK features for accessing different resources when developing with Java. We’ll cover areas such as JDBC, Annotations, CDI, and JPA.
After completing this course, why not do our Accessing Resources using Java Annotations, CDI, JDBC, and JPA lab to put your knowledge into practice?
- Understand what the JDBC API is how to implement it to access databases
- Understand what Annotations are and the benefits of working with them to access resources
- Understand what CDI is and how you can use it for dependency injection and interception
- And understand what JPA is and how you can use it for object relational mapping and as a persistence framework
- A basic understanding of the Java programming language
- A basic understanding of software development
- A basic understanding of the software development life cycle
- Software Engineers interested in advancing their Java skills
- Software Architects interested in using advanced features of Java to design and build both applications and frameworks
- Anyone interested in advanced Java application development and associated tooling
- Anyone interested in understanding the advanced areas and features of the Java SDK
OK, welcome back. In this lecture, we're going to explore Contexts and Dependence Injection, CDI, in detail and how it can and should be used to provide dependency injection interception services. In particular, we'll review the following topics: understand the value of CDI, explore dependency injection, understand alternatives, understand annotation processing, and using and configuring CDI. At the conclusion of this lecture, you should be able to perform each of the items listed above. Take a moment to rate yourself on each of these items on a scale one through to five. At the conclusion of this lecture, these objectives will be reviewed. You should rate yourself again to see how much benefit you've received.
Dependency injection refers to the process of supplying an external dependency to a software component. Dependency injection can help make your code architecturally pure. It aids in design by interface as well as test-driven development by providing a consistent way to inject dependencies. For example, a data access object may depend on a database connection. Instead of looking up the database connection with JNDI, you could simply inject it. One way to think about a dependency injection framework is to think of JNDI turned inside out. Instead of an object looking up other objects that it needs to get a job done, a dependency injection container injects those dependent objects. This is the so-called Hollywood Principle: "Don't call us, we'll call you."
If you have ever worked with CRC cards, you can think of a dependency as a collaborator. A collaborator is an object that another object needs to perform its role. Like a data access object needs a JDBC connection object, for example, context and dependency injection or CDI as the Java stand for the dependency injection, DI and interception or aspect-oriented programming AOP. It is evident from the popularity of both DI and IOP that Java needs to address both so that it can build other standards and JSS on top of it. Both DI and AOP are foundational to mini Java frameworks and therefore CDI will be the foundation of many futures specifications in JSS. CDI is a foundational aspect since Java EE6. It is supported by a number of application servers. CDI is similar to the core spring framework. Much like JPA simplified RRM, CDI simplifies and sanitizes the API for DI in AOP.
A managed bean is a contextual object which defines application state and or logic. These objects are called contextual instances of the Bean. The CDI container creates and destroys these instances and associates them with the appropriate context. Contextual instances of a bean may be injected into other objects including other bean instances that execute in the same context. All you need to do to define a bean as to write a POJO, or plain old Java object, and declare it to be a CDI bean. To do so, there are two primary approaches using annotations or using the Beans.XML file.
As an example, let's consider doing dependency injection without CDI. Objects often need to rely on other objects or services to perform a certain task. In the example shown here, a TravelService needs to be able to validate credit card details when a client is invoking the pay method. Both the service and the validator have been represented by interfaces. Now the TravelService needs a validator to performance its intent, namely, validate the credit card to carry out these tasks. The TravelService implementation class may depend on many objects and collaborates with its dependencies to complete the work. The TravelService implementation does not know or care how the credit card is being validated; all it cares about is there some kind of implementation of the interface is available to perform this task.
This level of indirection allows us to replace the validator with different implementations. For testing and developing instead of using a real validated service, you could simply use MEKIDO or easy mark or write a simulation credit card validator that is just a mock implementation specifically for the purpose of testing. An application that uses CDI must have a file named Beans.XML. The file can be completely empty, but it must be present. For a web application, the Beans.XML file must be in the WEB dish-INF directory. For EJB modules with JAR files, the Beans.XML file must be in the META-INF dish of directory.
In the example shown here, we've provided a starter Beans.XML file with its name, spaces, and no elements. Although the Beans.XML file could be completely empty, it is nice to have a starter file so that when you need to add things, you can readily. Also, it keeps the ID from complaining about a malformed XML file when there is nothing in it. The inject annotation lets us to find an injection point that is injected during bean instantiation.
Injection can occur via three different mechanisms, the targets being field, method or constructor. In the example shown here, CDI searches for a class that implements the credit card validated interface. The CDI specification defines a procedure called "type safe resolution" that the container follows when identifying the bean to inject into the injection point.
Instance resolution. By default, CDI looks for a class that implements the credit card validator interface. Once it finds this, it creates an instance and injects it. If we only hit one possible implementation of the credit card validator in our classpath, we would not need to annotate any of the implementations. However, when multiple are available, for example, if we had a JSON credit card validator and also a SOAP credit card validator, then one of them needs to be marked with the default annotation while the other one becomes marked with the alternative annotation. The alternative annotation codifies and simplifies a very normal case of dependency injection, namely, you have different injected objects based on different bills or environments.
The great thing about objects, as Grady Booch said, is that they can be replaced. Alternatives allow you to mark objects that are replacements for other objects and then activate them when you need them. If the dependency injection container can have alternatives, let's mark them as alternatives. Think about it this way. I don't have to document all of the alternatives as such. It is self-documenting. If someone knows CDI and they know all about the alternative annotation, they will not be surprised. You can think of CDI is a canonicalization of many patterns that we have been using with the more general purpose to dependency injections frameworks.
The simplification and canonicalization is part of the evolution of DI. Earlier, we defined multiple implementations of the validator. When I see this needs to be installed, that requires a different validation service to perform the credit card validation. All that needs to be done is an edit applied to the Beans.XML file in the Meta dish of directory. As earlier mentioned, type safe resolution is a process of matching a bean to an injection point. CDI can set as bean types in its qualifiers when resolving a Bean for injection.
Type safe resolution occurs at application startup for the most part. This allows CDI to warn the application developer of deployment problems like ambiguous or unresolved injections.
CDI qualifiers. A qualifier is just a runtime annotation that is marked with the qualify annotation. You can use qualifiers to provide various implementations of a particular bean type. A qualifier is an annotation that you apply to a bean. A qualifier type is a Java annotation defined with the target in retention annotations. For example, you could to clear a SOAP qualifier type and apply it to the soap credit card validated class, which is itself implementing the credit card validator interface. The newly created SOAP qualify annotation can now be applied to all possible injection points, constructors, setters, or fields as seen here bootstrapping the CDI container.
At startup, the CDI container needs to be initialized in the Java EE environment. This is performed by the application server. In the JC world, this is performed programmatically. CDI 2.0 introduced EC container initializer, which is a new API to configure and bootstrap a CDI container under Java EC. It returns a EC container that implements an instance of object allowing for programmatic lookup.
The instance interface. When programmatically retrieving Bean instances from the container, an instance object will be returned. This object represents all beans that are available for the requested type. Using methods of this interface, you can now auto rate over all available types or even perform a sub select by defining qualifiers. In CDI, qualifiers are defined using annotations. Since annotations are interfaces, it is impossible to create instances of these annotations so that they can be used as method parameters of the select method. It would be quite tedious to create a concrete implementation of an annotation type. Instead, CDI allows you to obtain a qualified instance by sub classing the annotation literal helper class. CDI promotes strong typing since a big part of CDI is its type safe injection. Looking up things by name is discouraged. Notice here we have one less class due to Java generics.
Okay, before we complete this lecture, pause this video and consider the following questions to test yourself on the content that we've just reviewed. Write down your answers for each question and then resume the video to compare answers. Okay, the answers to the above questions are: one - dependency injection and interception; two - to be non-invasive, to be usable in any environment, facilitate good coding practices and promote pluggability; three - envision of control - objects are handed the components they rely on by the framework, instead of looking for the components themselves; four - applications are self-documenting independent of particular frameworks, applications can focus on business logic; five - constructors, setters or fields; six -true; seven - inject annotation; eight - you don't, if you don't specify it, it is the default; nine - when you have more than one dependency with the same type.
Jeremy is a Content Lead Architect and DevOps SME here at Cloud Academy where he specializes in developing DevOps technical training documentation.
He has a strong background in software engineering, and has been coding with various languages, frameworks, and systems for the past 25+ years. In recent times, Jeremy has been focused on DevOps, Cloud (AWS, GCP, Azure), Security, Kubernetes, and Machine Learning.
Jeremy holds professional certifications for AWS, GCP, and Kubernetes (CKA, CKAD, CKS).