Configuration of dependency injection
Spring's dependency injection includes constructor based dependency injection and setter based dependency injection.
Constructor based dependency injection
<!-- Dependency injection via constructor parameter index --> <bean id="byIndex" class="cn.javass.spring.chapter3.HelloImpl3"> <constructor-arg index="0" value="Hello World!"/> <constructor-arg index="1" value="1"/> </bean> <!-- Dependency injection by constructor parameter type --> <bean id="byType" class="cn.javass.spring.chapter3.HelloImpl3"> <constructor-arg type="java.lang.String" value="Hello World!"/> <constructor-arg type="int" value="2"/> </bean> <!-- Dependency injection by constructor parameter name --> <bean id="byName" class="cn.javass.spring.chapter3.HelloImpl3"> <constructor-arg name="message" value="Hello World!"/> <constructor-arg name="index" value="3"/> </bean> <!-- Injection by static factory method --> <bean id="byName" class="cn.javass.spring.chapter3.HelloImpl3" factory-method="getBean"> <constructor-arg name="message" value="Hello World!"/> <constructor-arg name="index" value="3"/> </bean>
Dependency injection based on setter method
<bean class="...HelloImpl4"> <property name="message" value="Hello"/> <property name="index" value="1"/> //The values in value are all in the form of strings. If the conversion fails, an exception will be reported </bean> <bean id="Hello2" class="com.csx.personal.web.services.HelloImpl2"> <property name="msg" ref="message"/> //msg attribute is a class object </bean>
Circular dependency: Bean B is required to create Bean A, Bean C is required to create Bean B, and Bean A is required to create Bean C, thus forming circular dependency. Spring's solution: when spring creates A Bean, it will maintain A pool. When it creates A, it will go to the pool to find out whether A is in the pool. If it finds out, it will throw A circular dependency exception.
Avoid circular dependency in dependency injection: you can use setter injection instead of constructor injection.
Common columns of dependency configuration
Constant value injection configuration
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <!-- results in a setDriverClassName(String) call --> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mydb"/> <property name="username" value="root"/> <property name="password" value="masterkaoli"/> </bean>
Inject other beans
Here is a column that references the current container and the Bean in the parent container.
<bean id="Hello2" class="com.csx.personal.web.services.HelloImpl2"> <property name="msg"> //msg attribute is a class object <ref bean="message"/> //Reference the Bean with id="message" in the same container </property> </bean> <!-- References in the parent container Bean --> <!-- in the parent context --> <bean id="accountService" class="com.something.SimpleAccountService"> <!-- insert dependencies as required as here --> </bean> <!-- in the child (descendant) context --> <bean id="accountService" <!-- bean name is the same as the parent bean --> class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"> <ref parent="accountService"/> <!-- notice how we refer to the parent bean --> </property> <!-- insert other configuration and dependencies as required here --> </bean>
Inject internal Bean
Internal bean: this kind of bean is generally only used by one external bean (similar to the internal class), not by other beans in the container.
<bean id="outer" class="..."> <property name="target"> <!-- this is the inner bean --> <bean class="com.example.Person"> <property name="name" value="Fiona Apple"/> <property name="age" value="25"/> </bean> </property> </bean>
Injection of set
util namespace is recommended for injection of collection classes
<util:map id="myMap" key-type="java.lang.String" value-type="java.lang.String"> <entry key="key1" value="chen"/> <entry key="key2" value="zhao"/> </util:map> <util:list id="myList" value-type="java.lang.String"> <value>chen</value> <value>zhao</value> </util:list> <util:set id="mySet" value-type="java.lang.String" scope="singleton"> <value>chen</value> <value>zhao</value> </util:set> <util:properties id="myProp" location="classpath:xx.properties"/>
Injection of null values and empty strings
<bean class="...HelloImpl4"> <property name="message"><null/></property> //null value <property name="index" value=""/> //Empty string </bean>
Using the dependencies on attribute
The dependencies on property specifies the order in which the beans are initialized. This property only works for beans whose scope is a single column.
<!--In instantiation beanOne Instantiate before manager and accountDao these two items. bean--> <bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao"> <property name="manager" ref="manager" /> </bean> <bean id="manager" class="ManagerBean" /> <bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
Lazy load
There is a lazy init property in the definition of bean, which is used to set whether a single column bean instantiates the bean after container initialization. By default, the container instantiates all the singleton beans, which is also recommended because it can find out whether the bean configuration is correct in the initialization phase of the container. If a Bean is set to true according to the following settings, lazy-init will not be pre initialized by the container and will only be initialized when it is used. However, if a single column class depends on the bean, the bean set to lazy loading will still be pre initialized.
<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
If you want to set a global single Bean without pre initialization, you can set it in xml as follows:
<beans default-lazy-init="true"> <!-- no beans will be pre-instantiated... --> </beans>
Autowiring related
When we want to inject another bean into one property of A bean, we will use the form of property +ref tag. But for large projects, suppose that A bean A is injected by multiple bean references. If the id of A is modified for some reason, then all the ref tags of the beans that reference A must be modified. At this time, if autowire="byType" is used, then the beans that reference A need not be modified at all.
<! -- the usage of autowire is as follows: configure the autowire mode for a Bean -- > <! -- same as adding @ AutoWired annotation to Bean's attributes -- > <bean id="auto" class="example.autoBean" autowire="byType"/>
Several modes of autowire:
- no mode: it is also the default mode. In this mode, automatic attribute injection will not be carried out. We need to configure it through the value or ref attribute ourselves;
- byName pattern: by automatically assembling the name of the attribute, Spring will find the bean whose name is consistent with the bean attribute name in the container and inject it into the bean attribute automatically. Of course, bean properties need to have setter methods. For example: bean A has A property master, and the setter method of master is setMaster. If autowire="byName" is set in A, then Spring will find the bean named master in the container and inject it into A through setMaster method;
- byType: automatic assembly (injection) by type. Spring will find the bean whose Class is consistent with the bean property Class in the container and inject it into the bean property automatically. If the container contains multiple beans of this type, spring will throw an exception. If no bean of this type is found, the injection action will not be executed;
- Constructor: similar to byType, but matched by the parameter type of the constructor. Suppose bean A has constructor A(B b, C c), then Spring will find beans of type B and C in the container and inject them into A through constructor A(B b, C c). As with byType, if there are multiple beans of type B or C, an exception will be thrown. However, unlike byType, if A bean of A matching class cannot be found in the container, an exception will be thrown because Spring cannot call the constructor to instantiate the bean;
- Default: use the configuration of the parent label (that is, the default autowire attribute of the beans label).
It should be noted that we need to provide the corresponding setter methods for the above 5 ways of injection, and do not need to provide the corresponding setter methods through @ Autowired.
Disadvantages of automatic assembly
- Explicit dependencies in property and constructor parameter settings override automatic assembly;
Exclude beans from automatic assembly
If a Bean is configured as follows, it will not be a candidate for automatic assembly. But autowire candidate will automatically take effect on the byType form of auto injection. If we use the byName form of auto injection, we can still inject this Bean.
<bean id="auto" class="example.autoBean" autowire="byType" autowire-candidate="false"/>
If we only want some beans as candidates for automatic assembly, we can make global settings. If the following configuration is made, only beans with id of bean1 and bean2 will become candidate beans for automatic assembly. At the same time, the value of default autowire candidates supports regular expression form. However, it is strongly recommended not to configure the value of this option, just use the default configuration.
<beans default-autowire-candidates="bean1,bean2"> </beans>
Method injection (singleton dependent prototype Bean)
When we configure a bean, we should first consider whether the bean should be configured as a singleton mode or other modes. In our application, most classes are singleton classes. When a singleton class refers to a singleton class, or a prototype class refers to a prototype class or singleton class, we just need to configure it as usual. However, when a singleton class references a prototype class, there will be problems. This can be injected in the following way.
@Service @Scope("prototype") public class MyService1 { public void service() { System.out.println(this.toString() + ":id"); } } @Service public abstract class MyService { private MyService1 service1; public void useService(){ service1 = createService1(); service1.service(); } @Lookup("myService1") public abstract MyService1 createService1(); } //You can also configure bean s in this way <bean id="serviceC" class="com.csx.demo.springdemo.service.ServiceC"> <lookup-method bean="serviceD" name="createService"/> </bean> <bean id="serviceD" class="com.csx.demo.springdemo.service.ServiceD" scope="prototype"/>