从ClassPathXmlApplicationContext中看spring在web中如何运行


十一小长假在家玩和太happy了。根本没有时间看java之类的东西,今天是假日最后一天,所以会把上次的补上

个人感觉在web中看spring如何解析如何运行是一件比较难的事,spring附加了在我们看来是没有用的代码,但是既然它写了肯定是有用处的,这是我们初级程序员可以学习的地方。好了不多说了。看代码

ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
我们来看看ClassPathXmlApplicationContext的构造器

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

为什么我的反编译有行数的。。你问我。。我也不知道。。。。

this是当前类继续看

   public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
/*     */     throws BeansException
/*     */   {
/* 136 */     super(parent);
/* 137 */     setConfigLocations(configLocations);
/* 138 */     if (refresh)
/* 139 */       refresh();
/*     */   }
先看下super。。。super调用的是父类构造器

看下AbstractXmlApplicationContext

  public AbstractXmlApplicationContext(ApplicationContext parent)
/*     */   {
/*  58 */     super(parent);
/*     */   }
还是一样。。继续看

看下AbstractRefreshableConfigApplicationContext

public AbstractRefreshableConfigApplicationContext(ApplicationContext parent)
  {
    super(parent);
  }

还是一样。继续看下AbstractRefreshableApplicationContext

 public AbstractRefreshableApplicationContext(ApplicationContext parent)
  {
    super(parent);
  }


看下AbstractApplicationContext

 public AbstractApplicationContext(ApplicationContext parent)
  {
    this.logger = LogFactory.getLog(getClass());

    this.id = ObjectUtils.identityToString(this);

    this.beanFactoryPostProcessors = new ArrayList();

    this.active = false;

    this.activeMonitor = new Object();

    this.startupShutdownMonitor = new Object();

    this.applicationListeners = new ArrayList();

    this.parent = parent;
    this.resourcePatternResolver = getResourcePatternResolver();
  }

上面没有什么好看的。无非是初始化我们看下最后this.resourcePatternResolver = getResourcePatternResolver();

protected ResourcePatternResolver getResourcePatternResolver()
  {
    return new PathMatchingResourcePatternResolver(this);
  }

这是我自己写的PathMatchingResourcePatternResolver

public static void main(String[] args){
		ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();   
	       
	    Resource[] resources = null;
		try {
			resources = resolver.getResources("file:"+System.getProperty("user.dir")+"/WebRoot/WEB-INF/spring01/*/*.xml");
			System.out.println(resources[0].getURL()); 
			System.out.println(resources.length);
		} catch (IOException e) {
			e.printStackTrace();
		}   
	}


这个类是干嘛的就是匹配*的,所以我们配spring.xml不用一个一个去配了。直接用这类,就行了。。

AbstractApplicationContext中主要是初始化。看不看意义不大,关键看下这个

 public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
    throws BeansException
  {
    super(parent);
    setConfigLocations(configLocations);
    if (refresh)
      refresh();
  }

setConfigLocations(configLocations);这个不用说了吧。。。更简单了,把spring.xml的名字放进来嘛

看下if (refresh)

 refresh();

其实refresh肯定为true,这个我们应该能感觉到,事实也是这样

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

直接把true传过来了

关键是看下refresh()这个方法。。我们来看下。。。。refresh()这个方法是在AbstractApplicationContext这个类中,spring的目的是解耦合,但是他自己写的确实耦合度不是一般的高

 public void refresh() throws BeansException, IllegalStateException
  {
    synchronized (this.startupShutdownMonitor)
    {
      prepareRefresh();

      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      prepareBeanFactory(beanFactory);
      try
      {
        postProcessBeanFactory(beanFactory);

        invokeBeanFactoryPostProcessors(beanFactory);

        registerBeanPostProcessors(beanFactory);

        initMessageSource();

        initApplicationEventMulticaster();

        onRefresh();

        registerListeners();

        finishBeanFactoryInitialization(beanFactory);

        finishRefresh();
      }
      catch (BeansException ex)
      {
        beanFactory.destroySingletons();

        cancelRefresh(ex);

        throw ex;
      }
    }
  }

