目录
依赖注入的概念
Spring的核心机制是依赖注入(Dependency Injection,DI),也称为控制反转(Inversion of Control,IOC)。
该篇文章接上篇Spring开发入门
首先再创建一个普通类
package org.example;
public class TestDao {
public String test(){
return "我不知道要干嘛了?";
}
}
重新修改TestHello类
package org.example;
public class TestHello {
private TestDao testDao;
//必须有
public void setTestDao(TestDao testDao) {
this.testDao = testDao;
}
public void testHello(){
System.out.println(testDao.test());
}
}
修改配置文件
修改applicationContext.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="TestHello" class="org.example.TestHello">
<!--property元素用来指定需要容器注入的属性,此处是设值注入,因此TestHello类中必须拥有setTestDao方法-->
<property name="TestDao">
<!--此处将另一个bean的引用注入给TestHello bean-->
<ref bean="TestDao"></ref>
</property>
</bean>
<bean id="TestDao" class="org.example.TestDao">
</bean>
</beans>
编写测试类
package org.example;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main( String[] args ) {
//获取ApplicationContext对象
ApplicationContext application=new ClassPathXmlApplicationContext("ApplicationContext.xml");
//通过ApplicationContext获得TestHello对象
//getBean()方法中的参数即为配置文件中Bean的id的值
TestHello testHello=(TestHello) application.getBean("TestHello");
testHello.testHello();
}
}
运行结果
分析
平常我们需要调用TestDao中的方法都是通过
//创建TestHello实列
TestDao testDao=new TestDao();
//调用方法
testDao.test();
但是我们在上面的程序中完全没有TestHello实例和TestDao实例耦合在一起。也就是,程序没有在TestHello实例中新创建一个TestDao实例,TestDao实例是由Spring在运行期间动态“注入”到TestHello实例中的。当程序运行到需要TestDao实例的时候,由Spring创建它,然后注入给需要它的调用者。当TestHello实例运行到需要TestDao实例的地方,自然就产生了TestDao来供其使用。这种产生实例的方式就称为依赖注入。可以发现,在TestHello中应用TestDao时,生成了其实例的setter方法,Spring正是通过这个setter方法为TestDao创建实例的。
依赖注入的两种方式
set注入
上面介绍的就是set注入,下面介绍构造注入方式。
构造注入
构造注入是指在接受注入的类中定义一个构造方法,并在构造方法的参数中定义需要注入的元素。
依旧以上面的例子来展开,首先修改TestHello.java类,在该类中增加一个构造方法
package org.example;
public class TestHello {
private String message;
//构造方法
public TestHello(String message) {
this.message = message;//构造注入
}
public String getMessage() {
return message;
}
}
修改ApplicationContext.xml文件
constructor-arg:表示通过构造方式来进行依赖注入; index=0:表示构造方法中的第一个参数,可省略不写。如果有多个参数,就直接重复配置constructor-arg即可,不过要改变index的值。例如,如果在TestHello类中还有一个参数sex,并且通过构造方法为其注入值:public TestHello(String message,String sex) { this.message = message;//构造注入 this.sex=sex; }
那么需要在配置文件ApplicationContext.xml文件中加上一个constructor-arg
<bean id="TestHello" class="org.example.TestHello"> <constructor-arg index="0"> <value>我知道我要干嘛了!当然是学习啦!</value> </constructor-arg> <constructor-arg index="1"> <value>女</value> </constructor-arg> </bean>
<?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="TestHello" class="org.example.TestHello">
<constructor-arg index="0">
<value>我知道我要干嘛了!当然是学习啦!</value>
</constructor-arg>
</bean>
</beans>
运行结果
两种注入方式的比较
使用构造注入可以在构建对象的同时一并完成依赖关系的建立,所以如果要建立的对象的关系很多,使用构造注入就会在构造方法上留下很多参数,方法可读性差,这是建议使用set注入。然而,用set注入由于提供了setXX()方法,所以不能保证相关的数据在执行时不被更改设定,因此,如果想要让一些数据变为只读或私有,使用构造注入会是一个好的选择。