一,Spring核心模块介绍
在这之前,需要看一下这篇文章(https://www.ibm.com/developerworks/cn/java/j-lo-spring-principle/#icomments),
这篇文章把Spring核心模块的轮廓描述的非常清晰,文章把核心模块分为三个:Beans,Context,Core。实际上,Spring的Jar包也是这样分的,Spring-Beans-X.X.X.jar,Spring-Context-X.X.X.jar,Spring-Core-X.X.X.jar。在这三个模块中,最重要的是Beans模块,这个模块用来生成和管理Spring的Beans,Spring所有的功能都是围绕Bean来进行的。
二,Spring核心模块解析
如果 你已经看完了上面介绍的文章,那你对Spring的核心有了大概的了解,接下来我们解析一下每个模块大概的功能。
为了好理解,把上面文章中的图给拿过来参考。
Bean模块:
首先要介绍的是Bean模块,这里介绍一下这个模块比较重要的接口,不介绍接口的实现类。因为这个模块中,可供我们进行配置或定制的地方比较少,用的比较多的还是Context模块中的ApplicationContext接口和它的实现类,所以会在后台多介绍一下ApplicationContext。
重要的接口如下:
- BeanFactory
- HierarchicalBeanFactory
- ConfigurableBeanFactory
- ListableBeanFactory
- ConfigurableListableBeanFactory
- AutowireCapableBeanFactory
BeanFactory:
BeanFactory是Spring bean容器的根接口。它只提供了一些最基本的接口,查找是否包含Bean,取得Bean,Bean是Singleton还是Prototype的等操作。
每个bean都是通过string类型bean name进行标识.这边提供了设计模式单例,原型的替代实现。它的实现类其实就是利用BeanDefinition来生成Bean,而这些BeanDefinition是用名字来实现唯一性的。
HierarchicalBeanFactory:
继承了BeanFactory,增加了两个方法containsLocalBean(String name),getParentBeanFactory(),增加了取得对父容器对象的操作。至于如何使用,可以参看这个例子:http://www.java3z.com/article/article2/spring4.html。但在我们的实际应用中,应该在什么场景下使用这个Factory,还没有想到。
ConfigurableBeanFactory:
这个接口的前面有Configurable,意思是这个一个可以添加一些自定义配置的BeanFactory。例如增加了addBeanPostProcessor这类方法,可以在Bean初始化后,增加一些用户自定义的操作。继承了很多接口,其中有一个接口就是HierarchicalBeanFactory,在继承这个接口后,增加了一个和这个接口相关的方法:setParentBeanFactory (BeanFactory parentBeanFactory)。有了这个方法后,就可以设置父容器对象了。一般HierarchicalBeanFactory和ConfigurableBeanFactory都是成对继承的,如果只继承HierarchicalBeanFactory,而不继承ConfigurableBeanFactory的话,就无法设置父容器了。
ListableBeanFactory:
BeanFactory只定义了取得单个Bean的方法,并没有定义取得所有Bean,和所有BeanName,以及所有BeanDefinition的方法。ListableBeanFactory就定义了上面说的BeanFactory没有定义的方法,可以把它看作是BeanFactory的增强版。比如增加了对BeanDefinition的找到和取得方法containsBeanDefinition, getBeanDefinitionNames, getBeanDefinitionCount等。和取得所有BeanName的方法:getBeanNamesForAnnotation,getBeanNamesForType,它们的返回类型都是String[]。和取得所有Bean的方法getBeansOfType,getBeansWithAnnotation等。
ConfigurableListableBeanFactory:
看名字就能看出来,它是一个可配置的ListableBeanFactory。这个接口集成了很多接口算是一个大集合。除了实现了ConfigurableBeanFactory的功能,还提供了分析和修改BeanDefinition,预先初始化singleton的功能。
AutowireCapableBeanFactory:
在BeanFactory基础上实现对已存在实例的管理。可以使用这个接口集成其它框架,捆绑并填充并不由Spring管理生命周期并已存在的实例.像集成WebWork的Actions 和Tapestry Page就很实用。一般应用开发者不会使用这个接口,所以像ApplicationContext这样的外观实现类不会实现这个接口,如果真手痒痒可以通过ApplicationContext的getAutowireCapableBeanFactory接口获取。
关于实现类,其中的一个实现类就是DefaultListableBeanFactory,它是一非常重要的IoC实现。这个类实现了XmlBeanFactory就是使用这个类作为基类。ApplicationContext接口的实现类(AbstractRefreshableApplicationContext),也是通过持有DefaultListableBeanFactory的对象,来实现IoC容器的基本功能。
对于XmlBeanFactory这个类,它也是实现类之一,它的实现方式是以编程的方式来使用DefaultListableBeanFactory。从中可以看到IoC容器使用的一些基本过程。尽管我们在应用中使用IoC容器时,很少会使用这种原始的方式,但了解一下这个基本过程,对我们理解IoC容器的工作原理是非常有帮助的。因为这个编程式使用容器的过程,很清楚地揭示了IoC容器实现中的那些关键的类(比如:Resource,DefaultListableBeanFactory和BeanDefinitionReader)之间的关系,例如他们是如何把IoC容器的功能解耦合的,又是如何在一起为IoC容器服务的。
例如:XmlBeanFactory的实现方式就是以下的代码
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
1,private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
声明一个Reader,并把自己(XmlBeanFactory)当做参数传Reader。因为DefaultListableBeanFactory实现了ResourceLoader接口,使用这个功能来读取Resource。
2,this.reader.loadBeanDefinitions(resource);
使用Reader的loadBeanDefinitions方法,来读取Resource中的BeanDefinition,把Bean加载到Factory里(todo:应该是,还没有仔细读源码去验证。。。)。
上面使用了简单的2步就实现了一个XmlBeanFactory,我们也可以尝试去做做,例如:
ClassPathResource res = new ClassPathResource("beans.xml")
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(res);
看看,是不是很简单!
最后,在《SPRING技术内幕》上说,下面的这个继承路线,是一条主要的BeanFactory的设计路径
BeanFactory->HierarchicalBeanFactory->ConfigurableBeanFactory
看了一下,可能是因为就是上面的图画的一样,ConfigurableListableBeanFactory接口和AbstractAutowireCapableBeanFactory抽象类都实现了这个接口,所以说它是一条主要的设计路径吧。
Bean模块的接口就先介绍这些,接下来我们介绍ApplicationContext的相关接口和实现类,以及一些源码的介绍。
Context模块:
这个模块中,非常重要的接口就是ApplicationContext接口。这个接口继承了BeanFactory接口,也就是说它也有管理Bean的功能。但他和BeanFactory有什么不同呢?它是在BeanFactory基础之上,又增加了国际化,容器事件(可以监听容器的一些事件,来做一些操作)等。下面介绍和ApplicationContext接口相关的一些接口。介绍之前,我们先看一下接口的关系图,有助于理解。
- ApplicationEventPublisher
- BeanFactory
- EnvironmentCapable
- HierarchicalBeanFactory
- ListableBeanFactory
- MessageSource
- ResourceLoader
- ResourcePatternResolver
(BeanFactory,HierarchicalBeanFactory,ListableBeanFactory在前面已经介绍完了,就不在再介绍了)
ApplicationEventPublisher:
spring的事件发布者接口,定义了发布事件的接口方法publishEvent。因为ApplicationContext实现了该接口,因此spring的ApplicationContext实例具有发布事件的功能(publishEvent方法在AbstractApplicationContext中有实现)。在使用的时候,只需要把ApplicationEventPublisher的引用定义到ApplicationEventPublisherAware的实现中,spring容器会完成对ApplicationEventPublisher的注入。
下面是两个关于ApplicationEventPublisher的文章,有兴趣可以看一下:
http://www.cnblogs.com/beenupper/archive/2012/12/01/2797303.html
http://enjiex.iteye.com/blog/1070094
EnvironmentCapable:
是一个包含和暴露Enviroment引用的组件。所有的spring的application context都继承了EnvironmentCapable接口。
Enviroment是干什么用的呢?Environment包含两方便的抽象,profile和 property。profile的作用是,根据定义的profile,让哪一组Bean的定义生效,例如:用profile来定义不同环境的数据库连接。后者是提供方便的抽象,应用程序可以方便的访问 system property 环境变量自定义属性等。
关于Environment的文章,有兴趣可以看一下:http://blog.csdn.net/windsunmoon/article/details/45197361
MessageSource:
这个策略模式的接口(这个接口主要用于实现设置模式中的策略模式)是整个国际化消息支持的基础,它定义了国际化的主要接口。
关于之方面的文章,有兴趣可以看一下:http://book.51cto.com/art/201004/193394.htm
ResourceLoader:
这个策略模式的接口(这个接口主要用于实现设置模式中的策略模式)加载Resources。例如:ClassPathResource或FileSystemResources等。
关于Resoure,前面说了一点,Resource 接口是具体资源访问策略的抽象,也是所有资源访问类所实现的接口。Resource 接口主要提供了如下几个方法:
getInputStream():定位并打开资源,返回资源对应的输入流。每次调用都返回新的输入流。调用者必须负责关闭输入流。
exists():返回 Resource 所指向的资源是否存在。
isOpen():返回资源文件是否打开,如果资源文件不能多次读取,每次读取结束应该显式关闭,以防止资源泄漏。
getDescription():返回资源的描述信息,通常用于资源处理出错时输出该信息,通常是全限定文件名或实际 URL。
getFile:返回资源对应的 File 对象。
getURL:返回资源对应的 URL 对象。
从方法来看,这个接口主要定义了一些访问资源的方式,为了方便使用。功能强大的抽象类AbstractApplicationContext的基类DefaultResourceLoader,只实现了一个接口,就是这个接口。FileSystemXmlApplicationContext等实现类,都是从AbstractApplicationContext一点点继承过来的。
ResourcePatternResolver:
这个策略模式的接口(这个接口主要用于实现设置模式中的策略模式)用来把一个路径解析成Resources对象。这个接口继承了ResourceLoader接口,是ResourceLoader接口的一个扩展。它ResourceLoader接口相比,重载了一个方法getResources(String locationPattern),这个方法返回值是Resource数组(Resource[]),而ResourceLoader接口的返回值只是单个Resources。Spring提供了一个ResourcePatternResolver实现PathMatchingResourcePatternResolver(它提供了很多方法来添加和查找Resources),
它是基于模式匹配的,默认使用AntPathMatcher进行路径匹配,它除了支持ResourceLoader支持的前缀外,还额外支持“classpath*:”用于加载所有匹配的类路径Resource,ResourceLoader不支持前缀“classpath*:”:
介绍完上面的接口,我们就知道了ApplicationContext这个接口大概有什么功能了。
我们从FileSystemXmlApplicationContext再来看看接口的实现类,看看它都实现了哪些接口和实现类的功能大概是什么。
它的继承结构如下:
java.lang.Object
org.springframework.core.io.DefaultResourceLoader
org.springframework.context.support.AbstractApplicationContext
org.springframework.context.support.AbstractRefreshableApplicationContext
org.springframework.context.support.AbstractRefreshableConfigApplicationContext
org.springframework.context.support.AbstractXmlApplicationContext
org.springframework.context.support.FileSystemXmlApplicationContext
DefaultResourceLoader:
这个实现类,实现了ResourceLoader接口,说明这个实现类具有通过给定的路径加载Resource的功能。由此可见,ApplicationContext第一个实现类的功能,就是加载Resources功能。
AbstractApplicationContext:
这个实现类,继承了DefaultResourceLoader这个类,并且实现了ConfigurableApplicationContext接口。ConfigurableApplicationContext这个接口实现了ApplicationContext接口和Lifecycle、Closeable两个接口。既然它实现了ApplicationContext接口,也就说明它实现了上面讲的那些接口。所以AbstractApplicationContext实现类,算是一个核心实现类了。
AbstractRefreshableApplicationContext:
从名字可以看出来,主要实现了刷新Context内部的BeanFactory功能,通过refreshBeanFactory()方法。看了原代码可以看出,在AbstractApplicationContext类中,实现了“准备刷新,获取新BeanFactory,配置新的BeanFactory”等功能。但具体的实现细节没有被实现,还是抽象方法,就像refreshBeanFactory()方法,AbstractRefreshableApplicationContext类和GenericApplicationContext类都实现了这个抽象方法,做了不同的实现。这个类里有一个要被子类实现的抽象方法loadBeanDefinitions(DefaultListableBeanFactory beanFactory)。这个实现类没有实现其它接口。
AbstractRefreshableConfigApplicationContext:
它实现了BeanNameAware, InitializingBean这两个接口。从源代码可以看出,这个类主要作用是用来配置Resource的路径。这个方法在FileSystemXmlApplicationContext的构造函数中被调用。它配置路径的方法主要是和通过和Environment一起来解析路径。
AbstractXmlApplicationContext:这个类实现了读取XML类型的Resources。读取XML类型Resources,是使用了XmlBeanDefinitionReader,通过这个Reader来读取XML类型的Resources。这个实现类没有实现其它接口。
FileSystemXmlApplicationContext:基本的功能在基类上都已经实现了。这个类主要重写了getResourceByPath(String path) 方法,返回一个FileSystemResource类型的Resource。同样继承于AbstractXmlApplicationContext类的ClassPathXmlApplicationContext类,就没有实现这个方法,这是什么?这个方法最早是在DefaultResourceLoader定义的,在定义时默认就是使用了ClassPathContextResource做为返回Resource类型。这个实现类没有实现其它接口。