synchronized (this.startupShutdownMonitor) {

 prepareRefresh();
这个我们这里就不看了。无非是同步一些东西,看也看不懂,继续


 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

我们看下obtainFreshBeanFactory这个方法

protected ConfigurableListableBeanFactory obtainFreshBeanFactory()
  {
    refreshBeanFactory();
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();

    if (this.logger.isInfoEnabled()) {
      this.logger.info("Bean factory for application context [" + getId() + "]: " + ObjectUtils.identityToString(beanFactory));
    }

    if (this.logger.isDebugEnabled()) {
      this.logger.debug(beanFactory.getBeanDefinitionCount() + " beans defined in " + this);
    }

    return beanFactory;
  }


看下refreshBeanFactory()这个方法

 protected abstract void refreshBeanFactory()
    throws BeansException, IllegalStateException;

在他自己类中是这样写的。我们是看父类代码还是看子类代码呢。。。肯定是看子类的代码吗。abstract在,,那不用看了。。去他的子类找一找

在AbstractRefreshableApplicationContext中找到了refreshBeanFactory()的实现

 protected final void refreshBeanFactory()
    throws BeansException
  {
    if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
    }
    try {
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      customizeBeanFactory(beanFactory);
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
        this.beanFactory = beanFactory;
      }
    }
    catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing XML document for application context [" + getDisplayName() + "]", ex);
    }
  }


我们看下第一个if()中写的是hasBeanFactory()英文意思写得非常明白是滞有bean工厂吗,有的话销毁beans还有关闭bean工厂吗。如果你是第一次初始化就直接看下try-catch里面代码好了

DefaultListableBeanFactory beanFactory = createBeanFactory();

这个是实例化beanFactory其实我们不用看的。浪费时间。。。。

继续

customizeBeanFactory(beanFactory);定制客户的专属bean工厂也不用看的

关键的来了

loadBeanDefinitions(beanFactory);我们看下原码

在它的本类中

protected abstract void loadBeanDefinitions(DefaultListableBeanFactory paramDefaultListableBeanFactory)
    throws IOException, BeansException;


写的又是这样一句话。。。。看子类嘛。。。。其实第一次看真的会晕

在AbstractXmlApplicationContext这个类中实现了loadBeanDefinitions的方法。看下

 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
    throws IOException
  {
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

    initBeanDefinitionReader(beanDefinitionReader);
    loadBeanDefinitions(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);
  }

getConfigResources();

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

你说看了有什么用。。。直接不用看

String[] configLocations = getConfigLocations();

我们刚刚在refresh()上面是不是setConfigLocations()了;

那这里我们不就是直接获得了嘛,简单

if (configLocations != null)

reader.loadBeanDefinitions(configLocations);

这里configLocations肯定不为空啊。

看下

public int loadBeanDefinitions(String[] locations) throws BeanDefinitionStoreException
  {
    Assert.notNull(locations, "Location array must not be null");
    int counter = 0;
    for (int i = 0; i < locations.length; ++i)
      <pre class="html" name="code">counter += loadBeanDefinitions(locations[i]);

    return counter;
  }
 

看下

counter += loadBeanDefinitions(locations[i]);

我就直接copy出来了

public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
    return loadBeanDefinitions(location, null);
  }

  public int loadBeanDefinitions(String location, Set actualResources)
    throws BeanDefinitionStoreException
  {
    ResourceLoader resourceLoader = getResourceLoader();
    if (resourceLoader == null) {
      throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
    }

    if (resourceLoader instanceof ResourcePatternResolver) {
      try
      {
        Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
        loadCount = loadBeanDefinitions(resources);
        if (actualResources != null)
          for (int i = 0; i < resources.length; ++i)
            actualResources.add(resources[i]);


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

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

    }

    Resource resource = resourceLoader.getResource(location);
    int loadCount = loadBeanDefinitions(resource);
    if (actualResources != null)
      actualResources.add(resource);

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

    return loadCount;
  }


Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);

这个方法可以去看看上面我写的PathMatchingResourcePatternResolver这个类。。你就知道干嘛的了

loadCount = loadBeanDefinitions(resources);

主要看下这个

 public int loadBeanDefinitions(Resource[] resources) throws BeanDefinitionStoreException
  {
    Assert.notNull(resources, "Resource array must not be null");
    int counter = 0;
    for (int i = 0; i < resources.length; ++i)
      counter += loadBeanDefinitions(resources[i]);

    return counter;
  }

点开loadBeanDefinitions里进入到BeanDefiitionReader中的方法

public abstract int loadBeanDefinitions(Resource paramResource)
    throws BeanDefinitionStoreException;

还是看子类啊

看下XmlBeanDifintionReader

 public int loadBeanDefinitions(Resource resource)
    throws BeanDefinitionStoreException
  {
    return loadBeanDefinitions(new EncodedResource(resource)); } 


 

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

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


看下doLoadBeanDefinitions这个类

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
    throws BeanDefinitionStoreException
  {
    int validationMode;
    try
    {
      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);
    }
  }


看到Document这个类了吗,肯定是dom解析xml吗。。这里我们不用管了。解析xml不是spring的范围。所以不用太在意。下一篇会总结一下。。。其实也不用总结了。。。差不多就是这个过程 。web中也是这样调的。。。。。。。。看懂了这个。。。差不多。。。web也没有问题

个人写得比较详细,第一个是让自己更好的学习,也希望大家有问题可以和我说。。大家一起进步


 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值