前言
今天的这个IOC,不打算分析源码了,一方面觉的Spring的源码很庞大,一步步跟的话容易陷入很深的某一个分支里,而且容易遗忘。所以打算简单的说下原理,大家可以先记下来简单的原理,然后再看看大佬们的博客,然后再一步步debug源码,这样估计也就差不多了。那么接下来就先简单说下IOC的原理吧。
IOC的从广义范围来说,意思是控制反转,什么是控制反转呢,大家肯定都知道,以前我们要使用一个类里的方法或者属性的时候,我们先要new出这个类的对象,然后用这个对象调用里面的方法的。这是传统方式上的使用类里的方法和属性,但是这种方式存在很大的耦合性。为了降低耦合性,Spring出了IOC控制反转,它的含义是指,Spring帮助我们来创建对象就是我们所说的bean,并且管理bean对象,当我们需要用的时候,需要Spring提供给我们创建好的bean对象。这样就从之前我们的主动创建对象变为了,由Spring来控制创建对象,来给我们使用,也就是控制反转的意思。下面我们通过实际案例来讲解
代码案例
对于IOC它的设计主要包括:
它主要设计了两个接口用来表示容器
一个是BeanFactory(低级容器)
一个是ApplicationContext(高级容器)
BeanFactory它是IOC容器的顶层的接口,对于BeanFactory这个容器来说,它相当一个HashMap,BeanName作为key,value就是这个bean的实例化对象,通常提供注册(put)和获取(get)两个功能。这个实现主要是使用的工厂模式+反射技术,来进行对Bean的实例化,然后把这个实例化对象存到HashMap中,下面通过一个简单的例子来展现下BeanFactory是如何使用工厂模式+反射技术创建对象
- 创建一个接口类
1public interface Shape {
2 public void draw();
3}
- 实现这个接口类
1 public class Circle implements Shape {
2 public void draw(){
3 System.out.println("画圆形");
4 }
5 }
1 public class Square implements Shape {
2 public void draw(){
3 System.out.println("画方形");
4 }
5}
- 创建一个工厂类
1 public class ShapeFactory {
2 public Shape getInstance(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
3 Shape shape =null;
4 shape =(Shape)Class.forName(className).newInstance();
5 return shape;
6 }
7}
- 创建一个Client类来进行测试
1public class Client {
2 public static void main(String[] args){
3 ShapeFactory shapeFactory = new ShapeFactory();
4 Shape shape= shapeFactory.getInstance("Circle");
5 shape.draw();
6 }
7}
- 输出的是
1 画圆形
这个简单的小例子就是BeanFactory中通过工厂模式和反射创建对象的一个简单原理,当然BeanFactory的源码要比这个复杂的多。这里就是为了方便大家理解。
而对于ApplicationContext来说,它继承了BeanFactory这个接口,并且丰富了更多了功能在里面,这其中包括回调一些方法。这其中主要的就是有个refresh()方法,这个方法主要是刷新整个容器,即重新加载或者刷新所有的bean。接下来给大家看下refresh()方法的源码。
1 public void refresh() throws BeansException, IllegalStateException {
2 Object var1 = this.startupShutdownMonitor;
3 //首先是synchronized加锁,加这个锁的原因是,避免如果你先调一次refresh()然后这次还没处理完又调一次,就会乱套了
4 synchronized(this.startupShutdownMonitor) {
5 //这个方法是做准备工作的,记录容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
6 this.prepareRefresh();
7 //这一步是把配置文件解析成一个个Bean,并且注册到BeanFactory中,注意这里只是注册进去,并没有初始化
8 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
9 //设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean,这里都是spring里面的特殊处理
10 this.prepareBeanFactory(beanFactory);
11
12 try {
13 //具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类,来完成一些其他的操作
14 this.postProcessBeanFactory(beanFactory);
15 //这个方法是调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory)
16 this.invokeBeanFactoryPostProcessors(beanFactory);
17 //这个方法注册 BeanPostProcessor 的实现类
18 this.registerBeanPostProcessors(beanFactory);
19 //这方法是初始化当前 ApplicationContext 的 MessageSource,国际化处理
20 this.initMessageSource();
21 //这个方法初始化当前 ApplicationContext 的事件广播器
22 this.initApplicationEventMulticaster();
23 //这个方法初始化一些特殊的 Bean(在初始化 singleton beans 之前)
24 this.onRefresh();
25 //这个方法注册事件监听器,监听器需要实现 ApplicationListener 接口
26 this.registerListeners();
27
28 //初始化所有的 singleton beans(单例bean),懒加载(non-lazy-init)的除外
29 this.finishBeanFactoryInitialization(beanFactory);
30 //方法是最后一步,广播事件
31 this.finishRefresh();
32 } catch (BeansException var9) {
33 if(this.logger.isWarnEnabled()) {
34 this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
35 }
36 //调用销毁bean的方法
37 this.destroyBeans();
38 this.cancelRefresh(var9);
39 throw var9;
40 } finally {
41 this.resetCommonCaches();
42 }
43
44 }
45 }
以上就是ApplicationContext中的refresh()这个方法所做的事,里面需要看的重点的方法是ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();和this.finishBeanFactoryInitialization(beanFactory);这两个方法,大家有兴趣可以看下里面的源码,这里面包含了bean的一个生命周期。
简单的理解,首先访问的是“高级容器”refresh方法,这个方法是使用低级容器加载所有的BeanDefinition和properties到IOC的容器中,低级容器加载成功后,高级容器开始开始处理一些回调功能。例如Bean后置处理器,回调setBeanFactory方法,和注册监听、发布事件、实例化单例Bean。
IOC做的事其实就是,低级容器(BeanFactory)加载配置文件,解析成BeanDefinition,然后放到一个map里,BeanName作为key ,这个Bean实例化的对象作为value, 使用的时候调用getBean方法,完成依赖注入。
高级容器 (ApplicationContext),它包含了低级容器的功能,当他执行 refresh 模板方法的时候,将刷新整个容器的 Bean。同时其作为高级容器,包含了太多的功能。他支持不同信息源头,支持 BeanFactory 工具类,支持层级容器,支持访问文件资源,支持事件发布通知,支持接口回调等等。
写在最后
以上就是我对关于IOC的原理的一些理解,个人认为先把这个简单版本的原理,弄清楚后期再慢慢研究里面的细节。Spring、SpringMVC、Mybatis的原理说的差不多了,下次给大家说下是如何把三个框架整合到一起,搭建一个简单的web开发工程。
如果想知道更多知识,记得关注我哦