spring ioc和di

来源:互联网 发布:linux ssr 客户端 编辑:程序博客网 时间:2024/05/20 23:07

很多人认为IOC就是DI他们之间是对等的,其实不然。

很多文章中都提到他们的分别依赖:

谁依赖于谁?为什么需要依赖?

注入:谁注入于谁?到底注入什么?

控制反转:谁控制谁?控制什么?

这种描述很难让别人理解,感觉有点教科书的意味。下面我就简单的说下我的看法:

一、IOC和DI区别

IOC( inversion of control)控制反转,控制反转是一种思想结合程序通俗的讲,创建对象的方式反转了。

以前对象的创建是由我们开发人员自己维护创建,包括依赖关系都是自己进行注入(创建依赖对象new),例如:我们经常提到的三层框架Web层、Service层、Dao层。web层依赖于service层,service依赖于dao层,以前我们管理service层调用dao层的数据时,都会new一个对象调用其中的方法。

使用spring后对象的创建及依赖的对象都由spring完成创建和注入,控制反转就是对象的创建方式,从我们自己创建到交个spring(程序)进行创建管理

DIDependency Injection)依赖注入,依赖注入是一种技术,它是对控制反转这种思想进行技术支撑。依赖注入即控制反转中举的例子。


二、Spring创建Bean对象的三种方式

首先我们看看不用spring时如何创建对象

