Dependency Injection of Spring's Core Mechanism

Source: http://java.9sssd.com/javafw/art/1340

Java application (from a small range of applets to a full set of n-tier server-side enterprise applications) is a typical dependent application, which consists of some mutually appropriate applications. composed of collaborating objects. Therefore, we say that there are dependencies between these objects. By adding that the A component calls the method of the B component, we can say that the A component depends on the B component. By using dependency injection, the various components in a Java EE application do not need to be hard-coded together, or even use the factory pattern. When a Java instance needs other Java instances, the system automatically provides the required instance without the need for program display. ).

In fact, whether it is inversion of control or dependency injection, they can all understand this: when a Java instance (caller) needs another Java instance (callee), in the traditional programming process, the caller usually comes to Create an instance of the callee. But in dependency injection/inversion of control mode, the job of creating the callee is no longer done by the caller, but by the Spring container, which is then injected into the caller.

For Spring, Spring adopts a dynamic and flexible way to manage various objects. The specific implementation between objects and objects is transparent. Spring's dependency injection has almost no requirements on the caller and the callee, and fully supports the management of dependencies between POJOs.

There are usually two types of dependency injection:

1. Setting injection: The IoC container uses the property's setter method to inject the dependent instance.

2. Constructor injection: The IoC container uses the constructor to inject dependent instances.

1. Set value injection

Set value injection means that the IoC container uses the property setter method to inject the dependent instance. This injection method is relatively simple and intuitive.

Below is the Person interface, which defines a Person specification.

View Row Code
1 public interface Person {
2 //Define the method of using the axe
3 public void useAxe();
4 }
Axe interface:

View Row Code
1 public interface Axe {
2 //There is a method for cutting in the Axe interface
3 public String chop();
4 }
The implementation class of Person.

View Row Code
1 public class Chinese implements Person {
2 private Axe axe;
3 private String name;
4
5 // Setter method required for value injection
6 public void setAxe(Axe axe) {
7 this.axe = axe;
8 }
9
10 public void setName(String name) {
11 this.name = name;
12 }
13
14 // Implement the userAxe method of the Person interface
15 public void useAxe() {
16 // Call the chop method of axe, indicating that the Person object depends on the Axe object
17 System.out.println(" I am "+name+" using "+axe.chop());
18 }
19
20 }
The above code implements the userAxe() method of the Person interface, and calls the chop() method of the axe when implementing this method, which is Typical dependencies.

The role of the Spring container here is to manage this invocation relationship in a loosely coupled way. In the Chinese class above, the Chinese class does not know where the axe instance it wants to call is, nor how the axe instance is implemented. It just needs to call an axe instance, which will be injected by the Spring container.

Axe implementation class: StoneAxe class

View Row Code
1 public class StoneAxe implements Axe{
2
3 public String chop() {
4 return "Stone axe is so slow to chop wood!!!";
5 }
6
7 }
Up to this point, the program still doesn't know that the Chinese class is coupled with the Axe instance, and neither does Spring! In fact, Spring requires an XML configuration file to specify dependencies between instances.

Spring uses XML files as configuration files.

The XML configuration file for this application is as follows:

View Row Code
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns:xsi="http://www.w3.org/2001/ XMLSchema-instance"
3 xmlns="http://www.springframework.org/schema/beans"
4 xsi:schemaLocation="http://www.springframework.org/schema/beans
5 http://www.springframework. org/schema/beans/spring-beans-3.0.xsd">
6
7 <!-- Configure Chinese instance, its implementation class is Chinese -->
8 <bean id="chinese" class="com.spring.service. impl.Chinese">
9 <!-- Inject StoneAxe into the axe property -->
10 <
11 <property name="name" value="Sun Wukong"/>
12 </bean>
13    
14    
15 <!-- configure the stoneAxe instance -->
16 <bean id="stoneAxe" class="com.spring.service. impl.StoneAxe" />
17 </beans>
In the configuration file, the Spring configuration bean instance usually specifies two attributes:

id: specifies the unique identifier of the bean, and the program will access the bean instance through the value of the id attribute.

class: Specifies the implementation class of the bean. The interface cannot be reused here. It must be the implementation class. The Spring container will use the XML parser to read the attribute value and use reflection to create an instance of the implementation class.

It can be seen from the above that the dependencies between beans and beans are organized in the configuration file, not written in the code. By specifying the configuration file, Spring can precisely inject properties for each bean. Therefore, the value of the class attribute of the <bean.../> element in the configuration file cannot be an interface, but must be a real implementation class.

Spring will automatically take over the definition of the <property.../> element in each <bean.../> definition. Spring will call the corresponding setter method to inject property values ​​into the program after calling the parameterless constructor and creating the default Bean instance. <property…/> The defined attribute value will no longer have the Bean to actively set and manage, but will accept Spring's injection.

