在Spring IoC容器的设计中,我们可以看到两个主要的容器系列,一个是实现
BeanFactory
接口的简单容器系列,这系列容器只实现了容器的最甚本功能.另一个是ApplicationContext
应用上下文,它作为容器的高级形态而存在。应用上下文在简单容器的基础上,增加了许多面向框架的特性,同时对应用环境作了许多适配。有了这两种墓本的容器系列.基本上可以满足用户对IoC容器使用的大部分需求了。
loC容器的接口
loC容器的接口设计图如下:
-
从接口
BeanFactory
到HierarchicalBeanFactory
,再到Configurable Bean Factory
,是一条主要的BeanFactory设计路径。在这条接口设计路径中,BeanFactory接口定义了基本的IoC容器的规范。在这个接口定义中.包括了getBean()
这样的IoC容器的基本方法(通过这个方法可以从容器中取得Bean)。而HierarchicalBeanFactory
接口在继承了eanFactory
的基本接口之后.增加了getParentBeanFactory ()
的接口功能.使BeanFactory其备了双亲IoC容器的管理功能。在接下来的ConfigurableBeanFactory
接口中,主要定义了一些对BeanFactory的配置功能,比如通过setParentBeanFactory()
设置双亲IoC容器,通过addBeanPostProcessor()配iBean后里处理器,等等。通过这些接口设计的叠加,定义了BeanFactory就是简单IoC容器的基本功能。 -
第二条接口设计主线是以
ApplicationContext
应用上下文接口为核心的接口设计。这里涉及的主要接口设计有,从Bean Factory
到ListableBeanFactory
,再到ApplicationContext
,再到我们常用的WebApplicationContext
或者ConfigurableApplicationContext
接口。我们常用的应用上下文甚本上都是ConfigurableApplicationContext
或者WebApplicationContcxt
的实现。在这个接口体系中,ListableBeanFactory
和HierarchicalBeanFactory
两个接口.连接BeanFactory接口定义和ApplicationConext
应用上下文的接口定义。在ListableBeanFactory接口中,细化了许多BeanFactory的接口功能,比如定义了getBeanDefinitionNames()
接口方法。对于ApplicationContext接口,它通过继承MessageSource
,ResourceLoader
,ApplicationEventPublisher
接口,在BeanFactory简单loC容器的基础上添加了许多对高级容器的特性的支持。
如下是BeanFactory接口的抽象:
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
//判断容器是否含有指定名字的bean
boolean containsBean(String name);
//判断指定名字的bean是否是Singleton类型,定义的时候可以指定
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
//判断指定名字的bean是否是Prototype类型,定义的时候可以指定
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
//判断指定名字的bean的Class类型,是否是指定的类型
boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;
//得到指定名字的bean的Class类型
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
//获取指定名字的bean的所有别名,定义的时候可以指定
String[] getAliases(String name);
}
在Spring的代码实现中BeanFactory
只是一个接口类,并没有给出容器的具体实现,各种具体实现,比如DefauItListableBeanFactory
,XmlBeanFactory
, ApplicationContext
等都可以看成是容器附加了某种功能的具体实现,也就是容器体系中的具体容器产品。
BeanFactory分析
以 XmlBeanFactory 为例,看看BeanFactory
容器的设计原理:
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
从源码可以看出,XmlBeanFactory
只实现了xml读取的功能,并且还不是自己写的,是通过引用XmlBeanDefinitionReader
来实现的,而IoC容器功能是通过继承DefaultListableBeanFactory
实现的。 在Spring中,实际上是把DefaultListable BeanFactory作为一个默认的功能完整的loC容器来使用的。
XmlBeanFactory
设计的类继承关系如下图:
ApplicationContex分析
以FileSystemXmlApplicationContex
来说明ApplicationContex
容器的设计原理。
public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {
public FileSystemXmlApplicationContext() {
}
public FileSystemXmlApplicationContext(ApplicationContext parent) {
super(parent);
}
public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
this(configLocations, true, null);
}
public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
this(configLocations, true, parent);
}
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
this(configLocations, refresh, null);
}
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
@Override
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResource(path);
}
}
这里有两个可看的地方,第一个是FileSystemXmlApplicationContext
中refresh()
过程会牵涉loC容器启动的一系列复杂操作,同时,对于不同的容器实现,这些操作都是类似的,因此在基类中将它们封装好。
第二个是getResourceByPath
功能是与FileSystemXmlApplicationContext
设计具体相关的功能,这部分与怎样从文件系统中加载XML的Bean定义资源有关。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/16070.html