two brown trees

Introduction to Spring Framework

DI Container

Overview of Spring Framework’s DI

Dependency injection, or DI, is a process where an object defines its dependencies only through arguments to its constructor or setter method, or properties that are going to be set on an object instance after it’s created.

DI helps to decouple components; when dependencies are declared as interfaces or abstract classes, we can easily replace their implementations with another, or mocks for unit testing.

In Spring Framework, DI container injects dependencies automatically when it creates beans, based on configuration metadata. A bean represents an object which is instantiated, assembled, and managed by DI container. ApplicationContext interface plays a role as Spring Framework’s DI container; which is responsible for instantiating, configuring, and assembling beans, based on the configuration metadata.

How to Register Beans

The DI container consumes configuration metadata, which represents how components are supposed to be instantiated, configured, and assembled. The two most famous options for declaring configuration metadata are Java-based configuration and annotation-based configuration.

In Java-based configuration, we define beans on a configuration class annotated with @Configuration. Within that class, each component is annotated with @Bean to be registered in the DI container.

On the other hand, in annotation-based configuration, each component class is declared with @Component annotation respectively, and we instruct the DI container to scan those component based on the specified package.

Apparently, annotation-based configuration seems easier. However, when you want to register the bean for types that cannot be annotated with @Component, such as those from external libraries or third-party classes, you’ll use Java-based configuration.

How to Inject Dependencies into A Bean

There’re the two major DI options; constructor-based DI and setter-based DI.

In constructor-based DI, DI container invokes the constructor annotated as @Autowired with instantiated beans as its dependencies. On the other hand, in setter-based DI, DI container injects dependencies through its setter method annotated as @Autowired after invoking its default constructor to instantiate an object instance.

Which option should we go with? The official documentation mentions the following:

The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not null.

Constructor-based or setter-based DI?

Now, consider the case of injecting a bean whose scope is different from that of another bean it’s injected into. If we inject through @Autowired annotation, the scope of the injected bean becomes the same as another bean it is injected into, regardless of the bean definition. In order to inject a bean with its intended scope, we can lookup beans managed by the DI container through ApplicationContext.getBean method instead of @Autowired annotation.


Overview of Spring MVC architecture

In Spring MVC, DispatcherServlet plays a central role as a front controller, and delegates actual work to configurable components.

DispatcherServlet, first, delegates to HandlerMapping interface to find an appropriate handler. RequestMappingHandlerMapping, one of the well-known implementations, provides a mapping from HTTP requests to @RequestMapping annotated methods.

And then, it delegates to HanderAdapter interface to invoke the handler.

If an exception occurs during that, DispatcherServlet delegates to HandlerExceptionResolver to resolve the exception and provide alternative handling. One well-known implementation is ExceptionHandlerExceptionResolver, which invokes a @ExceptionHandler annotated method in a @ControllerAdvice annotated class.