Mastodon

Using Dependency Injection

One topic of discussion I encountered in every project so far is the “right” usage of Springs Dependency Injection (DI). In this article, I want to describe how this controversial feature is used in my current project.

This project is a Java application with a Swing frontend, a Spring-powered middleware and a Hibernate OPM. For this article, some classes of the middleware are important: Commands, Services and Data Access Objects (DAOs). Every action on the user interface (for example loading a panel or sorting a table on the server) is represented by one Command. If this command needs new data, it can call a Service or a DAO. The later only loads objects from the database whereas Services can perform additional logic.

Dependency Injection Architecture

As the figure shows, all of the three classes are placed in the middleware which runs in a Spring-container. This allows for the needed references to be set in a classic, manually Java-style or via DI. Originally, DI was supposed to be used for technical infrastructure such as database connections and objects that will be used no matter what happens during runtime, for example I18N translation objects. The architect of my team decided to have use case specific objects under DI, too. Namely, all Services and all DAOs are Spring beans. Commands on the other hand are the gateways between objects from outside of the Spring container, such as the Swing components, and the Spring-organized objects on the middleware. During the execution of a command, it acquires a Service or DAO via SpringApplicationContext.getBean(nameOfTheBean). This method is used only in Commands. The references between Services and DAOs are set in the spring-config.xml.

This architecture has several implications:

  1. Because all beans of the middleware and the references are constructed at the setup of the Spring application context, the performance will be relatively slow. Using classic Java referencing and constructing the objects on demand would boost the start of the application and decrease its performance during runtime. Because the users of the application will work all the day with it, it has to be started only once. Hence, a lower starting performance is acceptable.
  2. Because of the initial construction of the dependency graph, the application will use much memory from the start instead of requesting more RAM over the runtime.
  3. There is a clear policy on when to use DI and when not to. All objects in the middleware have to be beans and the only gateway between the Spring container and the outside are the Commands. This rule is simple and guarantees a homogenous code base, which is highly preferable.
  4. Because all references inside the middleware are set in the spring-config.xml, the code is not clattered with calls of getBean() and there is exactly one place to go to change these references. getBean() is only used in Commands.

In conclusion, the decision of the architect is logical and meets the requirements of the system. Additionally, it provides a clear guideline on how to use CI.