Spring框架核心源代码的分析及其感受-2

呵呵,无论从调用关系、方法名称和注释都能敏感的感觉到找对地方了, prepareRefresh 的注释写“ refreshing” ,真搞不清这个概念,先进去看看:

protected void prepareRefresh() {

       this.startupDate = System.currentTimeMillis();

 

       synchronized (this.activeMonitor) {

           this.active = true;

       }

 

       if (logger.isInfoEnabled()) {

           logger.info("Refreshing " + this);

       }

    }
 

 

发现,就是重置一个标志位(先不要急于对看见的东西着迷,我说的是看到和目标暂时无关的东西),我发现貌似和我找的东西无关,先退到到主程序再说 ( 这只是一个小例子,如果遇到一个大的和查找目的无关的代码,你先大体看看,然后再决定是不是马上退回去,不要在这里浪费时间,迟早还会回来的,这可以帮助你减少陷入代码丛林中的几率 ) ,接下来看 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

发现 obtainFreshBeanFactory() 方法的实现是:

 

 

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {

       refreshBeanFactory();

       ConfigurableListableBeanFactory beanFactory = getBeanFactory();

       if (logger.isDebugEnabled()) {

           logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);

       }

       return beanFactory;

    }
 

对于 refreshBeanFactory 方法:

protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
 

唉?一个抽象方法!谁实现它,反正不是 AbstractApplicationContext! 想退回去?且慢,当你不明确知道一个方法调用在干什么,尤其是抽象方法,你最好先找找它的实现,再想退回去也不迟,因为只要你忽略掉一个部分,就会对后面的代码的理解产生偏差,但是不要太深入了,这样既可以保证不会掉到实现的代码丛林中,也不会失掉什么关键点!幸好 Eclipse 有查看一个类、方法实现关系的工具,请按 F4, 看来有个好工具对学习是有好的帮助的,所以千万不要低估工具的力量!另外你看 ConfigurableListableBeanFactory beanFactory = getBeanFactory(); 只是取一个对象工厂!也是抽象方法,你可以也按我上面和下面介绍的办法去分析,结果就是一个创建对象工厂实例的逻辑,没有加载 XML 的逻辑!这里就不累述了,

 

发现这样一个实现关系,父类中有 DefaultResourceLoader, Resource 加载的能力吧? XML 配置文件不就是一种资源吗?看来靠近了想要到达的地方了,至少不会太远了,于是你想先进去看看,不过我还是建议你看看这个实现关系中的其他类,做到心里有数,至少知道这个地图,不然你一个劲往里钻,没有记不起来如何出来了,尤其是类多了时候,于是我先看了一下上面这个结构,知道下面还有两个 ApplicationContext 实现, Ok, 先看看这个资源加载器,因为从名字来看更接近我想找的东西!

public class DefaultResourceLoader implements ResourceLoader {

 

    private ClassLoader classLoader;

    public DefaultResourceLoader() {

       this.classLoader = ClassUtils.getDefaultClassLoader();

    }

    public DefaultResourceLoader(ClassLoader classLoader) {

       this.classLoader = classLoader;

    }

    public void setClassLoader(ClassLoader classLoader) {

       this.classLoader = classLoader;

    }

 

    public ClassLoader getClassLoader() {

       return (this.classLoader != null ? this.classLoader : ClassUtils.getDefaultClassLoader());

    }

    public Resource getResource(String location) {

       Assert.notNull(location, "Location must not be null");

       if (location.startsWith(CLASSPATH_URL_PREFIX)) {

           return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());

       }

       else {

           try {

              URL url = new URL(location);

              return new UrlResource(url);

           }

           catch (MalformedURLException ex) {

              return getResourceByPath(location);

           }

       }

    }

 

    protected Resource getResourceByPath(String path) {

       return new ClassPathContextResource(path, getClassLoader());

    }

 

    private static class ClassPathContextResource extends ClassPathResource implements ContextResource {

 

       public ClassPathContextResource(String path, ClassLoader classLoader) {

           super(path, classLoader);

       }

 

       public String getPathWithinContext() {

           return getPath();

       }

 

       @Override

       public Resource createRelative(String relativePath) {

           String pathToUse = StringUtils.applyRelativePath(getPath(), relativePath);

           return new ClassPathContextResource(pathToUse, getClassLoader());

       }

    }

 

}
 

 