public class UserServiceImpl {public List<User> getUserList(){//servi层调用dao层的方法,需要手动创建dao对象UserDao userDao = new UserDao();return userDao.getUserList();}}
使用spring,spring就会自动创建对象(前提按照一定的规则,这个规则是spring规定的)

第一种方式构造器注入创建(默认的创建方式)

public class User {public User() {System.out.println("User对象构造器注入创建!!!!");}private String name;private Integer age;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "User [name=" + name + ", age=" + age + "]";}}
Spring配置文件applicationContext.xml中配置

<?xml version="1.0" encoding="UTF-8"?><beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xmlns="http://www.springframework.org/schema/beans"        xmlns:p="http://www.springframework.org/schema/p"         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd ">    <!-- set方式注入: -->    <bean  name="user" class="cn.mingxungu.bean.User" /></beans>

测试代码

@Testpublic void fun1(){//1 创建容器对象ApplicationContext ac = new ClassPathXmlApplicationContext("cn/mingxungu/c_injection/applicationContext.xml");//2 向容器"要"user对象User u = (User) ac.getBean("user");//3 打印user对象System.out.println(u);}
结果:

User对象构造器注入创建!!!!
User [name=null, age=null]

第二种方式静态工厂创建(了解)

public class UserFactory {public static User createUser(){System.out.println("静态工厂创建User");return new User();}}
Spring配置文件applicationContext.xml中配置

<?xml version="1.0" encoding="UTF-8"?><beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd "><!-- 创建方式2:静态工厂创建   调用UserFactory的createUser方法创建名为user2的对象.放入容器 --><bean  name="user2" class="cn.mingxungu.b_create.UserFactory" factory-method="createUser" ></bean></beans>

测试代码

//创建方式2:静态工厂@Testpublic void fun2(){//1 创建容器对象ApplicationContext ac = new ClassPathXmlApplicationContext("cn/mingxungu/b_create/applicationContext.xml");//2 向容器"要"user对象User u = (User) ac.getBean("user2");//3 打印user对象System.out.println(u);}
输出结果

静态工厂创建User
User [name=null, age=null]

注意:静态工厂方法在配置文件中制定了工厂方法名称factory-method="createUser"

第三种方式实例工厂创建(了解)

public class UserFactory {public  User createUser2(){System.out.println("实例工厂创建User");return new User();}}
Spring配置文件applicationContext.xml中配置

<?xml version="1.0" encoding="UTF-8"?><beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns="http://www.springframework.org/schema/beans"    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd "><!-- 创建方式3:实例工厂创建  调用UserFactory对象的createUser2方法创建名为user3的对象.放入容器 --><bean  name="user3" factory-bean="userFactory"factory-method="createUser2" ></bean><bean  name="userFactory"         class="cn.mingxungu.b_create.UserFactory"   ></bean></beans>
测试代码

//创建方式3:实例工厂@Testpublic void fun3(){//1 创建容器对象ApplicationContext ac = new ClassPathXmlApplicationContext("cn/mingxungu/b_create/applicationContext.xml");//2 向容器"要"user对象User u = (User) ac.getBean("user3");//3 打印user对象System.out.println(u);}

输出结果

实例工厂创建User
User [name=null, age=null]

总结:

一、<bean>元素指定了factory-method属性,Spring就不再调用构造器来创建Bean实例,而是调用工厂方法来创建Bean实例。如果同时指定了class和factory-method两个属性,Spring就会调用静态工厂方法来创建Bean。Spring将先解析配置文件,并根据配置文件指定的信息,通过反射调用静态工厂类的静态工厂方法,将该静态工厂方法的返回值作为Bean实例。在这个过程中,Spring不再负责创建Bean实例,Bean实例是由用户提供的静态工厂类负责创建的。

二、实例工厂方法与静态工厂方法只有一点不同:调用静态工厂方法只需要使用工厂类即可,而调用实例工厂方法则需要工厂实例。所以在配置时,静态工厂方法使用class指定静态工厂类,实例工厂方法使用factory-bean指定工厂实例。
采用实例工厂方法创建Bean的<bean>元素时需要指定两个属性:
factory-bean:工厂bean的id
factory-method:实例工厂的工厂方法

三、Bean 生命周期


  


详解:

Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:

1、Bean自身的方法:这个包括了Bean本身调用的方法和通过配置文件中<bean>的init-method和destroy-method指定的方法

2、Bean级生命周期接口方法:这个包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法

3、容器级生命周期接口方法:这个包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。

4、工厂后处理器接口方法:这个包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工厂后处理器  接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。

说明:

在配置文件aplicationContext.xml中配置的bean的生命周期

<bean  name="user" class="cn.mingxungu.bean.User"  init-method="init" destroy-method="destory" />

init-method="init":配置一个方法作为生命周期初始化方法,在该Bean中编写一个init方法。spring会在对象创建之后立即调用.

destroy-method="destory":配置一个方法作为生命周期的销毁方法,在该Bean中编写一个destory方法。spring容器在关闭并销毁所有容器中该对象之前调用.

详细的测试参考:http://www.cnblogs.com/zrtqsk/p/3735273.html

四、Bean属性的注入

注入方式:set方法注入、构造函数注入、p名称空间注入、spel注入

set方法注入:

<!-- set方式注入: --><bean  name="user" class="cn.mingxungu.bean.User" ><!--值类型注入: 为User对象中名为name的属性注入tom作为值 --><property name="name" value="tom" ></property><property name="age"  value="18" ></property><!-- 引用类型注入: 为car属性注入下方配置的car对象 --><property name="car"  ref="car" ></property></bean>      <!-- 将car对象配置到容器中 -->      <bean name="car" class="cn.mingxungu.bean.Car" >          <property name="name" value="兰博基尼" ></property>          <property name="color" value="黄色" ></property>      </bean>
构造函数注入(掌握
<!-- 构造函数注入 --><bean name="user2" class="cn.mingxungu.bean.User" ><!-- name属性: 构造函数的参数名 --><!-- index属性: 构造函数的参数索引 --><!-- type属性: 构造函数的参数类型--><constructor-arg name="name" index="0" type="java.lang.Integer" value="999"  ></constructor-arg><constructor-arg name="car" ref="car" index="1" ></constructor-arg></bean><!-- 将car对象配置到容器中 --><bean name="car" class="cn.mingxungu.bean.Car" >    <property name="name" value="兰博基尼" ></property>    <property name="color" value="黄色" ></property></bean>

p名称空间注入

<!-- p名称空间注入, 走set方法1.导入P名称空间  xmlns:p="http://www.springframework.org/schema/p"2.使用p:属性完成注入|-值类型: p:属性名="值"|-对象类型: p:属性名-ref="bean名称" --><bean  name="user3" class="cn.mingxungu.bean.User" p:name="jack" p:age="20" p:car-ref="car" /><!-- 将car对象配置到容器中 --><bean name="car" class="cn.mingxungu.bean.Car" >    <property name="name" value="兰博基尼" ></property>    <property name="color" value="黄色" ></property></bean>

spel注入

<!--        spel注入: spring Expression Language sping表达式语言 --><bean  name="user4" class="cn.mingxungu.bean.User" ><property name="name" value="#{user.name}" ></property><property name="age" value="#{user3.age}" ></property><property name="car" ref="car" ></property></bean><!-- 将car对象配置到容器中 --><bean name="car" class="cn.itcast.bean.Car" >    <property name="name" value="兰博基尼" ></property>    <property name="color" value="黄色" ></property></bean>

复杂类型的注入

实体:

public class CollectionBean {private Object[] arr;//数组类型注入private List list;//list/set 类型注入private Map map;//map类型注入private Properties prop;//properties类型注入public Object[] getArr() {return arr;}public void setArr(Object[] arr) {this.arr = arr;}public List getList() {return list;}public void setList(List list) {this.list = list;}public Map getMap() {return map;}public void setMap(Map map) {this.map = map;}public Properties getProp() {return prop;}public void setProp(Properties prop) {this.prop = prop;}@Overridepublic String toString() {return "CollectionBean [arr=" + Arrays.toString(arr) + ", list=" + list + ", map=" + map + ", prop=" + prop+ "]";}}

配置文件

<bean name="cb" class="cn.mingxungu.c_injection.CollectionBean" ><!-- 如果数组中只准备注入一个值(对象),直接使用value|ref即可 <property name="arr" value="tom" ></property>--><!-- array注入,多个元素注入 --><property name="arr"><array><value>tom</value><value>jerry</value><ref bean="user4" /></array></property><!-- 如果List中只准备注入一个值(对象),直接使用value|ref即可 <property name="list" value="jack" ></property>--><property name="list"  ><list><value>jack</value><value>rose</value><ref bean="user3" /></list></property><!-- map类型注入 --><property name="map"  ><map><entry key="url" value="jdbc:mysql:///crm" ></entry><entry key="user" value-ref="user4"  ></entry><entry key-ref="user3" value-ref="user2"  ></entry></map> </property><!-- prperties 类型注入 --><property name="prop"  ><props><prop key="driverClass">com.jdbc.mysql.Driver</prop><prop key="userName">root</prop><prop key="password">1234</prop></props></property></bean>
五、Bean属性scope

scope类型:
singleton(默认值):单例对象.被标识为单例的对象在spring容器中只会存在一个实例
prototype:多例原型.被标识为多例的对象,每次再获得才会创建.每次创建都是新的对象.整合struts2时,ActionBean必须配置为多例的.
request:web环境下.对象与request生命周期一致.
session:web环境下,对象与session生命周期一致.
说明:前两个重点掌握,其他两个一般用不到
singleton测试
aplicationContext.xml配置文件

<?xml version="1.0" encoding="UTF-8"?><beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd "><!-- 创建方式1:空参构造创建  --><bean  name="user" class="cn.mingxungu.bean.User" scope="singleton"/></beans>

测试

@Test//scope:singleton 单例//scope:prototype 多例public void fun4(){//1 创建容器对象ApplicationContext ac = new ClassPathXmlApplicationContext("cn/mingxungu/b_create/applicationContext.xml");//2 向容器"要"user对象User u = (User) ac.getBean("user");User u2 = (User) ac.getBean("user");System.out.println("比较是否是一个对象"+(u==u2));   //单例:true   多例:false}

结果
User对象构造器注入创建!!!!
比较是否是一个对象true
prototype测试
只用修改上面的配置文件即可

<?xml version="1.0" encoding="UTF-8"?><beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd "><!-- 创建方式1:空参构造创建  --><bean  name="user" class="cn.mingxungu.bean.User" scope="prototype"/></beans>

结果
User对象构造器注入创建!!!!
User对象构造器注入创建!!!!
比较是否是一个对象false
结论:注意到 “User对象构造器注入创建!!!!” 打印的次数不一样,并且结果也不一样,说明prototype确实是重新new了一遍

原创粉丝点击