git clone https://github.com/openliberty/guide-cdi-intro.git cd guide-cdi-intro
Injecting dependencies into microservices
Learn how to use Contexts and Dependency Injection (CDI) to manage scopes and inject dependencies into microservices.
What you’ll learn
You will learn how to use Contexts and Dependency Injection (CDI) to manage scopes and inject dependencies in a simple inventory management application.
The application that you will be working with is an
inventory service, which stores the information about various JVMs that run on different systems. Whenever a request is made to the
inventory service to retrieve the JVM system properties of a particular host, the
inventory service communicates with the
system service on that host to get these system properties. The system properties are then stored and returned.
You will use scopes to bind objects in this application to their well-defined contexts. CDI provides a variety of scopes for you to work with and while you will not use all of them in this guide, there is one for almost every scenario that you may encounter. Scopes are defined by using CDI annotations. You will also use dependency injection to inject one bean into another to make use of its functionalities. This enables you to inject the bean in its specified context without having to instantiate it yourself.
The implementation of the application and its services are provided for you in the
start/src directory. The
system service can be found in the
start/src/main/java/io/openliberty/guides/system directory, and the
inventory service can be found in the
start/src/main/java/io/openliberty/guides/inventory directory. If you want to learn more about RESTful web services and how to build them, see Creating a RESTful web service for details about how to build the
system service. The
inventory service is built in a similar way.
What is CDI?
Contexts and Dependency Injection (CDI) defines a rich set of complementary services that improve the application structure. The most fundamental services that are provided by CDI are contexts that bind the lifecycle of stateful components to well-defined contexts, and dependency injection that is the ability to inject components into an application in a typesafe way. With CDI, the container does all the daunting work of instantiating dependencies, and controlling exactly when and how these components are instantiated and destroyed.
The fastest way to work through this guide is to clone the Git repository and use the projects that are provided inside:
start directory contains the starting project that you will build upon.
finish directory contains the finished project that you will build.
Try what you’ll build
finish directory in the root of this guide contains the finished inventory application. Give it a try before you proceed.
To try out the application, first navigate to the
finish directory and then run the following Maven goals to build the application and run it inside Open Liberty:
cd finish mvn install liberty:start-server
Point your browser to the http://localhost:9080/inventory/systems URL. This is the starting point of the
inventory service and it displays the current contents of the inventory. As you might expect, these are empty since nothing is stored in the inventory yet. Next, point your browser to the http://localhost:9080/inventory/systems/localhost URL. You see a result in JSON format with the system properties of your local JVM. When you visit this URL, these system properties are automatically stored in the inventory. Go back to http://localhost:9080/inventory/systems and you see a new entry for
localhost. For simplicity, only the OS name and username are shown here for each host. You can repeat this process for your own hostname or any other machine that is running the
After you are done checking out the application, stop the Open Liberty server:
Handling dependencies in the application
You will use CDI to inject dependencies into the inventory manager application and learn how to manage the life cycles of your objects.
Managing scopes and contexts
Navigate to the
start directory to begin.
This bean contains two simple functions. The
add() function is for adding entries to the inventory. The
list() function is for listing all the entries currently stored in the inventory.
This bean must be persistent between all of the clients, which means multiple clients need to share the same instance. To achieve this by using CDI, you can simply add the
@ApplicationScoped annotation onto the class.
This annotation indicates that this particular bean is to be initialized once per application. By making it application-scoped, the container ensures that the same instance of the bean is used whenever it is injected into the application.
The inventory resource is a RESTful service that is served at the
@RequestScoped annotation on the class to indicate that this bean is to be initialized once for every request. In other words, the bean is instantiated when the request is received and destroyed when a response is sent back to the client. While this bean can also be application-scoped, request scope is short-lived and is therefore ideal for HTTP requests.
Injecting a dependency
Refer to the
InventoryResource class you created above.
@Inject annotation indicates a dependency injection. You are injecting your
SystemClient beans into the
InventoryResource class. This injects the beans in their specified context and makes all of their functionalities available without the need of instantiating them yourself. The injected bean
InventoryManager can then be invoked directly through the
manager.add(hostname, props) and
manager.list() function calls. The injected bean
SystemClient can be invoked through the
systemClient.getProperties(hostname) function call.
Finally, you have a client component
SystemClient that can be found in the
src/main/java/io/openliberty/guides/inventory/client directory. This class communicates with the
system service to retrieve the JVM system properties for a particular host that exposes them. This class also contains detailed Javadocs that you can read for reference.
Your inventory application is now completed.
Building and running the application
To build the application, run the Maven
install phase from the command line in the
This command builds the application and creates a
.war file in the target directory. It also configures and installs Open Liberty into the
Next, run the Maven
This goal starts an Open Liberty server instance. Your Maven
pom.xml is already configured to start the application in this server instance.
You can find the
system services at the following URLs:
If you make changes to the code, use the Maven
compile goal to rebuild the application and have the running Open Liberty server pick them up automatically:
To stop the Open Liberty server, run the Maven
Testing the inventory application
While you can test your application manually, you should rely on automated tests since they trigger a failure whenever a code change introduces a defect. Since the application is a RESTful web service application, you can use JUnit and the RESTful web service Client API to write tests. In testing the functionality of the application, the scopes and dependencies are being tested.
@BeforeClass annotation is placed on a method that runs before any of the test cases. In this case, the
oneTimeSetup() method retrieves the port number for the Open Liberty server and builds a base URL string that is used throughout the tests.
@After annotations are placed on methods that run before and after every test case. These methods are generally used to perform any setup and teardown tasks. In this case, the
setup() method creates a JAX-RS client, which makes HTTP requests to the
inventory service. This client must also be registered with a JSON-P provider (
JsrJsonpProvider) to process JSON resources. The
teardown() method simply destroys this client instance.
See the following descriptions of the test cases:
testEmptyInventory()verifies that the inventory is initially empty when the server first starts up.
testHostRegistration()verifies that a host is correctly added to the inventory.
testSystemPropertiesMatch()verifies that the JVM system properties returned by the
systemservice match the ones stored in the
testUnknownHost()verifies that an unknown host or a host that does not expose their JVM system properties is correctly handled as an error.
To force these test cases to run in a particular order, put them in a
testSuite() method and label it with a
@Test annotation so that it automatically runs when your test class run.
src/test/java/it/io/openliberty/guides/system/SystemEndpointTest.java file is included for you to test the basic functionality of the
system service. If a test failure occurs, then you might have introduced a bug into the code.
Running the tests
If the server is still running from the previous steps, stop it using the Maven
liberty:stop-server goal from command line in the
Then, verify that the tests pass using the Maven
It may take some time before build is complete. If the tests pass, you will see a similar output to the following:
------------------------------------------------------- T E S T S ------------------------------------------------------- Running it.io.openliberty.guides.system.SystemEndpointTest Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.99 sec - in it.io.openliberty.guides.system.SystemEndpointTest Running it.io.openliberty.guides.inventory.InventoryEndpointTest Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.325 sec - in it.io.openliberty.guides.inventory.InventoryEndpointTest Results : Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
To see whether the tests detect a failure, change the
endpoint for the
inventory service in the
src/main/java/io/openliberty/guides/inventory/InventoryResource.java file to something else, then run the Maven build again. You see a test failure occur.
Great work! You’re done!
You have just completed building a simple inventory application using CDI services in Open Liberty.
Injecting dependencies into microservices by Open Liberty is licensed under CC BY-ND 4.0
Nice work! Where to next?
What did you think of this guide?
Thank you for your feedback!
Thank you for your feedback!
Would you like to open an issue in GitHub?Yes
What could make this guide better?
Raise an issue to share feedback
Create a pull request to contribute to this guide