Spring源码解析—第二篇IOC之beanfactory初始化源码解析

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

1、IOC简介

IOC(Inversion of Control):即”控制反转”,也叫DI(Dependency Injection):DI即依赖注入。

所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。

IoC 容器:最主要是完成了完成对象的创建和依赖的管理注入等等。

对象和对象关系怎么表示?

可以用 xml , properties 文件等语义化配置文件表示。

描述对象关系的文件存放在哪里?

可能是 classpath , filesystem ,或者是 URL 网络资源, servletContext 等。

2、Spring IOC的简单实现

2.1、创建实体类User

    package com.vesus.spring.model;

    /**
     * @Description:
     * @Author: vesus
     * @CreateDate: 2018/5/31 下午11:44
     * @Version: 1.0
     */
    public class User {

        private String id ;

        private String name ;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

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

2.2、创建applicationContext.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.vesus.spring.model.User" />
    </beans>

2.3、新建测试类

    package com.vesus.spring.model.test;

    import com.vesus.spring.model.User;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    /**
     * @Description:
     * @Author: vesus
     * @CreateDate: 2018/5/31 下午11:48
     * @Version: 1.0
     */
    public class Test {

        public static void main(String[] args) {

            BeanFactory beanFactory = new ClassPathXmlApplicationContext("applicationContext.xml");
            User user = (User) beanFactory.getBean("user") ;
            System.err.println(user.getDesc());
        }
    }

3、源码分析

3.1、入口类

    public ClassPathXmlApplicationContext(
        String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
                throws BeansException {

            super(parent);
            setConfigLocations(configLocations);//设置配置文件位置
            if (refresh) {
                refresh();//主要的加载bean的过程
            }
        }

有源码可以看到最主要的方法集中在refresh()上,下面分析一下refresh的源码。

3.2、refresh()源码分析

    public void refresh() throws BeansException, IllegalStateException {
            synchronized (this.startupShutdownMonitor) {
                // 准备刷新上下文环境
                prepareRefresh();

                //读取xml文件的,初始化beanFactory
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

                //准备beanfactory来使用这个上下文.做一些准备工作,例如classloader,beanfactoryPostProcessor等
                prepareBeanFactory(beanFactory);

                try {
                    //空方法,供子类使用
                    postProcessBeanFactory(beanFactory);

                    //开始执行注册到该上下文的BeanFactoryPostProcessors
                    invokeBeanFactoryPostProcessors(beanFactory);

                    //开始注册BeanPostProcessor来拦截其他的bean的初始化过程
                    registerBeanPostProcessors(beanFactory);

                    //初始化消息源
                    initMessageSource();

                    //注册上下文事件的广播集
                    initApplicationEventMulticaster();

                    //初始化其他上下文中子类中的特殊bean
                    onRefresh();

                    //注册监听器
                    registerListeners();

                    //初始化单例
                    finishBeanFactoryInitialization(beanFactory);

                    //初始化完成
                    finishRefresh();
                }

                catch (BeansException ex) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Exception encountered during context initialization - " +
                                "cancelling refresh attempt: " + ex);
                    }

                    // Destroy already created singletons to avoid dangling resources.
                    destroyBeans();

                    // Reset 'active' flag.
                    cancelRefresh(ex);

                    // Propagate exception to caller.
                    throw ex;
                }

                finally {
                    // Reset common introspection caches in Spring's core, since we
                    // might not ever need metadata for singleton beans anymore...
                    resetCommonCaches();
                }
            }
        }

Refresh 首先进行上下本刷新,然后读取xml文件,并初始化beanfactory。初始化beanfactory源码如下。

3.3、obtainFreshBeanFactory源码解析

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        //刷新beanfactory
        refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }

3.4、refreshBeanFactory源码解析

    protected final void refreshBeanFactory() throws BeansException {
            //判断容器是否存在,已经有了一个容器,先销毁里面的bean然后再关闭容器,spring保证只有一个容器
            if (hasBeanFactory()) {
                destroyBeans();//销毁已经存在的bean
                closeBeanFactory();//关闭bean工厂
            }
            try {
                //创建IoC容器
                DefaultListableBeanFactory beanFactory = createBeanFactory();
                //对IOC容器进行初始化
                beanFactory.setSerializationId(getId());
                customizeBeanFactory(beanFactory);
                //加载类
                loadBeanDefinitions(beanFactory);
                synchronized (this.beanFactoryMonitor) {
                    this.beanFactory = beanFactory;
                }
            }
            catch (IOException ex) {
                throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
            }
        }

refreshBeanFactory中创建IOC容器,并对容器进行初始化,主要的方法为加载类。

3.5、loadBeanDefinitions源码解析

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
            //创建一个XmlBeanDefinitionReader
            XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

            //配置XmlBeanDefinitionReader
            beanDefinitionReader.setEnvironment(this.getEnvironment());
            beanDefinitionReader.setResourceLoader(this);
            beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

            //初始化beanDefinitionReader
            initBeanDefinitionReader(beanDefinitionReader);
            //加载bean
            loadBeanDefinitions(beanDefinitionReader);
        }

从loadBeanDefinitions的源码中可以看到创建了一个XmlBeanDefinitionReader读取资源文件,加载资源文件中定义的类。继续跟踪loadBeanDefinitions最终找到XmlBeanDefinitionReader.java 中的registerBeanDefinitions

3.6、registerBeanDefinitions源码解析

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
            BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
            int countBefore = getRegistry().getBeanDefinitionCount();
            documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
            return getRegistry().getBeanDefinitionCount() - countBefore;
        }

这个方法是返回新加入的beanDefinition的个数,继续跟踪documentReader.registerBeanDefinitions,追踪到主要的方法为parseBeanDefinitions

3.7、parseBeanDefinitions源码解析

    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
            if (delegate.isDefaultNamespace(root)) {
                NodeList nl = root.getChildNodes();
                for (int i = 0; i < nl.getLength(); i++) {
                    Node node = nl.item(i);
                    if (node instanceof Element) {
                        Element ele = (Element) node;
                        if (delegate.isDefaultNamespace(ele)) {
                            //解析xml,获取bean
                            parseDefaultElement(ele, delegate);
                        }
                        else {
                            delegate.parseCustomElement(ele);
                        }
                    }
                }
            }
            else {
                delegate.parseCustomElement(root);
            }
        }

查看解析方法parseDefaultElement。

3.8、parseDefaultElement源码解析

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
            if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
                importBeanDefinitionResource(ele);
            }
            else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
                processAliasRegistration(ele);
            }
            else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
                //解析节点为bean的节点
                processBeanDefinition(ele, delegate);
            }
            else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
                // recurse
                doRegisterBeanDefinitions(ele);
            }
        }

3.9、processBeanDefinition源码解析

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
            //解析xml,获取bean
            BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
            if (bdHolder != null) {
                bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
                try {
                    //注册bean
                    BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
                }
                catch (BeanDefinitionStoreException ex) {
                    getReaderContext().error("Failed to register bean definition with name '" +
                            bdHolder.getBeanName() + "'", ele, ex);
                }
                // Send registration event.
                getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
            }
        }

至此,beanfactory初始化基本完成了。


来源:http://ddrv.cn

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring源码解析—第二篇IOC之beanfactory初始化源码解析

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