1、在传统的程序设计中,调用亲自创建被调用者的实例,即由程序控制“对象之间的依赖关系”,这种方式的耦合度比较高;控制反转就是将由程序控制的“对象间的依赖关系”转交给Ioc容器来进行控制,被调用者的实例创建工作不再是调用者完成, 大大降低了调用者和被调用者之间的关系。Ioc(inversion of control:控制反转)和Di(dependency Injection:依赖注入) 是相同的概念。
2、实现依赖注入的方式: 2.1、属性注入: //bean类 被关联 package com.liu.spring; public class RefBean { private String meg; public String getMeg() { return meg; } public void setMeg(String meg) { this.meg = meg; } } //bean 将关联RefBean类 package com.liu.spring; public class MessageBean { private String message; private RefBean refBean;//关联的RefBean类 public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public RefBean getRefBean() { return refBean; } public void setRefBean(RefBean refBean) { this.refBean = refBean; } } //配置文件 <beans> <!-- 配置文件 1.先配置类为RefBean --> <bean id="refBean" class="com.liu.spring.RefBean"> <property name="meg"> <value>我是属性注入方式实现的(我在RefBean类中)</value> </property> </bean> <!-- 2、再来配置类 MessageBean --> <bean id="messageBean" class="com.liu.spring.MessageBean"> <property name="message"> <value>Spring框架(我是在MessageBean类中)</value> </property> <!-- 加入另一个bean --> <property name="refBean"> <ref local="refBean"/> </property> </bean> </beans> //测试类 package com.liu.action; public class Action_01 { public static void main(String[] args) { //加载配置文件 ClassPathResource resource=new ClassPathResource("applicationContext.xml"); //创建bean工厂 BeanFactory factory=new XmlBeanFactory(resource); //获取对用的实例(就避免的new对象) MessageBean message=(MessageBean) factory.getBean("messageBean"); //打印结果 System.out.println(message.getMessage()+","+message.getRefBean().getMeg()); } } //最终的结果是 Spring框架(我是在MessageBean类中),我是属性注入方式实现的(我在RefBean类中)
2.2、构造方法注入: 注:只需在被关联的类中写好构造函数,在配置文件之中写好配置文件就行 //配置文件写法 <bean id="messageBean" class="com.liu.spring.MessageBean"> <!--- 构造函数注入的关键标签 ---> <constructor-arg index="0"> <value>Spring框架(我是在MessageBean类中)</value> </constructor-arg> <constructor-arg index="1"> <!-- 引用之外的bean --> <ref local="refBean"/> </constructor-arg> </bean> <!-- 被关联的bean类---> <bean id="refBean" class="com.liu.spring.RefBean"> <property name="meg"> <value>我是属性注入方式实现的(我在RefBean类中)</value> </property> </bean> 2.3、构造注入须知: 为了避免现在的配置文件的歧义而引起的张冠李戴,在bean中存在多个构造函数时,使用显示指定index和type属性 比较直观。 2.4、属性注入和构造注入的比较: 2.4.1、属性注入的特点是不需要知道属性的类型,但是必须知道属性的名称;使用set()方法实现依赖注入 2.4.2、构造函数注入的特点是不需要知道参数的名称,不需要知道set(),但是必须知道参数的序号和类型,必须定义包含不同参数 的构造函数。 2.4.3、构造函数注入和属性注入方式各有优缺点。 3、循环依赖问题: 3.1、什么是循环依赖: spring容器能够顺利实例化以构造函数注入的方式配置的Bean有一个前提:Bean引用的构造函数入参引用的对象必须已近准备就绪。由于这种机制,如果两个bean都采用构造函数注入,而且都是通过构造函数入参引用对方,就会发生死锁,就是依赖循环。 实体类如下: //Boss类 package com.liu.spring; public class Boss { private String name; private Car car; public String getName() { return name; } public void setName(String name) { this.name = name; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } //构造函数 public Boss(String name, Car car) { super(); this.name = name; this.car = car; } } //car类 package com.liu.spring; public class Car { private String brand; private Boss boss; public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public Boss getBoss() { return boss; } public void setBoss(Boss boss) { this.boss = boss; } //构造函数 public Car(String brand, Boss boss) { super(); this.brand = brand; this.boss = boss; } } //配置文件 <!-- 循环依赖问题的配置文件如下 (错) --> <bean id="car" class="com.liu.spring.Car"><!-- car类 --> <constructor-arg> <value>我是劳斯莱斯(来之car类)</value> </constructor-arg> <constructor-arg> <ref local="boss"/><!-- 引用boss --> </constructor-arg> </bean> <bean id="boss" class="com.liu.spring.Boss"> <constructor-arg> <value>我是刘明(来之boss类)</value> </constructor-arg> <constructor-arg> <ref local="car"/><!-- 引用car --> </constructor-arg> </bean> 异常为:Exception in thread "main" org.springframework.beans.factory.BeanCreationException: 3.2、循环依赖解决方法(配置文件使用属性注入) <!-- 循环依赖问题的配置文件如下 (正确) --> <bean id="car" class="com.liu.spring.Car"> <property name="brand"> <value>我是劳斯拉斯(来之car类)</value> </property> <property name="boss"> <ref local="boss"/> </property> </bean> <bean id="boss" class="com.liu.spring.Boss"> <property name="name"> <value>我是不知道(来之boss类)</value> </property> <property name="car"> <ref local="car"/> </property> </bean> ------测试类------------------ //加载配置文件 ClassPathResource resource=new ClassPathResource("applicationContext.xml"); //创建bean工厂 BeanFactory factory=new XmlBeanFactory(resource); //获得对应的实体类 Car car=(Car) factory.getBean("car"); Boss boss=(Boss) factory.getBean("boss"); System.out.println(car.getBrand()+"========"+car.getBoss().getName()); System.out.println(boss.getName()+"======="+boss.getCar().getBrand()); 最后的结果是: 我是劳斯拉斯(来之car类)========我是不知道(来之boss类) 我是不知道(来之boss类)=======我是劳斯拉斯(来之car类)