IOC原理之IoC容器的初始化过程

IoC容器的初始化过程包括Resource定位BeanDefinition的载入以及向IoC容器注册这些BeanDefinition三个阶段。

IoC容器的初始化过程概要

IoC容器的初始化包括三个过程:

  • 第一个过程是 Resource定位 过程。这个Resource定位指的是BeanDefinition的资源定位,它由ResourceLoader通过统一的Resource接口来完成,这个Resource对各种形式的BeanDefinition的使用都提供了统一接口。比如.在文件系统中的Bean定义信息可以使用FileSystemResource来进行抽象。在类路径中的Bean定义信息可以使用ClassPathResource来进行抽象等等。这个定位过程类似于容器寻找数据的过程,就像用水捅装水先要把水找到一样。

  • 第二个过程是 BeanDefinition的载入 。这个载入过程是把用户定义好的Bean表示成IoC容器内部的数据结构,而这个容器内部的数据结构就是BeanDefinition。下面介绍这个数据结构的详细定义。具体来说,这个BeanDefinition实际上就是POJO对象在IoC容器中的抽象。通过这个BeanDefinition定义的数据结构,使IoC容器能够方便地对Polo对象也就是Bean进行管理。

  • 第三个过程是 向IoC容器注册这些Bean Definition 的过程。这个过程是通过调用BeanDefinitionRegistry接口的实现来完成的。这个注册过程把载人过程中解析得到的BeanDeftnition向IoC容器进行注册。在IoC容器内部将BeanDefinition注人到一个HashMap中去,IoC容器就是通过这个HashMap来持有这些BeanDefinition数据的

几个常用的ApplicationContext

1. FileSystemXmlApplicationContext

FileSystemXmlApplicationContext的继承体系:

由继承关系可知,FileSystemXmlApplicationContext通过继承AbstractApplicationContext具备了DefaultResourceLoader读取Resource定义的BeanDefinition的能力。因为AbstractApplicationContext的基类是DefaultResourceLoader

看看其完整继承体系:

2. ClassPathXmlApplicationContext

ClassPathXmlApplicationContext的继承体系:

由继承关系可知,ClassPathXmlApplicationContext通过继承AbstractApplicationContext具备了DefaultResourceLoader读取Resource定义的BeanDefinition的能力。因为AbstractApplicationContext的基类是DefaultResourceLoader。和上面的FileSystemXmlApplicationContext如出一辙。

看看其完整继承体系:

3. AnnotationConfigApplicationContext

AnnotationConfigApplicationContext的继承体系:

可以看到,AnnotationConfigApplicationContext,也是通过DefaultResourceLoader读取Resource

看看其完整继承体系:

详细分析IoC初始化过程

以常用的ClassPathXmlApplicationContext为例:

1、 新建resources/META-INF/spring/context.xml

<?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.xsd">

    <bean id="user" class="com.source.IoC.domain.User">
        <property name="name" value="张三"/>
    </bean>

</beans>

2、 新建User

public class User {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

3、


  public static void main(String args[]) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();

        applicationContext.setConfigLocation("classpath:/META-INF/spring/context.xml");
        applicationContext.refresh();

        User user = applicationContext.getBean("user", User.class);
        System.out.printf("user.getName() = %s \n", user.getName());
    }

运行main方法,整个运行过程如下:

所以这里主要要来看一看AbstractApplicationContext中的refresh() 这个函数:

 public void refresh() throws BeansException, IllegalStateException {
        Object var1 = this.startupShutdownMonitor;
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            //这里是在子类中启动refreshBeanFactory()定位并载入
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            //prepare the bean factory for use in this context
            this.prepareBeanFactory(beanFactory);

            try {
                //设置BeanFactory的后置处理
                this.postProcessBeanFactory(beanFactory);
                //调用BeanFactory的后处理器,这些后处理器是在Bean定义中想容器注册的
                this.invokeBeanFactoryPostProcessors(beanFactory);
                //注册Bean后处理器,在Bean创建过程中调用
                this.registerBeanPostProcessors(beanFactory);
                //对上下文中的消息源进行初始化
                this.initMessageSource();
                //初始化上下文中的事件机制
                this.initApplicationEventMulticaster();
                //初始化其他的特殊Bean
                this.onRefresh();
                //检查监听Bean并且将这些Bean向容器注册
                this.registerListeners();
                //实例化所有的(non-lazy-init)单件
                this.finishBeanFactoryInitialization(beanFactory);
                //发布容器事件,结束Refresh过程
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }
                //为防止Bean资源占用,在异常处理中,销毁已经在前面过程中生成的单件Bean
                this.destroyBeans();
                //重置'active'标志
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

这个obtainFreshBeanFactory很关键,这里面有 IoC的Resource定位和载入

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        //资源定位和载入,是一个抽象方法,在子类AbstractRefreshableApplicationContext中实现的方法
        this.refreshBeanFactory();
        //getBeanFactory是一个抽象方法,在子类AbstractRefreshableApplicationContext中实现的方法
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);
        }

        return beanFactory;
    }

