Spring源码分析之IOC2

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

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

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

本篇将介绍下ApplicationContext上下文方式的得到bean的源码

上篇用到一个列子

    ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");

就从ClassPathXmlApplicationContext入手吧

找到它的构造函数

    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
            this(new String[] {configLocation}, true, null);
        }

调用的是上面的这个

里面又调用另一个构造函数

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

            super(parent);
            setConfigLocations(configLocations);
            if (refresh) {
                refresh();
            }
        }

看到setConfigLocations(configLocations);这个方法,在跟进去咯

    public void setConfigLocations(String[] locations) {
            if (locations != null) {
                Assert.noNullElements(locations, "Config locations must not be null");
                this.configLocations = new String[locations.length];
                for (int i = 0; i < locations.length; i++) {
                    this.configLocations[i] = resolvePath(locations[i]).trim();
                }
            }
            else {
                this.configLocations = null;
            }
        }

这里面的关键点是


    this.configLocations = new String[locations.length];
    for (int i = 0; i < locations.length; i++) {
                    this.configLocations[i] = resolvePath(locations[i]).trim();
                }

这里面有个属性configLocations其定义如下

    private String[] configLocations;

,就是个数组来存放路径的,

在上面关键代码第一行初始化,然后for语句段就是解析路径的。resolvePath方法就不跟进咯,OK,在回到上上面的构造函数里,解释了setConfigLocations方法,在往下走咯。就来到

    if (refresh) {
                refresh();
            }
        }

由于传进来的refresh参数是true,所以refresh()方法就会执行咯。好吧,上refresh这牛X的方法

    public void refresh() throws BeansException, IllegalStateException {
            synchronized (this.startupShutdownMonitor) {
                // Prepare this context for refreshing.
                prepareRefresh();

                // Tell the subclass to refresh the internal bean factory.
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

                // Prepare the bean factory for use in this context.
                prepareBeanFactory(beanFactory);

                try {
                    // Allows post-processing of the bean factory in context subclasses.
                    postProcessBeanFactory(beanFactory);

                    // Invoke factory processors registered as beans in the context.
                    invokeBeanFactoryPostProcessors(beanFactory);

                    // Register bean processors that intercept bean creation.
                    registerBeanPostProcessors(beanFactory);

                    // Initialize message source for this context.
                    initMessageSource();

                    // Initialize event multicaster for this context.
                    initApplicationEventMulticaster();

                    // Initialize other special beans in specific context subclasses.
                    onRefresh();

                    // Check for listener beans and register them.
                    registerListeners();

                    // Instantiate all remaining (non-lazy-init) singletons.
                    finishBeanFactoryInitialization(beanFactory);

                    // Last step: publish corresponding event.
                    finishRefresh();
                }

                catch (BeansException ex) {
                    // Destroy already created singletons to avoid dangling resources.
                    destroyBeans();

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

                    // Propagate exception to caller.
                    throw ex;
                }
            }
        }

这方法的东西好丰富哦,就各点来击破咯

first 这 synchronized (this.startupShutdownMonitor) 都懂得啥下面first的方法是prepareRefresh();这方法可以忽略咯,就是setting its startup date,

second 就是ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

这里调用的是父类AbstractRefreshableApplicationContext的方法obtainFreshBeanFactory();

源码如下

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

这里面又有别的方法调用咯,第一个方法实现

    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);
            }
        }

这里面又调用了createBeanFactory(),看方法就明白意思了啥,就是创建BeanFactory.

    protected DefaultListableBeanFactory createBeanFactory() {
            return new DefaultListableBeanFactory(getInternalParentBeanFactory());
        }

在回到refreshBeanFactory()方法中,接下来就是调用loadBeanDefinitions(beanFactory),看意思就是加载beanDefinition了,这个方法是在AbstractRefreshableConfigApplicationContext的子类AbstractXmlApplicationContext实现的

    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.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);
        }

