Spring支持三种依赖注入的方式。
1. 属性注入
属性注入是通过JavaBean的setter方法注入Bean的属性值或依赖的对象。属性注入是使用元素,使用name属性指定Bean的属性名称,value属性或者子节点指定属性的值。是实际应用中常用的注入方式。
属性注入的例子如下,在src目录下新建com.spring.beans的包,在该包下新建SmartPhone.java类,代码如下:
package com.spring.beans;
public class SmartPhone {
private String brand;
private int price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "SmartPhone [brand=" + brand + ", price=" + price + "]";
}
}
在src目录下新建applicationContext1.xml的配置文件,代码如下,其中bean中的class为SmartPhone的全类名。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="smartPhone" class="com.spring.beans.SmartPhone">
<property name="brand" value="Huawei"></property>
<property name="price">
<value>2500</value><!-- 采用value子节点的方式赋值 -->
</property>
</bean>
</beans>
新建主类Main.java,代码如下:
package com.spring.beans;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext1.xml");
SmartPhone smartPhone = (SmartPhone)ctx.getBean("smartPhone");
System.out.println(smartPhone);
}
}
运行后输出如下结果:
2. 构造器注入
构造器注入是通过构造方法注入Bean的属性值,它保证了Bean实例在实例化后就可以使用。构造器注入在元素里声明属性,该标签里没有name属性。如果JavaBean中只有构造器注入的方式,如下代码:
package com.spring.beans;
public class SmartPhone {
private String brand;
private int price;
public SmartPhone(String brand, int price) {
super();
this.brand = brand;
this.price = price;
}
@Override
public String toString() {
return "SmartPhone [brand=" + brand + ", price=" + price + "]";
}
}
则applicationContext1.xml配置文件中内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="smartPhone1" class="com.spring.beans.SmartPhone">
<constructor-arg value="Galaxy"></constructor-arg>
<constructor-arg value="5000"/>
</bean>
</beans>
同样在主方法中采用获取Bean的id的方式,打印输出下面的结果:
如果同时采用了属性注入和构造器注入的方式,则此时要特别注意,在加入有参构造方法之后,务必再写一个无参的构造方法。混合使用时JavaBean中代码如下:
package com.spring.beans;
public class SmartPhone {
private String brand;
private int price;
public SmartPhone() {
}//混合使用时必须加上无参构造方法,否则报错。
public SmartPhone(String brand, int price) {
super();
this.brand = brand;
this.price = price;
}//构造器注入
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "SmartPhone [brand=" + brand + ", price=" + price + "]";
}
}
则applicationContext1.xml配置文件中的代码:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="smartPhone" class="com.spring.beans.SmartPhone">
<property name="brand" value="Huawei"></property>
<property name="price">
<value>2500</value><!-- 采用value子节点的方式赋值 -->
</property>
</bean>
<bean id="smartPhone1" class="com.spring.beans.SmartPhone">
<constructor-arg value="Galaxy"></constructor-arg>
<constructor-arg value="5000"/>
</bean>
</beans>
Main.java中代码:
package com.spring.beans;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext1.xml");
SmartPhone smartPhone = (SmartPhone)ctx.getBean("smartPhone");
System.out.println(smartPhone);
SmartPhone smartPhone1 = (SmartPhone)ctx.getBean("smartPhone1");
System.out.println(smartPhone1);
}
}
运行得到如下结果:
由此我们可以知道,当只使用属性注入方式时,由于Java类中存在一个默认的无参构造方法,所以我们不需要单独再写出来,从而也证明属性注入方式是依赖于无参构造方法的。当仅仅使用构造器注入方式时,只需要一个有参的构造方法即可。但当两者混合使用时,由于构造器注入方式的有参构造方法的存在,Java不再提供无参构造方法,所以我们得单独写一个无参构造器。否则报不存在无参构造器的错误。
通过上述的例子也可以知道构造器注入方式是根据参数的顺序来赋值的。但是如果构造器有重载怎么办?
在com.spring.beans包下新建一个Car.java类:
package com.spring.beans;
public class Car {
private String brand;
private String corp;
private int price;
private double maxSpeed;
public Car(String brand, String corp, int price) {
super();
this.brand = brand;
this.corp = corp;
this.price = price;
}
public Car(String brand, String corp, double maxSpeed) {
super();
this.brand = brand;
this.corp = corp;
this.maxSpeed = maxSpeed;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", corp=" + corp + ", price=" + price + ", maxSpeed=" + maxSpeed + "]";
}
}
该类中有重载的构造方法,applicationContext1.xml配置文件中代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="car" class="com.spring.beans.Car">
<constructor-arg value="Audi" index="0"></constructor-arg>
<constructor-arg value="Shanghai" index="1"></constructor-arg>
<constructor-arg value="3000" index="2"></constructor-arg>
</bean>
<bean id="car2" class="com.spring.beans.Car">
<constructor-arg value="bens"></constructor-arg>
<constructor-arg value="German"></constructor-arg>
<constructor-arg value="50"></constructor-arg>
</bean>
</beans>
虽然第二个bean标签是为了调用第二个构造器,但无疑这两个bean都会去匹配第一个构造器,如下运行结果:
这时可以在constructor-arg标签中加入type的属性来标识不同的构造器,将applicationContext1.xml改成如下形式:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="car" class="com.spring.beans.Car">
<constructor-arg value="Audi" ></constructor-arg>
<constructor-arg value="Shanghai" ></constructor-arg>
<constructor-arg value="3000" type="int"></constructor-arg>
</bean>
<!-- <bean id="car" class="com.spring.beans.Car">
<constructor-arg value="Audi" index="0"></constructor-arg>
<constructor-arg value="Shanghai" index="1"></constructor-arg>
<constructor-arg value="3000" type="int"></constructor-arg>
</bean> --><!--使用构造器注入属性值可以指定参数的位置和参数的类型,以区分重载的构造器,这两者也可以混合使用,像本段注释的代码,也是正确的。 -->
<bean id="car2" class="com.spring.beans.Car">
<constructor-arg value="bens" type="java.lang.String"></constructor-arg>
<constructor-arg value="German" type="java.lang.String"></constructor-arg>
<constructor-arg type="double">
<value>50</value><!--可使用value子节点 -->
</constructor-arg>
</bean>
</beans>
则运行主方法后结果显示:
字面值即可用字符串表示的值,可以通过元素标签或value属性进行注入。基本数据类型和其封装类,String等类型都可以采取字面值注入的方式。若字面值包含特殊字符,可以使用<![CDATA[]]>把字面值包裹起来。比如说要输出尖括号,如下,bean标签中配置:
<bean id="car2" class="com.spring.beans.Car">
<constructor-arg value="bens" type="java.lang.String"></constructor-arg>
<constructor-arg type="java.lang.String">
<value><![CDATA[<German>^]]></value>
</constructor-arg>
<constructor-arg type="double">
<value>50</value><!--可使用value子节点 -->
</constructor-arg>
</bean>
主函数中输出:
3. 工厂方法注入
工厂方法注入一般不使用,感兴趣的读者可自行百度学习。