First of all, to learn how to inject beans in Spring, you must first understand what dependency injection is. Dependency injection refers to: let the calling class inject the dependency of the implementation class of the implementation class of a certain interface by a third party, thereby eliminating the dependence of the calling class on the implementation class of a certain interface.
The dependency injection methods supported in Spring containers mainly include property injection, constructor injection, and factory method injection. Next, we will introduce these three dependency injection methods and their specific configuration methods in detail.
1. Attribute injection
Attribute injection means injecting the attribute value or dependent object of the bean through the setXXX( ) method. Since the attribute injection method is selective and flexible, it is also the most commonly used injection method in actual development.
Spring will first call the bean's default constructor to instantiate the bean object, and then call the set method through the reflected method to inject the property value.
Property injection requires the bean to provide a default constructor and must provide a set method for the properties that need to be injected.
TIps: the so-called default constructor, that is, a constructor without parameters. If there is no custom constructor in the class, the system (JVM) will automatically generate a default constructor without parameters. If the constructor with parameters is explicitly customized in the class, the system will not automatically generate the default constructor, and you need to manually add a constructor without parameters.
The following is an example to demonstrate the property injection method of beans in Spring:
Write a user class:
package com.Kevin.bean;/** * Create a class test bean property injection method* @author Kevin * */public class User { private String username; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; }}Configuration file:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <!-- configuration object --> <bean id="user"> <property name="username"> <value>Kevin</value> </property> </beans>
Among them, each property value corresponds to a property tag, and the name property value is the name of the property in the class. In the bean implementation class, it has the corresponding implementation method setUsername( ).
Tips: Spring will only check whether the bean contains a setter method, and does not make specific requirements for whether there are corresponding attribute variables. However, according to the conventional rules, we should set the corresponding attribute variables for it.
Naming specifications for <property> tags in Spring:
Generally speaking, Java attribute variable names start with lowercase letters, but considering some English abbreviations with special meanings, Java beans also allow variable names starting with uppercase letters. But the following two points must be met:
For attribute injection methods, guarantees can only be provided in the configuration file artificially, but guarantees cannot be provided at the syntax level. At this time, you need to use constructor injection to better meet the requirements.
2. Constructor injection
Constructor injection is another commonly used injection method besides attribute injection. It can ensure that some necessary properties are set when beans are instantiated and can be used after instantiation.
The prerequisite for using constructor injection is that the bean must provide a constructor with arguments.
For constructor injection, configuration files can be used in the following ways:
【Match parameter entry method by type】
Write bean code:
package com.Kevin.bean;/** * Write bean test to match parameters by type* @author Kevin * */public class Person { private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; }}Write configuration files:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <!-- configuration object --> <bean id="person"> <constructor-arg type="String"> <value>Kevin</value> </constructor-arg> <constructor-arg type="Integer"> <value>20</value> </constructor-arg> </beans>
Spring's configuration files adopt configuration strategies that are independent of the order of element labels, so the certainty of configuration information can be guaranteed to a certain extent.
Then when multiple type parameters of the constructor in a bean are the same, it is easy to cause confusion by matching parameters according to type. At this time, another method is needed: matching parameters according to index.
【Match parameters according to index】
Write bean code:
package com.Kevin.bean;/** * Write bean tests and parameters in the index method* @author Kevin * */public class Student { private String name; private String gender; private Double score; public Student(String name, String gender, Double score) { super(); this.name = name; this.gender = gender; this.score = score; }}The configuration file is written as follows:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <!-- configuration object --> <bean id="student"> <constructor-arg index="0" value="Kevin"></constructor-arg> <constructor-arg index="1" value="Male"></constructor-arg> <constructor-arg index="2" value="66"></constructor-arg> </bean> </beans>
Tips: During property injection, Spring determines the configuration attribute and the corresponding setter method according to the specifications of the java bean, and uses the java reflection mechanism to call the attribute's setter method to complete the property injection. However, the Java reflection mechanism does not remember the constructor's parameter name, so we cannot configure the constructor by formulating the constructor's parameter name, so we can only indirectly complete the constructor's property injection through the parameter type and index.
【Combined use type and index matching parameters】
In some complex configuration files, type and index are required to be used simultaneously to complete the parameter injection of the constructor. Here is an example to demonstrate.
Write beans:
package com.Kevin.bean;/** * Write bean tests to use type and index matching parameters together* @author Kevin * */public class Teacher { private String name; private String address; private double salary; private int age; public Teacher(String name, String address, double salary) { super(); this.name = name; this.address = address; this.salary = salary; } public Teacher(String name, String address, int age) { super(); this.name = name; this.address = address; this.age = age; }}In this class, there are two overloaded constructors, and they all have three parameters. In this case, using the type and index methods cannot complete the requirements. At this time, both of their properties need to be used at the same time.
Configuration file:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <!-- configuration object --> <bean id="teacher"> <constructor-arg index="0" type="String"> <value>Kevin</value> </constructor-arg> <constructor-arg index="1" type="String"> <value>China</value> </constructor-arg> <constructor-arg index="2" type="int"> <value>20</value> </constructor-arg> </bean> </beans>
You can see that the focus is actually on the type of the third parameter, so we specify the index and type in the configuration file, so that Spring can know which constructor to inject parameter.
Tips: Add to our configuration file, there is an ambiguity problem. The Spring container can be started normally and will not report an error. It will randomly use a matching constructor to instantiate the bean. The randomly selected constructor may not be needed by the user, so we should be careful to avoid this ambiguity when programming.
【Match parameters through its own type reflection】
If the type of the bean constructor parameter is discernible, since the Java reflection mechanism can obtain the type of the constructor parameter, even if the injection of the constructor does not provide type and index information, Spring can still complete the injection of constructor information. For example, in the following example, the parameter type of the constructor of the Manager class can be distinguished.
Write Manager class:
package com.Kevin.bean;/** * Write a bean test to match arguments through its own type reflection* @author Kevin * */public class Manager { private String name; private Double salary; private Person person; public Manager(String name, Double salary, Person person) { super(); this.name = name; this.salary = salary; this.person = person; } }Write configuration files:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <!-- configuration object --> <bean id="manager"> <constructor-arg> <value>Kevin</value> </constructor-arg> <constructor-arg> <ref bean="user"/> </constructor-arg> <constructor-arg> <ref bean="person"/> </constructor-arg> </beans>
The above methods can implement the injection of constructor parameters, but in order to avoid the occurrence of problems, it is recommended to use explicit index and type to configure the constructor parameter entry information.
3. Factory method injection
The factory method is a design pattern that is often used in applications and is also the main method of implementing the idea of control inversion and single-instance design. The factory class is responsible for creating one or more factory class instances. The factory class method generally returns the target class instance in the form of an interface or abstract class variable.
The factory class blocks the instantiation steps of the target class externally, and the caller does not even have to specify what the specific target class is. Because Spring containers provide the functionality of factory methods in framework methods and are open to developers in a transparent way. Therefore, it is rarely necessary to write engineering methods manually. However, engineering methods will still be encountered in some legacy systems or third-party library. At this time, Spring factory injection method can be used to inject Spring.
Spring factory injection methods can be divided into static and non-static.
【Non-static factory method】
Some factory methods are non-static and must be instantiated before factory methods can be called. The following is an example to demonstrate.
Write factory class:
package com.Kevin.factorybean;/** * Write factory class tests non-static factory method injection* @author Kevin * */public class BookFactory { public Book buyBook(){ Book book = new Book(); book.setName("Think in Java"); return book; }}Configuration file writing:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <!-- configuration object --> <bean id="bookFactory"></bean> <bean id="book" factory-bean="bookFactory" factory-method="buyBook"></bean> </beans>
Since the factory method of bookFactory is not static, you need to first define a bean of the factory class, and then refer to the factory bean instance through the factory-bean property. Then, the corresponding factory-method is used to specify the corresponding factory method.
【Static Factory Method】
Many factory class methods are static, which means that factory class methods can be called without creating factory class instances. Therefore, static engineering methods are more convenient and concise than non-static factory methods. The following is an example to demonstrate the static factory method.
Write factory class:
package com.Kevin.factorybean;/** * Write factory class test static factory method injection* @author Kevin * */public class CarFactory { public static Car createCar(){ Car car = new Car(); car.setBrand("Lamborghini"); return car; }}Write configuration files:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <!-- configuration object --> <bean id="car" factory-method="createCar"></bean> </beans>
Summarize
Spring provides three optional injection methods, but in actual applications, there is no unified standard for which injection method we should choose. Here are some reasons to refer to:
Reason for constructor injection:
Properties injection reason:
In fact, Spring provides us with so many methods for injecting parameters, so these methods must have their own reasons. Each method has unique advantages in a certain issue. We only need to choose the appropriate method according to our specific usage needs, but factory method injection is generally not recommended.
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.