The id attribute of each bean is the unique identification of the bean. The program accesses the bean through the id attribute, and the dependency between the bean and the bean is also associated with the id attribute.

Test program:

View Row Code
1 public class BeanTest {
2 public static void main(String[] args) {
3 //Create Spring container
4 ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
5 //Get Chinese instance
6 Person person = ctx.getBean("chinese",Person.class);
7 person.useAxe();
8 }
9
10 }
Execute the above program, the execution result is as follows:



When the main program calls the userAxe() method of Person, the method The Axe instance needs to be used in the body of the method, but there is nowhere in the program to couple a specific Person instance and Axe instance together, that is to say, the program does not pass in the Axe instance for the Person instance, and the Axe instance is injected by Spring during runtime.

Person instances not only do not need to know the specific implementation of Axe instances, but also do not even need to know the creation process of Axe. According to the specification of the configuration file, when the Spring container creates a Person instance, it not only creates the default instance of Person, but also injects the dependent Axe instance for the instance.

The dependency between beans and beans is managed by Spring. Spring uses the setter method to inject the dependent beans for the target Be Armani. This method is called setter injection.

From the above example, we can see that dependency injection manages the coupling between Bean instances with configuration files, so that the coupling between Bean instances is separated from the code hierarchy.

The Spring IoC container has the following three basic points:

1. Each component of the application program is interface-oriented. Interface-oriented programming can promote the coupling of each component to the interface level, which is beneficial to the later expansion of the project.

2. The components of the application are no longer actively generated by the program, but are generated and initialized by the Spring container.

3. Spring uses configuration files or Annotation to manage Bean implementation classes and dependencies. Spring container uses reflection mechanism to create time according to configuration files and inject dependencies into it.

Second, the construction injection

Construction injection is to use the constructor to set the way of dependencies.

Japanese class:

View Row Code
1 public class Japanese implements Person{
2
3 private Axe axe;
4 //Default constructor
5 public Japanese(){
6        
7 }
8    
9 //Constructor with parameters required for injection
10 public Japanese(Axe axe){
11 this.axe = axe;
12 }
13    
14 public void useAxe() {
15 System.out.println(axe.chop());
16 }
The Chinese class above does not have a setter method, It just provides a constructor with the Axe attribute, and Spring will inject the dependent Bean instance for Chinese through the constructor.

Constructing the injected configuration file requires some modification. To use constructor injection, use the <constructor-arg…/> element to specify the constructor arguments. As follows:

View Row Code
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xmlns= "http://www.springframework.org/schema/beans"
4 xsi:schemaLocation="http://www.springframework.org/schema/beans
5 http://www.springframework.org/schema/beans/spring -beans-3.0.

The element specifies a constructor parameter, and the parameter type is Axe, which specifies that Spring calls the constructor with an Axe parameter in the Chinese class to create a Chinese instance, because the constructor with parameters is used to create an instance, so when the Bean instance is created. After that, the dependencies of the Bean have been set up. Its execution effect is the same as that of Set Value Injection. But it is still a bit different: the timing of creating Axe properties in Person instances is different—the value injection type first creates a Bean instance through a parameterless constructor, and then invokes its setter method to inject dependencies, while construct injection directly invokes a Bean instance. The constructor of the parameter, when the Bean instance is created, the dependencies are also completed. 3. Comparison of the two injection methods Spring supports two dependency injection methods. These two dependency injection methods are not good or bad, but the suitable scenarios are different.
















Setting value injection has the following advantages:

1. It is more similar to the traditional JavaBean writing method, and it is easier for program developers to understand and accept. Setting dependencies through setter methods is more intuitive and natural.

2. For complex dependencies, if constructor injection is used, the constructor will be too bloated and difficult to read. When Spring creates a Bean instance, it needs to instantiate all the instances of its dependencies at the same time, resulting in performance degradation. Set value injection can avoid these problems.

3. Especially in the case of optional properties, the multi-parameter constructor is more cumbersome.

But the constructor also has the following advantages:

1. Constructor injection can determine the injection order of dependencies in the constructor, and prioritize the injection of dependencies.

2. For beans whose dependencies do not need to be changed, construct injection is more useful. Because there is no setter method, all dependencies are set in the constructor, so there is no need to worry about the subsequent code destroying the dependencies.

3. The dependencies can only be set in the constructor, and only the creator of the components can change the dependencies of the components. For the caller of the component, the dependencies inside the component are completely transparent, which is more in line with the principle of high cohesion.

through the above comparison. Therefore, it is recommended to use setting injection as the main injection strategy and construction injection as the supplementary injection strategy. For injections whose dependencies do not need to be changed, use construct injection as much as possible; for other dependencies, consider setting injection.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326463714&siteId=291194637