博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ClassPathXMLApplicationContext上下文加载过程
阅读量:6607 次
发布时间:2019-06-24

本文共 7271 字,大约阅读时间需要 24 分钟。

今天看了一下《spring技术内幕》,看了下spring IOC容器的加载过程,但是里面的代码很杂,就自己用源码的测试用例debug了一下看了下过程

测试用例

@Test    public void testSingleConfigLocation() throws IOException {        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(FQ_SIMPLE_CONTEXT);        assertTrue(ctx.containsBean("someMessageSource"));        LazyBean bean = ctx.getBean(LazyBean.class);        Environment environment =ctx.getEnvironment();        String[] profiles =environment.getDefaultProfiles();        for(String s :profiles){            System.out.println(s);        }        CollectionBean bean2 = (CollectionBean) ctx.getBean("collection");        SingletonBean bean3 = ctx.getBean(SingletonBean.class);        SingletonBean bean4 = ctx.getBean(SingletonBean.class);        if (bean != null) {            System.out.println(bean.getTestFiled());        }        if (bean2 != null) {            System.out.println(bean2.getList());        }        if (bean3 != null) {            bean3.process();        }        if (bean4 != null) {            bean4.process();        }        System.out.println(ctx.getBeanDefinitionCount());        /*         * System.out.println(ctx.getBean("lazyBean"));         * System.out.println(ctx.getBean("lazyBean"));         */        ctx.close();    }

加载过程

  • 首先会调用父类AbstractApplicationContext的静态初始化块
static {        // Eagerly load the ContextClosedEvent class to avoid weird classloader issues        // on application shutdown in WebLogic 8.1. (Reported by Dustin Woods.)        ContextClosedEvent.class.getName();    }

大概就是说为了避免一些奇怪的问题会首先发布一个ContextClosedEvent事件,然后按照正常的初始化依次初始化父类。

  • 调用构造方法中的refresh方法,这个方法也是上下文初始化的开始
public ClassPathXmlApplicationContext(            String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)            throws BeansException {        super(parent);        setConfigLocations(configLocations);        if (refresh) {            refresh();        }    }
  • refresh方法会调用AbstractRefreshableApplicationContext中的refreshBeanFactory方法创建一个DefaultListableBeanFactory实例,作为上下文的容器
protected final void refreshBeanFactory() throws BeansException {        if (hasBeanFactory()) {            destroyBeans();            closeBeanFactory();        }        try {            DefaultListableBeanFactory beanFactory = createBeanFactory();            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);        }    }
  • 创建了容器之后就要从xml文件中加载和注册bean的定义,上面的loadBeanDefinition方法在AbstractXmlApplicationContext中的实现会被调用
@Override    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {        // Create a new XmlBeanDefinitionReader for the given BeanFactory.        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);        // Configure the bean definition reader with this context's        // resource loading environment.        beanDefinitionReader.setEnvironment(this.getEnvironment());        beanDefinitionReader.setResourceLoader(this);        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));        // Allow a subclass to provide custom initialization of the reader,        // then proceed with actually loading the bean definitions.        initBeanDefinitionReader(beanDefinitionReader);        loadBeanDefinitions(beanDefinitionReader);    }    /**     * Initialize the bean definition reader used for loading the bean     * definitions of this context. Default implementation is empty.     * 

Can be overridden in subclasses, e.g. for turning off XML validation * or using a different XmlBeanDefinitionParser implementation. * @param reader the bean definition reader used by this context * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setDocumentReaderClass */ protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) { reader.setValidating(this.validating); } /** * Load the bean definitions with the given XmlBeanDefinitionReader. *

The lifecycle of the bean factory is handled by the {

@link #refreshBeanFactory} * method; hence this method is just supposed to load and/or register bean definitions. * @param reader the XmlBeanDefinitionReader to use * @throws BeansException in case of bean registration errors * @throws IOException if the required XML document isn't found * @see #refreshBeanFactory * @see #getConfigLocations * @see #getResources * @see #getResourcePatternResolver */ protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }

  • 这两个方法会用来加载并注册BeanDefiniton,它们又会使用XmlBeanDefinitionReader来加载xml中的bean的定义,bean定义的解析会使用DefaultBeanDefinitionDocumentReader,它又会使用BeanDefinitionParserDelegate类委托解析bean的定义
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//委托BeanDefinitionParserDelegate进行解析 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. 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)); } }

上面黑体标注的是将解析的BeanDefinition注册到上下文中的过程,我之前没找到这个方法很奇怪loadBeanDefinition返回的都是int我就在想,BeanDefinition哪去了。静态方法会调用BeanDefinitionRegistry

接口的registerBeanDefinition方法。而DefaultListableBeanFactory实现了这个接口,

public static void registerBeanDefinition(            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)            throws BeanDefinitionStoreException {        // Register bean definition under primary name.        String beanName = definitionHolder.getBeanName();        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());        // Register aliases for bean name, if any.        String[] aliases = definitionHolder.getAliases();        if (aliases != null) {            for (String alias : aliases) {                registry.registerAlias(beanName, alias);            }        }    }

到此BeanDefinition就被注册到了ClassPathXmlApplicationContext中,还有很多细节没贴出来,自己debug一下很有意思的

 

转载于:https://www.cnblogs.com/zshjava/p/10650425.html

你可能感兴趣的文章
Atitit.计算机图形图像图片处理原理与概论attilax总结
查看>>
于ssh端口转发的深入实例[转 - 当当 - 51CTO技术博客
查看>>
从Python安装到语法基础,这才是初学者都能懂的爬虫教程 ...
查看>>
超级AD远程管理软件
查看>>
Oracle数据库安全加固记录
查看>>
安全运维之:Linux系统账户和登录安全
查看>>
【cocos2d-x从c++到js】17:使用FireFox进行JS远程调试
查看>>
Kafka Offset Storage
查看>>
深度学习笔记之CNN(卷积神经网络)基础
查看>>
JAVA设计模式之【原型模式】
查看>>
Hadoop 添加删除数据节点(datanode)
查看>>
33.8. slb configuration
查看>>
ext的window如何隐藏水平滚动条
查看>>
71.8. Run level shell script to start Oracle 10g services on RedHat Enterprise Linux (RHAS 4)
查看>>
SAP QM Transfer of Inspection Stock
查看>>
全新视觉| 数治省市:SAP大数据构想一切可能
查看>>
ORACLE expdp备份与ORA-31693、ORA-02354、ORA-02149
查看>>
SAP S/4 HANA新变化-信用管理
查看>>
doc-remote-debugging.html
查看>>
DBMS_STATS.GATHER_TABLE_STATS
查看>>