呵呵,无论从调用关系、方法名称和注释都能敏感的感觉到找对地方了,
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框架核心源代码分析及感悟》 Spring框架作为Java企业级应用开发的基石,其强大的功能和灵活性深受开发者喜爱。深入理解Spring的核心源代码,不仅有助于我们更好地使用这个框架,还能提升我们的编程技艺和对...
Spring框架是Java开发中不可或缺的一部分,它以依赖注入(Dependency Injection,简称DI)和面向切面编程(Aspect-Oriented Programming,简称AOP)为核心,提供了丰富的功能来简化企业级应用的开发。当我们深入理解...
《Spring Boot 揭秘与实战》系列源代码涉及了使用Spring Boot框架进行开发的一系列实践案例,包括但不限于配置、编码、测试以及部署等方面。作为当今流行的开源框架,Spring Boot简化了基于Spring的应用开发,通过...
1. **SpringBoot**:SpringBoot是Spring平台和第三库的集成,它利用了Spring框架的核心特性,简化了配置文件,实现了自动配置,并且支持快速构建独立的Spring应用程序。 - **优点**:易于理解和使用,可快速搭建...
源代码将被合理组织,并包含适当的注释,以便其他开发者理解和维护。此外,代码将遵循代码规范和最佳实践,确保代码质量。 系统的用户界面将采用现代化的Web设计语言,如HTML5、CSS3和JavaScript等,以提供响应式和...
【标题】"20170117-171626-49634_java书城系统_网上书城_源码"所指的是一个基于Java编程语言开发的网上书城系统源代码。这个系统可能包含了实现网上书店核心功能的所有必要组件,如用户管理、书籍展示、购物车、订单...
在平台的实现过程中,sheuquyanglaofuwu这一子文件夹包含了所有的源代码文件,这些源码文件是整个平台的核心,通过它们的整合和编译,最终形成了可供部署和运行的养老服务应用程序。 springboot187社区养老服务平台...
本项目是一个基于Java语言,采用ssm(Spring+SpringMVC+MyBatis)框架开发的电影推荐系统,其核心算法是协同过滤(Collaborative Filtering),并提供了完整的源代码、说明文档以及演示PPT。 协同过滤是推荐系统中...