IoC的概念
IoC的概念:在使用Spring框架之后,对象的实例不再由调用者来创建,而是由Spring容器来创建,Spring容器会负责控制程序之间的关系,而不是由调用者的程序代码直接控制。这样控制权就由应用代码转移到了Spring容器,控制权发生了反转,即为控制反转。
Ps:我在初次看到这个定义时,反复读了很多遍没办法理解定义所描述的概念,在通过入门程序之后,有所体会,大概的含义就是,在原来的实际编程中,创建类,并给它赋予各种属性和方法,在调用类方法时,多数情况是先生成一个类对象,比如:
User user = new User;
user.say();
这种方式是我手动的创建了类的对象,也可以说是类的实例,实例的创建是由我所写的new方法创建出来的。而在入门程序中,我并没有使用new方法,而是在Spring文件里配置了类的属性,在需要使用类方法的时候,通过Spring容器来直接获取类的实例:
UserDao userDao=(UserDao)applicationContext.getBean("userDao");
userDao.say();
这种实例方式的转换,就是控制反转,用户不再自己实例化对象,交给Spring框架完成这个过程。
DI的概念
DI的概念:从Spring的角度去看,Spring容器负责将被依赖对象赋值给调用者的成员变量,相当于为调用者注入了它依赖的实例,这就是Spring的依赖注入。
Ps:其实DI和IoC是同一个概念在不同角度上去阐述的,IoC的概念阐述是站在调用者的角度去阐述的,DI的概念是站在Spring容器的角度去阐述的,在使用Spring容器进行实例化的时候,我们创建了一个变量,如上面所写的userDao我们使用这个变量来接受了Spring容器为我们实例化的对象,这个过程就是定义里所说的Spring容器负责将被依赖对象赋值给调用者的成员变量,实际描述的就是Spring容器为我们实例化对象的过程。
具体实现方式
首先在入门程序的基础上,新定义一个接口命名为UserService,在其中定义一个say()方法。
再定义一个实现类,命名为UserServiceImpl,在其中实现say()方法:
public class UserServiceImpl implements UserService {
@Override
public void say() {
System.out.println("userService say Hello World!");
}
}
如果这样写的话只是单纯利用了Spring容器的实例化功能,如果在执行userService的同时想要调用入门程序中userDao的方法,就要在实现类中定义一个userDao属性用于实现依赖,然而此时定义的userDao属性是空的,Spring无法提供给我们一个UserDao对象,所以我们需要为userDao属性添加一个set方法用于实现依赖注入,修改后的代码如下:
package beginner.ioc;
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void say() {
this.userDao.say();
System.out.println("userService say Hello World!");
}
}
(我在编写实现类的时候出现了一个小错误,错误信息是:The method say() of type UserServiceImpl must override or implement a supertype method。错误原因:是由于写完接口没有保存,直接写实现类导致。不是什么大问题,但是是编写习惯导致的,以后要注意。)
在Spring的配置文件,也就是入门程序中的ApplicationContext.xml中,新加入一个bean元素,将其id属性值设为userService,class属性值设为实现类的全限定名。定义一个property属性将其name属性设置为userDao,设置一个ref属性用于引用入门程序中编写的userDao对象,将其值设置为userDao。(虽然两个属性值都为userDao,但是其含义是不同的,name属性的userDao是我在UserServiceImpl类里定义的userDao属性,而ref属性的userDao是在Spring容器中配置文件所设置的UserDao类的id值,也就是说如果我在UserServiceImpl中定义的UserDao类型的属性命名为userDao1,在配置文件中定义的UserDao类的id值设置为userDao2,那么property的name属性应该设值为userDao1,ref属性应该设值为userDao2。)
编写好的配置文件代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
<bean id="userDao" class="beginner.ioc.UserDaoImpl"></bean>
<bean id="userService" class="beginner.ioc.UserServiceImpl">
<property name="userDao" ref="userDao">
</property>
</bean>
</beans>
最后编写测试类代码:
package beginner.ioc;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestDI {
public static void main(String[] args) {
//1.初始化Spring容器,加载配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//2.通过容器获取UserService实例
UserService userService = (UserService) applicationContext.getBean("userService");
//3,调用实例中的say();方法
userService.say();
}
}
成功运行: