-
项目开发中,单个实例并不仅存在基本类型属性,亦或存在其他类型实例。Spring可对其进行初始化赋值,也被称为注入。此实例之创建,需其他实例作为属性方可,故称此示例依赖其他实例而存在,故构成依存关系。
-
依赖注入如上文所说,一对象依赖某其他对象,则对此对象注入其他对象至引用中。被依赖只对象只可通过构造参数、工厂方法参数、或在对象set方法的途径赋值到依赖对象中。
-
依赖注入称为DI,此类方式可使对象并为察觉所依赖对象位置或类型即可获取其实例,简化代码的同时耦合度响应降低,因注入的可能是属性的子类类型,故可能性较多的,但通过依赖注入可降低耦合度,灵活控制对象的创建。
-
DI主要借助构造方法注入与set方法注入。
构造方法注入
-
通过构造方法注入要求类中存在公开有参构造,参数用于向对象类型属性赋值。
-
构造方法中参数的匹配是通过类型进行的,即相应类型参数对相应类型属性。此实例由Spring创建,在xml文件中使用constructor-arg标签在bean中注入。如果构造函数参数类型相同,则标签的顺序即为赋值的顺序。
package x.y; public class ThingOne { public ThingOne(ThingTwo thingTwo, ThingThree thingThree) { // 对参数的操作或赋值 } }
<beans> <bean id="beanOne" class="x.y.ThingOne"> <constructor-arg ref="beanTwo"/> <constructor-arg ref="beanThree"/> </bean> <bean id="beanTwo" class="x.y.ThingTwo"/> <bean id="beanThree" class="x.y.ThingThree"/> </beans>
-
还可通过类型指定的方式进行属性赋值,如true一字,可为String亦可为boolean,具体类型可在constructor-arg标签中借助type属性进行指定:
<bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg type="int" value="7500000"/> <constructor-arg type="java.lang.String" value="42"/> </bean>
-
若多个参数类型相同,还要进行指定参数的赋值,则需通过下标的方式进行设置,下标使用index属性指定,起始值为0:
<bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg index="0" value="7500000"/> <constructor-arg index="1" value="42"/> </bean>
-
还可通过使用name属性指定参数名称来进行设置:
public ExampleBean(int years, String ultimateAnswer) { this.years = years; this.ultimateAnswer = ultimateAnswer; }
<bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg name="years" value="7500000"/> <constructor-arg name="ultimateAnswer" value="42"/> </bean>
使用参数名的方式配置,需开启debug模式运行程序,以便Spring获取构造函数,且在其中获取其名。如果要直接运行程序且使用参数名的方式,要在构造函数中使用ConstructorProperties注解指定参数名:
@ConstructorProperties({"years", "ultimateAnswer"}) public ExampleBean(int years, String ultimateAnswer) { this.years = years; this.ultimateAnswer = ultimateAnswer; }
Setter方法注入
-
在进行注入时,若为强制性注入即必要此属性存在对象,则可使用构造函数注入方式。若为可选择方式,即可为空的属性注入,则使用setter方法注入。但可在set方法上添加@Required注解,将此set方法定为必要注入项。
-
Spring团队提倡构造函数注入,因为可确保对象实现不可变,并确保不存在必需的null内容。并且构造函数注入方式使创建的实例以完全初始化的状态进行调用。
-
默认情况下,Spring可以将注入的String类型的值与其他基本类型进行转换然后注入。
-
循环依赖问题要注意,例如A类中存在属性B,B类中存在属性A,然后将两个类之间相互进行注入则会发生循环注入问题,将出现BeanCurrentlyInCreationException。避免这种问题可使用setter方式注入,或者采用不同的构造函数进行循环依赖。
-
在进行注入之前,会先将需要到的实例进行创建,然后再向属性中注入。
-
在进行setter方法进行注入的时候,可在bean中添加property标签,其中可直接指定属性名称,将自动调用其set方法,必须保证其拥有响应set方法。value属性可对基本类型进行赋值,ref可借鉴其他bean标签所创建的实例进行注入。
public class A { B b; int age; public void setB(B b) { this.b = b; } public void setAge(int age) { this.age = age; } }
<bean id="createA" class="bean.A"> <property name="b" ref="createB"></property> <property name="age" value="10"></property> </bean> <bean class="bean.B" id="createB"></bean>
-
还可将ref作为一个标签写在property标签之中,使用bean属性指定将注入的bean标签标识:
<bean id="createA" class="bean.A"> <property name="b"> <ref bean="createB"></ref> </property> <property name="age" value="10"></property> </bean> <bean class="bean.B" id="createB"></bean>