Spring what is dependency injection




















Dependency Injection by setter method Let's see how we can inject dependency by setter method. Reinforcement Learning. R Programming. React Native. Python Design Patterns. Python Pillow.

Python Turtle. Verbal Ability. Interview Questions. Company Questions. Artificial Intelligence. Cloud Computing. Data Science. Angular 7. Machine Learning. Data Structures. Operating System. Computer Network. Compiler Design.

In this case, that developer would then be required to create another Car implementation to support his or her particular Engine. As we will see shortly, we must solve it by changing our assumptions, which will remove the problem altogether. The former problem can be easily solved by creating a Car base class and moving the common code into that base class.

Since the engine field is private , we are forced to either relax the visibility of the engine field or change the Car base class constructor to accept an Engine object and make the assignment within the Car base class constructor. Since relaxing the visibility of the engine field could open the engine field up to manipulation by outside classes such as a Car implementation from another developer , we will use the constructor-based solution:.

Using this approach, we successfully removed the duplicate code, but this solution begs the question: Why not just go back to our original Car class and allow the client instantiating Car objects to pass in the Engine implementation as a constructor argument? This approach would also remove the need to create a new Car implementation for each Engine implementation, since the Car class only depends on the Engine interface and has no knowledge of any particular Engine implementation.

Following this approach, we can change our Car implementation to:. By adding the Engine constructor argument, we have changed the decision of which Engine implementation to use from the Car class itself — which originally decided on a CombustionEngine — to the client that instantiates the Car class.

This reversal of the decision process is called the IoC principle. Instead of the Car class itself controlling which Engine implementation is used, now the client controls which implementation is used. From this example, it is clear that the client that instantiates the Car class has control over the Engine implementation used and depending on which implementation is passed to the Car constructor, the behavior of the Car object changes drastically.

An additional benefit of IoC is that it also makes testing the Car class much easier. Since the Engine implementation can be supplied by the client, we can supply a mock Engine object within our testing framework that can be used to ensure that specific methods are called on the Engine implementation when actions on the Car are performed. Although we have solved the issue of deciding who controls what Engine implementation to use, we have also altered the steps required to instantiate a Car object.

Originally, no arguments were required to instantiate a Car , since the Car constructor handled the creation of the Engine object. Using the IoC approach, we require that a fully-constructed Engine object be passed to the Car constructor before a Car object can be instantiated. In short, originally, we instantiated the Car object first and then instantiated the Engine object; but, using IoC, we first instantiate the Engine object and then the Car object.

Therefore, we have created a dependency in the construction process. This dependency differs from the compile-time dependency that the Car class has on the Engine interface, though. Instead, we have introduced a run-time dependency. Before a Car object can be instantiated at run-time, an Engine object must be instantiated first.

We can formalize this process by creating a graph of these dependencies, where the nodes of the graph represent an object and the edges represent the dependency relationship with the arrow pointing to the depended-upon object. This graph is called a dependency tree — or dependency graph. In the case of our Car class, the dependency tree is simple:.

This dependency tree can become more complex if the terminal nodes of the tree have additional dependencies of their own. For example, if the CombustionEngine had other dependencies, we would be required to first satisfy the dependencies of the CombustionEngine before we could instantiate a CombustionEngine object to be passed to our Car constructor during instantiation of the Car object:.

Given our updated CombustionEngine , our dependency tree would resemble the following:. This complexity would continue to grow as we continue to introduce more dependencies. To resolve this complication, we need to abstract the creation process for an object based on its dependency tree. This process is what constitutes a DI framework. Either an explicit declaration of dependencies or introspection of the constructor for a class satisfies 1. With reflection, we can know that the Car object requires an Engine object in the same way we discovered this in the previous sections: We look at the constructor of the Car class — from which a Car object would be instantiated — and see that it requires an Engine argument.

