在上篇文章Spring入门中对IOC进行了一个简单的介绍,但是要想真正的去理解IOC以及能更好的使用IOC,就要知道其理论。
1、IOC原型IOC也就是控制反转,那么我们先按照之前的步骤(正向控制,对象通过new实现)来看:
我们之前在做数据和业务层一般分为以下几个步骤:
- UserDao 接口
- UserDaoImpl 实现类
- UserService 接口
- UserServiceImpl 实现类
UserDao 接口:
public interface UserDao {
void getUser();//获取信息
}
UserDaoImpl 实现类:
public class UserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("默认数据实现");
}
}
UserService 接口:
public interface UserService {
void getUser();
}
UserServiceImpl 实现类(核心:业务层调用Dao层):
public class UserServiceImpl implements UserService{
private UserDao userDao = new userDaoImpl();
@Override
public void getUser() {
userDao.getUser(); //这里去调用Dao层
}
}
测试类:
public class Test {
public static void main(String[] args) {
//用户实际调用的是业务层
UserService userService = new UserServiceImpl();
userService.getUser();
}
}
这样没有问题可以输出 默认数据实现 字样
但是现在有新的需求,需要增加Mysql和Oracle两个UserDao实现类:
UserDaoMysqlImpl:
public class UserDaoMysqlImpl implements UserDao {
@Override
public void getUser() {
System.out.println("MySQL实现");
}
}
UserDaoOracleImpl:
public class UserDaoOracleImpl implements UserDao {
@Override
public void getUser() {
System.out.println("oracle实现");
}
}
如果需要使用这两个实现类,在测试类中去实现,我们需要每次都要修改业务层实现类:
UserServiceImpl:
public class UserServiceImpl implements UserService {
//也就是需要用那个数据实例类就要在业务层更改
//
private UserDao userDao = new UserDaoImpl();
private UserDao userDao = new UserDaoMysqlImpl();
private UserDao userDao = new UserDaoOracleImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
但是这样存在一个很大的问题,如果之后有100个类,那么是否每次都需要在业务层更改?
显然是肯定不恰当的,不符合程序的设计原则,那么该如何改善?也就是当用户输入的参数变了后我们不能去修改原代码,我们可以这样修改:
加入Set方法
public class UserServiceImpl implements UserService {
//不直接new,而是用下面的Set实现动态值的注入
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
这样我们只用在测试类(也就是客户端)根据传入值即可修改:
public class Test02 {
public static void main(String[] args) {
//用户实际调用的是业务层
UserService userService = new UserServiceImpl();
((UserServiceImpl) userService).setUserDao(new UserDaoImpl());
//(new 需要的类)
userService.getUser();
}
}
这样就实现了不用去修改原代码,而是根据用户输入的参数去确定需要实现的类
两者有什么区别?
- 之前的程序是主动创建对象,控制权在程序员手里
- 使用Set注入后,程序没有主动性,而是变成了被动的接收对象(客户端传什么就创建什么)
- 也就是说如果在以后更新了很多实现类,只需要和用户说有了这个功能,用户即可通过给的接口去调用到实际业务层内的方法
这就是IOC的原型,也就是控制反转,把控制权交给了第三者(不是程序本身,也不是程序员)
IOC是Spring的核心:
使用了多种方式实现IOC,其中有通过XML文件配置,也可以通过注解等
Spring容器在初始化的时候先读取配置文件,根据配置文件或元素创建于组织对象存取容器内,需要使用的时候再从IOC容器中取出需要的对象
通过Spring去实现IOC容器:
首先导入Spring:
org.springframework spring-core 5.3.20 org.springframework spring-context 5.3.20 org.springframework spring-beans 5.3.20 org.springframework spring-expression 5.3.20 junit junit 4.11 test
通过XML配置文件方法:
在resources内创建一个Spring的配置文件,名字可以随便取,例如:bean.XML
创建完打开可以看到这样的表头信息:
在Spring中,对象都被bean代替,也就是说每一个bean都代表一个对象:
- 之前创建对象方式:类型 变量名 = new 类型();
- Spring中: bean = 对象
格式:
把上面的案例通过Spring的XML文件来配置实现:
测试类写法:
public class Test01 {
public static void main(String[] args) {
//读取配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//去IOC容器中找bean,且id=userServiceImpl的对象
UserServiceImpl userService = (UserServiceImpl) context.getBean("userServiceImpl");
//使用它的方法
userService.getUser();
}
}
那这样如何控制?
我们只需在配置文件中的传入对象控制即可,例如:
我们只要修改ref后面的id名,Spring就会自动根据这个id名去容器中找是否有这个对象,如果有,则通过getBean()去获取到
在实际业务中只需要给客户一个配置文件,客户可以根据自己的需求去更改这个配置文件来实现自己需要的功能,而不需要去修改源码。
而且通过这种方式,我们没有使用new去创建对象,那这是怎么实现的?这就是Spring的魅力!!!
3、总结:控制反转: 之前对象的创建是由程序来控制,现在是交给Spring去控制,程序本身不创建对象,而变成被动的接收对象
依赖注入: 利用Set方法来进行注入
其实IOC是一种编程思想,是由主动的创建变成被动的接收
使用Spring,就彻底不用去程序中改动了,只需要配置XML文件即可



