设值注入:
也称属性注入,是指通过setter()方法传入被调用者的实例。这种注入方式简单、直观,在Spring依赖注入中也是最常用的。
public interface Animal {
public void eatFood();
}
public interface Action {
public void eat();
}
public class Cat implement Animal {
private Action action;
public Cat() {}
public void setAction(Action action) {
this.action = action;
}
public void eatFood() {
System.out.println(action.eat());
}
}
public class CatAction implement Action {
public CatAction(){}
public String eat() {
return "猫吃鱼";
}
}
采用Spring配置文件将Animal实例与Action实例组织起来:
bean.xml:Spring配置文件
<beans>
<bean id="cat" class="Cat">
<property name="action">
<ref local="catAction"><!-- 将两一个Bean的引用注入给cat bean-->
</property>
</bean>
<bean id="catAction" class="CatAction">
</beans>
配置文件的Bean的class不能仅仅是接口,而必须是真正的实现类。接口是不能被直接实例化的,只能实例化该接口的实现类。
Spring会自动接管每个Bean定义里面的<property>元素定义。Spring会在执行无参构造器后、创建默认的Bean的实例后,调用相应的setter()方法为程序注入属性值。property定义的属性值将不在由该Bean来主动创建和管理,而改为被动接受Spring注入。
每个Bean的id属性是该Bean的唯一标识,程序通过id属性访问Bean,bean与bean的依赖关系也通过Id属性建立。
public static void main(String[] args) {
ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");
Animal animal = (Animal)ctx.getBean("cat");
cat.eatFood();
}
调用者无需了解被调用者的实现过程,连工厂定位都可以圣罗。如果需要改写Action的实现类或者说需要提供给Animal另一个Action的实现类,Animal接口和Cat实现类都无需修改,只需要提供Action的另一个实现,然后通过配置文件进行简单修改即可。
Animal和Action之间没有任何的代码耦合,Bean和Bean之间的依赖关系交由Spring进行管理,采用Setter方法为目标Bean注入属性的方式成为设值注入。业务对象的变换变得简单,对象与对象之间的依赖关系从代码里分离出来,通过配置文件动态管理。
构造注入:
指通过构造方法完成依赖关系的设定,而不是通过setter()方法。
public class Dog implement Animal {
private Action action;
public Dog(){}
public Dog(Action action) {
this.action = action;
}
public void eatFood() {
System.out.pringln(this.action.eat());
}
}
<beans>
<bean id="dog" class="Dog">
<constructor-arg><ref bean="dogAction" /></constructor-arg>
</bean>
</beans>
执行效果与设值注入相同,区别在于创建Animal实例时,action属性赋值的时机不同,设值注入需要某一个bean实例时创建一个默认的bean的实例,然后调用相应的设值方法,注入依赖关系。而构造注入则是在创建bean实例时,已经完成依赖关系的注入。
优缺点:
设值注入:与传统Javabean的写法更加相近,开发人员更容易理解和接受,通过setter()方法射钉起来关系显得更加直观和自然。 对于复杂的依赖关系,如果采用构造注入,会导致构造器过于臃肿,难以阅读,Spring在创建Bean实例时,需要同时实例化期以来的全部实例,因而导致性能下降。而是用设值注入则能避免这些问题。 尤其是在某些属性可选的情况下,多参数的构造器更加笨重。
构造注入:可以再构造器中决定依赖关系的注入顺序。对于依赖关系无需变化的bean,构造注入更有用。因为没有setter()方法,所有的依赖关系全部在构造器内设定,因此,无须担心后续的代码对依赖关系产生破坏。依赖关系只能在构造器内设定,则只有组件的创建者才能改变组件的依赖关系。对组件的调用者而言,组件内部的依赖关系完全透明,更符合高内聚的原则。建议采用设置注入为主,构造注入为辅的注入策略。对于依赖关系无需变化的注入,尽量采用构造注入;而对于其他的依赖关系的注入,则考虑采用设值注入。