深入了解IOC |
概念
IOC:控制反转
所谓控制,就是指资源的获取方式
主动式:
ExamServlet{
ExamService es=new ExamService ();
Paper paper=new Paper();// 复杂对象的创建是非常庞大的工程
}
被动式:
ExamServlet{
Paper paper;
public void test(){
paper.checkout();
}
}
简单总结:控制反转就是把创建和管理bean的过程交给了第三方,而这里的第三方就是容器Spring IoC Container
bean是什么?
Bean就是包装好了的对象,无论依赖注入还是控制反转都是针对bean来说的。
容器是什么
容器:管理所有的组件(有功能的类),负责创建配置和管理bean。
因为对象的创建和销毁都是很麻烦的,让容器去管理对象的声明,我们只管使用就可以了
假设ExamServlet受容器管理,ExamService 也受容器管理;容器可以自动的探查出哪些组件(类)需要用到另一些组件(类);容器帮我们创建ExamService 对象,并把ExamService 对象赋值
容器:主动的new资源变为被动的接受资源;容器可以理解为是婚介所;找对象的人由主动获取变为被动接受;
IOC容器
Spring 提供了两种 IoC 容器,分别是 BeanFactory、ApplicationContext 。
BeanFactory ,就像一个包含 Bean 集合的工厂类。它会在客户端要求时实例化 Bean 对象。
ApplicationContext,它是 BeanFactory 的子类,更好的补充并实现了 BeanFactory 的。
ApplicationContext 的里面有两个具体的实现子类,用来读取配置配件的:
- ClassPathXmlApplicationContext - 从 class path 中加载配置文件,更常用一些;
- FileSystemXmlApplicationContext - 从本地文件中加载配置文件,不是很常用,如果再到 Linux 环境中,还要改路径,不是很方便。
- XmlWebApplicationContext :由 Web 应用的XML文件读取上下文。例如我们在 Spring MVC 使用的情况。
DI(Dependency injection)依赖注入
容器能知道哪个组件类运行的时候,需要另外一个类(组件);容器通过反射的形式,将容器中准备好的ExamService 对象,注入(利用反射给属性赋值)到BookServlet中;
主要是容器管理的组件,都能使用容器提供的强大功能
通过各种方式给容器中注册对象,所以前是自己new对象吗,现在所有的对象交给容器创建,给容器中注册组件,就像是国家负责分配对象一样,不用自己找对象了,你需要什么样的对象,国家给你安排,依赖注入就是给你找的对象指定指标,指定多高多胖等等的属性
spring IOC 的实现机制
spring ioc就是通过工厂+反射实现的,demo如下
interface Fruit {
public abstract void eat();
}
class Apple implements Fruit {
public void eat(){
System.out.println("Apple");
}
}
class Orange implements Fruit {
public void eat(){
System.out.println("Orange");
}
}
class Factory {
// 具体实现的工厂
public static Fruit getInstance(String className) {
Fruit f = null;
try {
f = (Fruit) Class.forName(className).newInstance(); // 反射机制动态获取类中的信息
} catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
class Client {
public static void main(String[] args) {
Fruit f = Factory.getInstance("io.github.dunwu.spring.Apple");
if(f != null){
f.eat();
}
}
}
上面的小例子就是在运行的时候才把io.github.dunwu.spring.Apple传进去,工厂才知道生产哪个类,可以把io.github.dunwu.spring.Apple变成变量,然后写入配置文件,就可以根据需求动态的决定生产哪个类,这个例子就体现了ioc生产bean的思想。
使用spring框架
使用框架一般都分为三步:1.引入依赖;2.修改配置文件;3.测试
导包
4个核心jar包
日志包
写配置
集合了spring的ioc容器管理的所有组件(类)
创建一个Spring Bean Configuration
实例测试
新建Person类
配置文件
测试类
分析
1.对象是什么时候创建的?
在类的构造方法中打印什么时候调用,在类的getter、setter方法打印什么时候调用,然后再容器启动后打印启动完成,就可以知道对象是什么时候创建的
可以看出在容器启动完成之前,对象已经创建了,并且已经赋值,而且容器是通过类的构造函数创建对象,通过类的getter,setter方法赋值。
2.创建对象是否是单例模式
从容器中取出id为01的创建好的对象
判断是否相等
结果是相等
说明容器只创建了一次对象,是单例模式
3.获取不存在的对象,就会报异常
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘person03’ available
执行结果
4.只要容器一启动所有的对象都创建了
可以看出构造函数调用了两次,一共有两个对象都创建出来了
小结
- 结论
- 给容器中创建一个组件,我们根据id拿到对象
- 容器创建之后对象就创建了
- 只要容器一启动所有的对象都创建了
- 同一组件在ioc中是单实例的,容器启动完成之前都已经创建准备好的
- 如果获取容器中没有的组件,获取组件就会报异常
- ioc容器在创建这个组件对象的时候,property会利用setter方法为javaBean属性进行赋值
- src 源码包开始的路径,称为类路径的开始
- 所有源码包里面的都会被合并放在类路径里面