看看refreshBeanFactory()源码如下:

   protected final void refreshBeanFactory() throws BeansException {
       //这里判断,如果建立了BeanFactory,则销毁并关闭该BeanFactory
        if (this.hasBeanFactory()) {
            this.destroyBeans();
            this.closeBeanFactory();
        }

        try {
            //这里的创建并设置持有的DefaultListableBeanFactor的地方
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            beanFactory.setSerializationId(this.getId());
            this.customizeBeanFactory(beanFactory);
            //载入Bean ,抽象方法,委托子类AbstractXmlApplicationContext实现
            this.loadBeanDefinitions(beanFactory);
            Object var2 = this.beanFactoryMonitor;
            synchronized(this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        } catch (IOException var5) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
        }
    }

看看子类AbstractXmlApplicationContext中实现的loadBeanDefinitions

 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = this.getConfigResources(); //只可能为null
        if (configResources != null) { //不会走这一条路 参数类型Resource...
            reader.loadBeanDefinitions(configResources);
        }

        String[] configLocations = this.getConfigLocations();
        if (configLocations != null) { // 参数类型String... 
            reader.loadBeanDefinitions(configLocations);
        }

    }

    @Nullable
    protected Resource[] getConfigResources() {
        return null;
    }

继续往下看AbstractBeanDefinitionReader流操作类的loadBeanDefinitions,这里的流操作来实现IoC的载入

     public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
        Assert.notNull(locations, "Location array must not be null");
        int counter = 0;
        String[] var3 = locations;
        int var4 = locations.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String location = var3[var5];
            counter += this.loadBeanDefinitions(location); //调用下面的函数
        }

        return counter;
    }

    public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
        return this.loadBeanDefinitions(location, (Set)null); //调用下面的函数
    }

    public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
        ResourceLoader resourceLoader = this.getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
        } else {
            int loadCount;
            if (!(resourceLoader instanceof ResourcePatternResolver)) {
                Resource resource = resourceLoader.getResource(location);
                loadCount = this.loadBeanDefinitions((Resource)resource);
                if (actualResources != null) {
                    actualResources.add(resource);
                }

                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
                }

                return loadCount;
            } else {
                try {
                    Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
                    loadCount = this.loadBeanDefinitions(resources);
                    if (actualResources != null) {
                        Resource[] var6 = resources;
                        int var7 = resources.length;

                        for(int var8 = 0; var8 < var7; ++var8) {
                            Resource resource = var6[var8];
                            actualResources.add(resource);
                        }
                    }

                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
                    }

                    return loadCount;
                } catch (IOException var10) {
                    throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);
                }
            }
        }
    }

loadBeanDefinitions会调用DefaultResourceLoader中的getResource

public Resource getResource(String location) {
        Assert.notNull(location, "Location must not be null");
        Iterator var2 = this.protocolResolvers.iterator();

        Resource resource;
        do {
            if (!var2.hasNext()) {
                if (location.startsWith("/")) {
                    return this.getResourceByPath(location);
                }

                if (location.startsWith("classpath:")) {
                    return new ClassPathResource(location.substring("classpath:".length()), this.getClassLoader());
                }

                try {
                    URL url = new URL(location);
                    return (Resource)(ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
                } catch (MalformedURLException var5) {
                    return this.getResourceByPath(location);
                }
            }

            ProtocolResolver protocolResolver = (ProtocolResolver)var2.next();
            resource = protocolResolver.resolve(location, this);
        } while(resource == null);

        return resource;
    }

可以看到,getResource又调用了子类实现的getResourceByPath方法或是子类传递过来的字符串,实现 Resource定位

整个过程就说得通了。总结起来就是,Resource资源通过最外层的实现类传进来的字符串或者直接调用getResourceByPath方法,来获取bean资源路径,然后通过AbstractBeanDefinitionReader流操作实现载入,最后通过AbstractApplicationContextregisterListeners 进行注册。这就是IoC容器的初始化过程。

其他容器的初始化过程,由上面的继承关系对比,就可以知道是差不多的,这里就不一个一个分析了。

猜你喜欢

转载自blog.csdn.net/she_lock/article/details/80296973