好了,我可以肯定的一点是这里是加载 XML 文件的地方,但且不是解析的地方,为什么?精通 Java 的家伙都知道资源加载这回事,也知道 Resource 接口这样的东西干什么用的,从代码上看只是加载资源而已,好了!到此为止,我必须退回去一步了,幸好我之前浏览了一下类实现的结构图, AbstractApplicationContext 下面有两个 ApplicationContext 实现,当你每次看结构时最好做个笔记,在 ApplicationContext 继承体系中,你也能看到这两个类,这样你就清楚这些类和 FileSystemXmlApplicationContext 相对关系了,也知道和 AbtractApplicationContext 之间是个什么关系了,因为我们在 FileSystemXmlApplicationContext 中发现入口的驱动方法是 Refresh 方法,而 Refresh 方法是在 AbstractApplicationContext 中实现的,而 Refresh 方法调用一个方法来实现加载和解析,而这个解析过程被推迟到子类实现,而 FileSystemXmlApplicationContext 并没有实现,只能是处于它们之间的一个 ApplicationContext 来实现的(有关为什么会有这样一个“复杂”的继承体系 -ApllicationContext 下又有一个 ApplicationContext, 我会慢慢给大家讲清楚,这也和软件的设计思想有关,而且是最朴素的理念!),基于这种分析,我就在 AbstractRefreshableApplicationContext GenericApplicationContext 之间做个抉择!因为 refresh 这个方法名让我联想到可能需要仔细看看 AbstractRefreshableApplicationContext !另外 FileSystemXmlAppliactionContext 的父类中有 AbstractRefreshableApplicationContext ,从地图中分析,从名称中分析(一般像这样著名开源框架都能遵守很好命名规范,否则就不敢拿出来开源了,会被大家骂死)得到最大的可能性是 AbstractRefreshableApplicationContext !我们就试着打开看看吧!

终于发现 refreshBeanFactory 方法实现的地方了:

@Override

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

       }

    }
 

 

Very good! 逻辑简单并且明了!前面是如果一个 BeanFactory 存在就摧毁之,然后再创建一个,哈哈,也就是说是实例化 ApplicationContext 时实际上一个重启动作,也就是清空 AppliactionContext 缓存的对象(容器倒出所有的水或者东西),而且你发现重新创建的 DefaultListableBeanFactory, 我猜这个也许是 ApplicationContext 其他行为的核心,比如对象创建,依赖注入和 AOP 等等!再往下看,一下子盯住一个方法那就是 loadBeanDefinitions(beanFactory) ,好了,凡是经常用 Spring 的人,都知道 BeanDefinition 是干什么的,就是里面存有对象依赖关系的元数据,而这些元数据都是在 XML 中定义的,我兴高采烈地进入这个方法来看一看:

protected abstract void loadBeanDefinitions (DefaultListableBeanFactory beanFactory)

           throws BeansException, IOException

哈哈,又一次触雷,你可能会问,为什么会这么设计,非得子类去实现吗?这个问题是个设计理念的问题,等我把 IOC 的原理都给你展示清楚,你在解释为什么这么设计,会更有说服力的。

现在看来 loadBeanDefinitions 的实现极大可能是在 AbstractRefreshableApplicationContext FileSystemXmlAppliactionContext 之间的 ApplicationContext! 看来记录一下类继承结构很有用啊!而这个之间,就两个类了: AbstractRefreshableConfigApplicationContext AbstractXmlApplicationContext, 范围已近很小了,我们这时大可以仔细看看这两个类了看看哪个才是真实现 loadBeanDefinitions 方法的!检视一下,发现,是在 AbstractXmlApplicationContext 中,

@Override

 

你可能感兴趣的:(spring,数据结构,xml,bean,框架)