初探Spring之IoC容器
本博客适合已经会用spring的读者,而不是初学者,这里博主也是会用以后再想想为什么能用的一步,想说深入底层,但显然目前还不能叫深入hhh。
IoC的概念
IoC(Inverse of Control)的字面意思是控制反转,它负责把对象的创建和对象间的调用通过Spring去管理,目的是降低程序耦合度。那这里有两个词,控制和反转,让我们带着两个词进入IoC容器的学习。
对象间调用
我们在一个对象中使用另一个对象,就必须要显示的去创建另一个对象的实例,不管是构造方法还是工厂方法(工厂方法其实也是new)来获得对象。
这里有三种对象间的调用方式
1、传统java对象的调用方式
class UserSerivce{
addUser(){
UserDao dao = new UserDao();
dao.add();
}
}
class UserDao{
add(){
System.out.println("add");
}
}
这里如果我们的UserDao里方法发生了变化,那UserService里的代码显然也要改变。
2、工厂模式
class UserService{
void add(){
UserDao dao = UserFactory.getUserDao();
}
}
class UserDao{
add(){
//*****
}
}
class UserFactory{
public static UserDao getUserDao(){
return new UserDao();
}
}
3、就是我们今天要看的IoC
利用IoC来创建
IoC底层利用的三个技术
- xml解析
- 工厂模式
- 反射
IoC的过程
1#创建xml配置类,配置创建的对象
<bean id="userDao" class="com.feng.UserDao">
</bean>
2#创建工厂类,利用反射机制创建对象
class UserFactory{
public static UserDao getUserDao(){
String classValue = class属性值;
//利用xml解析xml文件中的class属性来获取class值com.feng.UserDao
Class clazz = Class.forName(classValue);
return (userDao)clazz.newInstance();
}
}
这里可以发现Spring的IoC方式最大限度降低了程序间的耦合度,对象的创建和对象间的调度都可以丢给Spring来管理。
SpringIoC容器
IoC思想基于容器,IoC容器底层其实就是对象工厂,把容器实例化,Spring给我们提供了两种方式(两个接口)。
BeanFactory:
BeanFactory为IOC容器提供了基础功能,Spring文档中提到,当前该类仅仅是为了向后兼容老的版本,除非你不得不用,否则就应该使用第二种容器。
etc:
BeanFactory beanFactory = new ClassPathXmlApplicationContext("bean1.xml");
//加载配置文件不创建对象
User user = beanFactory.getBean("user",user.class);
//此时才创建对象
ApplicationContext:
通过API文档可以知道,ApplicationContext是BeanFactory的子接口,并且从文档中也可以看到ApplicaionContext除了包含有BeanFactory的所有功能还支持了更多的功能。
etc:
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");//加载配置文件时,创建对象
User user = context.getBean("user",User.class);
可以看到ApplicationContext的的实现有很多种,常用的两种相信大家并不陌生
FileSystemXmlApplicationContext:默认是从系统的盘符下获取文件
ClassPathXmlApplicationContext:默认是指项目的classpath路径下面的配置文件
IoC的别名,依赖注入
依赖注入(DI,Dependency Injection)
所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。为什么说IoC又称为DI,其实他们只是从不同的角度去描述一件事情,就是通过引入IoC容器,利用依赖关系注入的方式,实现对象之间的解耦。
这里举一个很容易理解的例子就懂了,比如现在有两个对象,对象A和对象B,现在A要调用B,是不是需要一个IoC容器?我们把A当成一台电脑,B可能是一个鼠标、一个键盘、一个硬盘、一个U盘,反正就是可以插在电脑上,给电脑用的任何东西,电脑(对象A)现在需要U盘(对象B),谁是IoC容器?你就是IoC容器,你做了什么?电脑想用什么你就给他插什么,插上以后,他就有了对象B的控制权,(读取U盘也好,连接鼠标也好)。你(IoC容器只负责满足他),要什么给什么,他也不需要操心怎么创建鼠标、键盘(创建对象),也不需要操心最后怎么摧毁,反正你(IoC)一切包办,是不是很好理解。
现在需要U盘(对象B),谁是IoC容器?你就是IoC容器,你做了什么?电脑想用什么你就给他插什么,插上以后,他就有了对象B的控制权,(读取U盘也好,连接鼠标也好)。你(IoC容器只负责满足他),要什么给什么,他也不需要操心怎么创建鼠标、键盘(创建对象),也不需要操心最后怎么摧毁,反正你(IoC)一切包办,是不是很好理解。
传统实现里,对象A要什么都要自己去new,各个组件间的耦合度十分严重。有了IoC容器后,它把组件之间的关系从程序内部提到外部容器,也就是说由容器在运行期将组件间的某种依赖关系动态注入组件中。
SpringIoC例子
实体类
public class Hello {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Hello{" +
"name='" + name + '\'' +
'}';
}
}
beans.xml
<?xml version="1.0" encoding="GBK"?>
<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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--使用Spring来创建对象,在Spring这些都成为Bean
类型 变量名 = new 类型();
Hello hello = new Hello();
id = 变量名
class = new 的对象
property 相当于给对象的属性设置一个值
ref:引用Spring容器中创建好的对象
value:具体的值,基本数据类型
-->
<bean id="hello" class="com.feng.pojo.Hello">
<property name="name" value="Spring"/>
</bean>
</beans>
测试类
public class MyTest {
public static void main(String[] args) {
//获取Spring的上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext( "beans.xml");
//我们的对象现在都在Spring中管理,我们要使用直接去里面取出来即可
Hello hello = (Hello)context.getBean("hello");
System.out.println(hello.toString());
}
}