spring——依赖注入
http://blog.csdn.net/lishuangzhe7047/article/details/20740835
http://blog.163.com/taodengwen@126/blog/static/87199341201191383429693/
spring框架为我们提供了三种注入方式,分别是set注入,构造方法注入,接口注入。接口注入不作要求,下面介绍前两种方式。
1,set注入
采用属性的set方法进行初始化,就成为set注入。
1)给普通字符类型赋值。
public class User{ privateString username; publicString getUsername() { returnusername; } publicvoid setUsername(String username) { this.username= username; } }
我们只需要提供属性的set方法,然后去属性文件中去配置好让框架能够找到applicationContext.xml文件的beans标签。标签beans中添加bean标签, 指定id,class值,id值不做要求,class值为对象所在的完整路径。bean标签再添加property 标签,要求,name值与User类中对应的属性名称一致。value值就是我们要给User类中的username属性赋的值。
public class User{ private UserService userservice; public UserServicegetUserservice() { returnuser; } public void setUserservice(UserService userservice){ this.userservice= userservice; } }
配置文件中要增加UserService的bean标签声明及User对象对UserService引用。
public class User{ privateList<String> username; publicList<String> getUsername() { returnusername; } publicvoid setUsername(List<String> username) { this.username= username; } }
public class User{ privateProperties props ; publicProperties getProps() { returnprops; } publicvoid setProps(Properties props) { this.props= props; } }
public class User{ privateString usercode; publicUser(String usercode) { this.usercode=usercode; } }
- <bean id="userAction"class="com.lsz.spring.action.User">
- <constructor-argvalueconstructor-argvalue="admin"></constructor-arg>
- </bean>
2)构造函数有两个参数时
当参数为非字符串类型时,在配置文件中需要制定类型,如果不指定类型一律按照字符串类型赋值。
当参数类型不一致时,框架是按照字符串的类型进行查找的,因此需要在配置文件中制定是参数的位置
- <constructor-argvalueconstructor-argvalue="admin"index="0"></constructor-arg>
- <constructor-argvalueconstructor-argvalue="23" type="int"index="1"></constructor-arg>
这样制定,就是构造函数中,第一个参数为string类型,第二个参数为int类型
控制反转与依赖注入
控制反转(IoC/Inverse Of Control): 调用者不再创建被调用者的实例,由spring框架实现(容器创建)所以称为控制反转。
依赖注入(DI/Dependence injection) : 容器创建好实例后再注入调用者称为依赖注入。
当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例,。如果创建被调用者实例的工作不再由调用者来完成,而是由外部容器完成,因此称为控制反转; 创建被调用者 实例的工作通常由外部容器来完成,然后注入调用者,因此也称为依赖注入。
下面一个小实例:
定义一个接口
public interface Person {
void sayHello();
}
第一个实现类:
public class Chinese implements Person {
public void sayHello() {
System.out.println("您好 !");
}
}
第二个实现类:
public class American implements Person {
public void sayHello() {
System.out.println("How do you do .");
}
}
注意这个类与传统设计有什么区别:该类调用Person子类的方法,传统设计在本类中创造实例,而在此类里并没有创造实例
public class User {
Person p;
public Person getP() {
return p;
}
//使用setter注入
public void setP(Person p) {
this.p = p;
}
//调用person子类重写的sayHello方法,这里的p并没有实例化
public void function(){
p.sayHello();
}
}
外部‘容器’
public class Container{
public static User getBean(){
Person p=new Chinese();
User user = new User();
//由容器‘注入’实例
user.setP(p);
return user;
}
}
测试类:
public class Test{
public static void main(String[] args){
User user = Container.getBean();
user.function();
}
}
//后台输出‘您好’
通过这个例子应该看懂了控制反转,和依赖注入了吧,这个是不是与传统设计相‘反了’。:-D
相关知识
依赖和耦合(Dependency and Coupling)
如果模块A调用模块B提供的方法,或访问模块B中的某些数据成员(当然,在面向对象开发中一般不提倡这样做),我们就认为模块A依赖于模块B,模块A和模块B之间发生了耦合。
那么,依赖对于我们来说究竟是好事还是坏事呢?
由于人类的理解力有限,大多数人难以理解和把握过于复杂的系统。把软件系统划分成多个模块,可以有效控制模块的复杂度,使每个模块都易于理解和维护。但在这种情况下,模块之间就必须以某种方式交换信息,也就是必然要发生某种耦合关系。如果某个模块和其它模块没有任何关联(哪怕只是潜在的或隐含的依赖关系),我们就几乎可以断定,该模块不属于此软件系统,应该从系统中剔除。如果所有模块之间都没有任何耦合关系,其结果必然是:整个软件不过是多个互不相干的系统的简单堆积,对每个系统而言,所有功能还是要在一个模块中实现,这等于没有做任何模块的分解。
因此,模块之间必定会有这样或那样的依赖关系,永远不要幻想消除所有依赖。但是,过强的耦合关系(如一个模块的变化会造成一个或多个其他模块也同时发生变化的依赖关系)会对软件系统的质量造成很大的危害。特别是当需求发生变化时,代码的维护成本将非常高。所以,我们必须想尽办法来控制和消解不必要的耦合,特别是那种会导致其它模块发生不可控变化的依赖关系。依赖倒置、控制反转、依赖注入等原则就是人们在和依赖关系进行艰苦卓绝的斗争过程中不断产生和发展起来的。