在Spring中IOC容器的重要地位我们就不多说了对于Spring的使用者而言IOC容器实际上是什么呢?我们可以说BeanFactory就是我们看到的IoC容器当然了Spring为我们准备了许多种IoC容器来使用这样可以方便我们从不同的层面不同的资源位置不同的形式的定义信息来建立我们需要的IoC容器
在Spring中最基本的IOC容器接口是BeanFactory 这个接口为具体的IOC容器的实现作了最基本的功能规定 不管怎么着作为IOC容器这些接口你必须要满足应用程序的最基本要求
public interface BeanFactory {
//这里是对FactoryBean的转义定义因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象
//如果需要得到工厂本身需要转义
String FACTORY_BEAN_PREFIX = &;
//这里根据bean的名字在IOC容器中得到bean实例这个IOC容器就是一个大的抽象工厂
Object getBean(String name) throws BeansException;
//这里根据bean的名字和Class类型来得到bean实例和上面的方法不同在于它会抛出异常如果根据名字取得的bean实例的Class类型和需要的不同的话
Object getBean(String name Class requiredType) throws BeansException;
//这里提供对bean的检索看看是否在IOC容器有这个名字的bean
boolean containsBean(String name);
//这里根据bean名字得到bean实例并同时判断这个bean是不是单件
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
//这里对得到bean实例的Class类型
Class getType(String name) throws NoSuchBeanDefinitionException;
//这里得到bean的别名如果根据别名检索那么其原名也会被检索出来
String[] getAliases(String name);
}
在BeanFactory里只对IOC容器的基本行为作了定义根本不关心你的bean是怎样定义怎样加载的 就像我们只关心从这个工厂里我们得到到什么产品对象至于工厂是怎么生产这些对象的这个基本的接口不关心这些如果要关心工厂是怎样产生对象的应用程序需要使用具体的IOC容器实现 当然你可以自己根据这个BeanFactory来实现自己的IOC容器但这个没有必要因为Spring已经为我们准备好了一系列工厂来让我们使用比如XmlBeanFactory就是针对最基础的BeanFactory的IOC容器的实现 这个实现使用xml来定义IOC容器中的bean
文以spring框架的XmlBeanFactory为入手点进行分析希望能够以尽量简洁明了的方式给予有需要的朋友一定的帮助
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);
thisreaderloadBeanDefinitions(resource);
}
}
这个类的代码很简单一个成员对象加两个构造函数从这里我们可以看出最重要的地方在于最后一个构造函数
第一句就是将父亲工厂交给父类的构造函数实际上最后也就是把父工厂保存到类的parentBeanFactory成员对象中这个对象是在AbstractBeanFactory抽象类中定义的而这个父工厂也会一直传递到该抽象类进行保存第二句就是整个类中最重要的地方了顾名思义它的目的是通过XmlBeanDefinitionReader这个XML的Reader从资源resource中(也就是你的配置文件)读取bean的定义接下来我们打开XmlBeanDefinitionReader的loadBeanDefinitions方法我们可看到在这个方法里代码就一行调用了一个同名不同参的方法而参数是EncodedResource的一个实例这个类实际上是Resource的一个包装类用来保存资源的Encode的那接下来我们再看被调用的loadBeanDefinitions方法这个方法里最主要的部分就是
InputSource inputSource = new InputSource(inputStream);
if (encodedResourcegetEncoding() != null) {
inputSourcesetEncoding(encodedResourcegetEncoding());
}
return doLoadBeanDefinitions(inputSource encodedResourcegetResource());
这里的目的是将资源包装成一个InputSource连同Resource作为参数传递到doLoadBeanDefinitions方法
DocumentBuilderFactory factory = createDocumentBuilderFactory();
if (loggerisDebugEnabled()) {
loggerdebug(Using JAXP implementation [ + factory + ]);
}
DocumentBuilder builder = createDocumentBuilder(factory);
Document doc = builderparse(inputSource);
return registerBeanDefinitions(doc resource);
这个方法的目的一目了然就是为了将资源解释成为Document对象然后调用registerBeanDefinitions方法这里不做详细解释不了解的话请去看看关于JAXP的介绍接下来我们打开registerBeanDefinitions方法
public int registerBeanDefinitions(Document doc Resource resource) throws BeansException {
XmlBeanDefinitionParser parser =
(XmlBeanDefinitionParser) BeanUtilsinstantiateClass(thisparserClass);
return parserregisterBeanDefinitions(this doc resource);
}
这里创建了一个XmlBeanDefinitionParser接口的实现这个接口的具体类是DefaultXmlBeanDefinitionParser这个接口很简单只有registerBeanDefinitions一个方法这个方法的作用也很明了就是用来注册Bean的定义的所以说类和方法的名字一定要起得有意义这样可以让人一看就大概了解其作用减少了很多阅读代码的痛苦废话不多说我们打开DefaultXmlBeanDefinitionParser的registerBeanDefinitions方法这个类就是解释XML配置文件的核心类了打开registerBeanDefinitions方法后我们看到如下代码
public int registerBeanDefinitions(BeanDefinitionReader reader Document doc Resource resource)
throws BeanDefinitionStoreException {
thisbeanDefinitionReader = reader;
thisresource = resource;
loggerdebug(Loading bean definitions);
Element root = docgetDocumentElement();
//初始化根元素
initDefaults(root);
if (loggerisDebugEnabled()) {
loggerdebug(Default lazy init + getDefaultLazyInit() + );
loggerdebug(Default autowire + getDefaultAutowire() + );
loggerdebug(Default dependency check + getDefaultDependencyCheck() + );
}
preProcessXml(root);//一个空方法用于扩展
int beanDefinitionCount = parseBeanDefinitions(root);//解释配置的主要方法
if (loggerisDebugEnabled()) {
loggerdebug(Found + beanDefinitionCount + <bean> elements in + resource);
}
postProcessXml(root); //一个空方法用于扩展
return beanDefinitionCount;
}
在这个方法当中主要用于解释定义的有两个方法一个是initDefaults一个是parseBeanDefinitions第一个方法是用来解释根元素的属性的例如lazyinit autowire等而parseBeanDefinitions就是用来解释具体的bean定义了方法代码如下
protected int parseBeanDefinitions(Element root) throws BeanDefinitionStoreException {
NodeList nl = rootgetChildNodes();
int beanDefinitionCount = ;
for (int i = ; i < nlgetLength(); i++) {
Node node = em(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (IMPORT_ELEMENTequals(nodegetNodeName())) {
importBeanDefinitionResource(ele);
}
else if (ALIAS_ELEMENTequals(nodegetNodeName())) {
String name = elegetAttribute(NAME_ATTRIBUTE);
String alias = elegetAttribute(ALIAS_ATTRIBUTE);
thisbeanDefinitionReadergetBeanFactory()registerAlias(name alias);
}
else if (BEAN_ELEMENTequals(nodegetNodeName())) {
beanDefinitionCount++;
BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele false);
BeanDefinitionReaderUtilsregisterBeanDefinition(bdHolder thisbeanDefinitionReadergetBeanFactory());
}
}
}
return beanDefinitionCount;
}
其他标签具体如何被解释这里就不多说相信大家也能看得懂这里主要讲一下解释bean的的处理我们注意以下代码
else if (BEAN_ELEMENTequals(nodegetNodeName())) {
beanDefinitionCount++;
BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele false);
BeanDefinitionReaderUtilsregisterBeanDefinition(bdHolder thisbeanDefinitionReadergetBeanFactory());
}
这里是当碰到一个bean标签的时候所进行的处理也既是对bean的定义进行解释可以看到parseBeanDefinitionElement方法的第一个参数就是bean则个元素第二个参数表示该bean是否为内置的bean从这里进行解释的bean都不可能是内置的所以这里直接以false为参数打开parseBeanDefinitionElement方法就可以看到这个方法里就是对bean的内部的解释也很简单也不多讲了呵呵(下班时间已经到了所以就写这么多了基本的流程也就这样没什么特别难的地方)对了最后还有一点就是解释完后bean的定义将会被保存到beanFactory中这个beanFactory的实现就是XmlBeanFactory了该beanFactory是在new的时候被传递到reader中的就是该类中以下这行代码
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);