Since we know that a Car object requires an Engine object, we must declare at least one implementation of the Engine class to be eligible to be used as a dependency. For example, if we declare that the CombustionEngine is eligible to be used as a dependency, then we can create a CombustionEngine object, which satisfies the Engine requirement for the Car object.

This process is recursive, though. Since we declared the CombustionEngine class to be eligible as a dependency, we would need to know how to create an object of the CombustionEngine class. This necessitates that we introspect the CombustionEngine constructor — as we did in 1 — which tells us that in order to create a CombustionEngine object, we require Camshaft and Crankshaft objects.

Thus, we would now require that the Camshaft and Crankshaft classes be declared as eligible to be used as dependencies before we could create a Car object. Lastly, 3 we take the previous two requirements and puts them into action. In practice, this means that when an object is requested, such as a Car object, we must walk the dependency tree and check that there is at least one eligible class for all dependencies.

For example, declaring the CombustionEngine class as eligible satisfies the Engine node requirement. If such a dependency exists, we instantiate the dependency and then move to the next node. If there is more than one class that satisfies a required dependency, then we must explicitly state which of the possibilities should be selected.

We will cover how Spring does this later. Similarly, if the dependency graph contains a cycle, where an object of class A is required to instantiate an object of class B , but class B requires an object of class A , then we must throw an error. We will also see later how Spring handles cyclical dependencies. Once we are sure that all dependencies are satisfied, we can then construct the dependencies, starting with the terminal nodes.

In the case of our Car object, we first instantiate Camshaft and Crankshaft objects — since those objects do not have dependencies — and then pass those objects to the CombustionEngine constructor to instantiate a CombunstionEngine object. Finally, we pass the CombustionEngine object to the Car constructor to instantiate our desired Car object.

While often considered hair-splitting, it is essential that a distinction is made between a library and a framework. A library is a set of standalone code that is used within another set of code.

For example, a math library may provide classes and methods that allow us to perform complex operations. These classes and methods are imported by our application and are adapted within our code to make up our application. A framework , on the other hand, can be thought of as a skeleton in which our code slots into to create an application. Many frameworks stub out application-specific portions and require that we as developers provide code that fits into the framework.

In practice, this means writing implementations of interfaces and then registering the implementations with the framework. In the case of Spring, the framework centers around the ApplicationContext interface. This interface represents a context that is responsible for implementing the three DI responsibilities outlined in the previous section. Thus, we register eligible classes with the ApplicationContext through either Java-based or XML-based configurations and request the creation of objects, called beans , from the ApplicationContext.

The ApplicationContext then builds a dependency tree and traverses it to create the desired bean. The logic contained in the ApplicationContext is often referred to as the Spring Container.

In general, a Spring application can have more than one ApplicationContext , and each ApplicationContext can have separate configurations.

For example, one ApplicationContext may be configured to use the CombustionEngine , as its Engine implementation while another container may be configured to use the ElectricEngine as its implementation.

Throughout this article, we will focus on a single ApplicationContext per application, but the concepts described below apply even when an application has multiple ApplicationContext instances.

In order to simplify the configuration process, Spring allows developers to provide DI configurations using Java code. At its core, two main annotations make up this process:. For example, given the Car , CombustionEngine , Camshaft , and Crankshaft classes we previously defined, we can create a configuration that resembles the following:.

Note that the methods annotated with Bean follow the convention that the method name matches the return value type but in lower-camelcase. Preferred option when properties are less and mutable objects can be created. Preferred option when properties on the bean are more and immutable objects eg: financial processes are important for application.

Example of Spring DI:. Setter and constructor injections have their own pros and cons as discussed above. So we should use the combination of both which is also suggested by the Spring community itself.

Use constructor injection for the mandatory dependencies and setter injection for optional dependencies. Skip to content. Change Language. Related Articles. Table of Contents. Save Article. Improve Article. Like Article. IGeek geek;. GFG IGeek geek. Previous Introduction to Spring Framework.



0コメント

  • 1000 / 1000