控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法
也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。
其实就是两种方式实现loc容器
一种是xml配置文件的方式
一种就是使用注解的方式
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
一. 配置文件的方法实现loc容器
(1). 基本步骤
第一步
创建一个MAVEN工程的javaweb项目
第二步
导入spring框架的jar包的坐标
第三步
创建spring框架的xml配置文件(注意: 名字可以随便起, 约定俗成是叫applicationContext.xml)
第四步
在applicationContext.xml中配置Bean对象
<!--这里配置UserDao接口的实现类-->
<bean id="userDaoMysql" class="dao.daoimpl.UserDaoMysqlImpl"></bean>
<bean id="userDaoOrale" class="dao.daoimpl.UserDaoOraleImpl"></bean>
第四步
对配置好的bean进行测试
@Test
public void testUserDao(){
/*
* 获取UserDao接口的实现类并测试方法
* 使用loc容器来获取*/
//1.加载spring的配置文件来创建一个叫app的对象
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDaoMysql = (UserDao) app.getBean("userDaoMysql");
UserDao userDaoOrale = (UserDao) app.getBean("userDaoOrale");
userDaoMysql.getUser();
userDaoOrale.getUser();
}
小结: 也就是说, 有了这个loc容器之后, 创建对象是就不再是 接口 = new 具体实现类; 这种硬编码的形式了, 而是统一使用一个叫app的对象的getBean(“具体实现类的配置好的id”)这个方法来获取.
实际开发中, 当我们要换掉某一个接口具体的实现类时, 就可以去通过修改applicationContext.xml这个配置文件来轻而易举的完成, 之要不换id, 代码是可以完全不必改动的. 这样一来就实现的解耦.
(2).Bean标签的常用三个属性详解
以上这样配置Bean对象
是最简单的形式, 也就是只使用bean标签的id和class这两个属性
这种情况下, 就是使用的类中的无参构造方法, 如果没有无参构造方法, 那么将不能创建对象.
1.学习scope标签
这个标签是用来决定该bean对象的作用范围的
有5个取值
- singleton : 默认值, 单例的, 也就是说, 每次获取的对象地址其实是一样的
- prototype: 多例的, 也就是说, 每次创建都会创建一个新的对象, 地址是不一样的
- request: 在web环境下使用, spring创建一个Bean对象, 将对象存入request域中
- session: 在web环境下使用, spring创建一个Bean对象, 将对象存入session域中
- global session: 在web环境下, 应用在Portlet环境, 如果没有Portlet环境, 那么就相当于session.
注意: scope属性还会决定对象的创建时机, 如果是singleton, 对象将会在applicationContext.xml被加载时就创建, 也就是只创建这么么一次. 而prototype既是在每一次getBean时. 说白了, 就是类的无参构造方法被调用的时机不同. scope属性还会决定对象的销毁时机, 如果是singleton, 容器销毁才会将对象也销毁, 而prototype则是, 对象长时间不使用了, 就会被java的垃圾回收机制销毁.
2. 学习init-method和destroy-method属性
init-method属性: 值是类的初始化方法, 创建对象时, 自动执行
destroy-method: 值是类的销毁方法, 销毁对象时, 自动执行
(3).以上配置就是使用的类的无参构造方法, 那怎么样使用非无参构造方法呢
有一种叫工厂静态方法实例化
有一种叫工厂实例方法实例化
1. 工厂静态方法
第一步: 先创建一个工厂类
第二步: 在工厂类中写静态方法,
public class StaticFactory {
/*
* 返回UserDao接口的实现类*/
public static UserDao getUserDaoMysql(){
return new UserDaoMysqlImpl();
}
public static UserDao getUserDaoOrale(){
return new UserDaoOraleImpl();
}
}
第三步: 在applicationContext.xml配置文件中配置这个工厂类
第四步: 使用factory-method属性
<!--使用工厂静态方法-->
<!--<bean id="userDao" class="factory.StaticFactory" factory-method="getUserDaoMysql"></bean>-->
<bean id="userDao" class="factory.StaticFactory" factory-method="getUserDaoOrale"></bean>
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) app.getBean("userDao");
userDao.getUser();
这是Orale的实现方法
小结: 只要我们修改配置文件中factory-method属性的值, 就可以实现切换UserDao接口不同实现类的需求, id不变, 完全不用修改代码.
2. 工厂实例方法
这个方法和静态那种的不同就是, 这种是需要先配置好该工厂类, 有了这个工厂类的id之后, 再配置工厂类的方法, 而静态的明显是工厂类和方法在同一个bean标签中
public class DynamicFactory {
/*
* 返回UserDao接口的实现类对象*/
public UserDao getUserDaoMysql(){
return new UserDaoMysqlImpl();
}
public UserDao getUserDaoOrale(){
return new UserDaoOraleImpl();
}
}
<!--使用工厂实例方法-->
<bean id="factory" class="factory.DynamicFactory"></bean>
<!--<bean id="userDao" factory-bean="factory" factory-method="getUserDaoOrale"></bean>-->
<bean id="userDao" factory-bean="factory" factory-method="getUserDaoMysql"></bean>
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) app.getBean("userDao");
userDao.getUser();
这是Mysql的实现方法
小结:
- 借助工厂类的方法来实例化bean对象, 这样一来可以对同一个接口, 例如UserDao, 通过写方法来return的方式, 来new出实现类, 好处就是, 这样可以使用类中所有的构造方法来new
- 不论是静态方法, 还是非静态的方法, 明显的是, 当我们使用一个id对应一个接口时, 我们只用修改配置文件中该id的配置信息(也就是具体对应哪个方法), 就可以切换id对应的接口的实现类, 或者是同一个实现类使用不同的构造方法