Spring-IOC原理简述

今天的这个IOC,不打算分析源码了,一方面觉的Spring的源码很庞大,一步步跟的话容易陷入很深的某一个分支里,而且容易遗忘。所以打算简单的说下原理,大家可以先记下来简单的原理,然后再看看大佬们的博客,然后再一步步debug源码,这样估计也就差不多了。那么接下来就先简单说下IOC的原理吧。

IOC的从广义范围来说,意思是控制反转,什么是控制反转呢,大家肯定都知道,以前我们要使用一个类里的方法或者属性的时候,我们先要new 这个类,然后用这个对象调用里面的方法的。这是传统方式上的使用类里的方法和属性,但是这种方式存在很大的耦合性。为了降低耦合性,Spring出了IOC控制反转,它的含义是指,Spring帮助我们来创建对象就是我们所说的bean,并且管理bean对象,当我们需要用的时候,需要Spring提供给我们创建好的bean对象。这样就从之前我们的主动创建对象变为了,由Spring来控制创建对象,来给我们使用,也就是控制反转的意思。

对于IOC它的设计包括了:

依赖注入、依赖检查、自动配置、支持集合、指定初始化方法和销毁方法、支持回调某些方法。

它主要设计了两个接口用来表示容器

一个是BeanFactory

一个是ApplicationContext

对于BeanFactory这个容器来说,它相当一个HashMap,BeanName作为key,value就是这个bean的实例化对象,通常提供注册(put)和获取(get)两个功能。这个实现主要是使用的工厂模式+反射技术,来进行对Bean的实例化,然后把这个实例化对象存到HashMap中,下面通过一个简单的例子来展现下BeanFactory是如何使用工厂模式+反射技术创建对象的。

1、创建一个接口类

public interface Shape {
    public void draw();
}

2、实现这个接口类

public class Circle implements Shape {
    public void draw(){
        System.out.println("画圆形");
    }
}
public class Square implements Shape {
    public void draw(){
        System.out.println("画方形");
    }
}

3、创建一个工厂类

public class ReflectFactory {
    public Shape getInstance(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Shape shape =null;
        shape =(Shape)Class.forName(className).newInstance();
        return shape;
    }
}

4、创建一个Client类来进行测试

public class Client {
   public static void main(String[] args){
       ShapeFactory shapeFactory = new ShapeFactory();
       Shape shape= shapeFactory.getInstance("Circle");
       shape.draw();
   }
}

5、输出的是

画圆形

这个简单的小例子就是BeanFactory中通过工厂模式和反射创建对象的一个简单原理,当然BeanFactory的源码要比这个复杂的多。这里就是为了方便大家理解。

而对于ApplicationContext来说,它继承了BeanFactory这个接口,并且丰富了更多了功能在里面,这其中包括回调一些方法。这其中主要的就是有个refresh()方法,这个方法主要是刷新整个容器,即重新加载或者刷新所有的bean。接下来给大家看下refresh()方法的源码。

public void refresh() throws BeansException, IllegalStateException {
        Object var1 = this.startupShutdownMonitor;
        //首先是synchronized加锁,加这个锁的原因是,避免如果你先调一次refresh()然后这次还没处理完又调一次,就会乱套了
        synchronized(this.startupShutdownMonitor) {
         //这个方法是做准备工作的,记录容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
            this.prepareRefresh();
            //这一步是把配置文件解析成一个个Bean,并且注册到BeanFactory中,注意这里只是注册进去,并没有初始化
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            //设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean,这里都是spring里面的特殊处理
            this.prepareBeanFactory(beanFactory);

            try {
                //具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类,来完成一些其他的操作
                this.postProcessBeanFactory(beanFactory);
                //这个方法是调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory)
                this.invokeBeanFactoryPostProcessors(beanFactory);
                //这个方法注册 BeanPostProcessor 的实现类
                this.registerBeanPostProcessors(beanFactory);
                //这方法是初始化当前 ApplicationContext 的 MessageSource,国际化处理
                this.initMessageSource();
                //这个方法初始化当前 ApplicationContext 的事件广播器
                this.initApplicationEventMulticaster();
                //这个方法初始化一些特殊的 Bean(在初始化 singleton beans 之前)
                this.onRefresh();
                //这个方法注册事件监听器,监听器需要实现 ApplicationListener 接口
                this.registerListeners();

                //初始化所有的 singleton beans(单例bean),懒加载(non-lazy-init)的除外
                this.finishBeanFactoryInitialization(beanFactory);
                //方法是最后一步,广播事件
                this.finishRefresh();
            } catch (BeansException var9) {
                if(this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }
                //调用销毁bean的方法
                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

以上就是ApplicationContext中的refresh()这个方法所做的事,里面需要看的重点的方法是ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();this.finishBeanFactoryInitialization(beanFactory);这两个方法,大家有兴趣可以看下里面的源码。

对上面的两大块分析完成后,那么对于IOC容器的启动过程是什么样呢,说的更直白些就是ClassPathXmlApplicationContext这个类启动的时候做了啥?

首先访问的是“高级容器”refresh方法,这个方法是使用低级容器加载所有的BeanDefinition和properties到IOC的容器中,低级容器加载成功后,高级容器开始开始处理一些回调功能。例如Bean后置处理器,回调setBeanFactory方法,和注册监听、发布事件、实例化单例Bean。

IOC做的事其实就是,低级容器(BeanFactory)加载配置文件,解析成BeanDefinition,然后放到一个map里,BeanName作为key  ,这个Bean实例化的对象作为value,   使用的时候调用getBean方法,完成依赖注入。  

至于高级容器 (ApplicationContext),它包含了低级容器的功能,当他执行 refresh 模板方法的时候,将刷新整个容器的 Bean。同时其作为高级容器,包含了太多的功能。一句话,他不仅仅是 IoC。他支持不同信息源头,支持 BeanFactory 工具类,支持层级容器,支持访问文件资源,支持事件发布通知,支持接口回调等等。

对于Spring来说还有很多,因为篇幅原因,对于Spring的Bean的生命周期、创建bean的三种方式、注入的三种方式、BeanFactory和ApplicationContext的区别 等等,就不在这阐述了。

发布了311 篇原创文章 · 获赞 58 · 访问量 28万+

猜你喜欢

转载自blog.csdn.net/qq_30353203/article/details/103916206