这里面创建了一个XmlBeanDefinitionReader 对象,这玩意就是来读取基于XML bean定义的

。而beanDefinitionReader.setResourceLoader(this);这句咯是为reader配置resourceLoader,因为DefaultResourceLoader是父类,所以this可以直接被使用。initBeanDefinitionReader(beanDefinitionReader);是初始化,而loadBeanDefinitions(beanDefinitionReader);类容多了


    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);
            }
        }

这里面的有两种方式加载bean咯,一个是Resouce,一个是String,来看下reader.loadBeanDefinitions(configResources);的实现

    public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
            Assert.notNull(resources, "Resource array must not be null");
            int counter = 0;
            for (Resource resource : resources) {
                counter += loadBeanDefinitions(resource);
            }
            return counter;
        }

这里面又调用了 loadBeanDefinitions()这方式的实现是在XmlBeanDefinitionReader中,

    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
            Assert.notNull(encodedResource, "EncodedResource must not be null");
            if (logger.isInfoEnabled()) {
                logger.info("Loading XML bean definitions from " + encodedResource.getResource());
            }

            Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
            if (currentResources == null) {
                currentResources = new HashSet<EncodedResource>(4);
                this.resourcesCurrentlyBeingLoaded.set(currentResources);
            }
            if (!currentResources.add(encodedResource)) {
                throw new BeanDefinitionStoreException(
                        "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
            }
            try {
                InputStream inputStream = encodedResource.getResource().getInputStream();
                try {
                    InputSource inputSource = new InputSource(inputStream);
                    if (encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
                    return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
                }
                finally {
                    inputStream.close();
                }
            }
            catch (IOException ex) {
                throw new BeanDefinitionStoreException(
                        "IOException parsing XML document from " + encodedResource.getResource(), ex);
            }
            finally {
                currentResources.remove(encodedResource);
                if (currentResources.isEmpty()) {
                    this.resourcesCurrentlyBeingLoaded.set(null);
                }
            }
        }

这代码的主要意思是,的到xml文件,并得到IO的InputSource.在返回时有句doLoadBeanDefinitions(inputSource, encodedResource.getResource());这发放的源码

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
                throws BeanDefinitionStoreException {
            try {
                int validationMode = getValidationModeForResource(resource);
                Document doc = this.documentLoader.loadDocument(
                        inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
                return registerBeanDefinitions(doc, resource);
            }
            catch (BeanDefinitionStoreException ex) {
                throw ex;
            }
            catch (SAXParseException ex) {
                throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                        "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
            }
            catch (SAXException ex) {
                throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                        "XML document from " + resource + " is invalid", ex);
            }
            catch (ParserConfigurationException ex) {
                throw new BeanDefinitionStoreException(resource.getDescription(),
                        "Parser configuration exception parsing XML from " + resource, ex);
            }
            catch (IOException ex) {
                throw new BeanDefinitionStoreException(resource.getDescription(),
                        "IOException parsing XML document from " + resource, ex);
            }
            catch (Throwable ex) {
                throw new BeanDefinitionStoreException(resource.getDescription(),
                        "Unexpected exception parsing XML document from " + resource, ex);
            }
        }

这方法就是加载bean定义在制定的XML文件。主要代码是

    Document doc = this.documentLoader.loadDocument(
                        inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());

documentLoader的实例 private DocumentLoader documentLoader = new DefaultDocumentLoader();它主要是取得XML文件Document对象。这里就不在详述了,时间有限咯。

在取得Document对象后,就要开始注册咯registerBeanDefinitions(doc, resource);就由这方法搞定咯

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
            // Read document based on new BeanDefinitionDocumentReader SPI.
            BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
            int countBefore = getRegistry().getBeanDefinitionCount();
            documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
            return getRegistry().getBeanDefinitionCount() - countBefore;
        }

来源:http://ddrv.cn

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring源码分析之IOC2

评论 抢沙发

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

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

支付宝扫一扫打赏

微信扫一扫打赏