微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ClassPathXMLApplicationContext上下文加载过程

今天看了一下《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事件,然后按照正常的初始化依次初始化父类

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

        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }
    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.
     * <p>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.
     * <p>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一下很有意思的

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。