xml文件里包含Bean的信息,为了避免多次IO,需要一次性读取xml文件中所有bean信息,加入到Spring工厂。
new ClassPathResource("applicationContext.xml")
ClassPathResource是Spring封装的一个类型;
Resource接口 :可以读取相关资源文件的内容 获得输入流;可读取的类型,不仅包括本地的xml、 properties、txt 等文件,还包括 网络中的资源。它有父接口,InputStreamSource,其中定义了一个getInputStream方法,用来获取输入流。
ClassPathResource类中对getInputStream方法的实现。
Resource将xml配置文件读取到jvm中,那jvm中是如何体现xml中的bean呢?
因为一切皆对象,所以肯定是以对象的方式存在的。
Spring通过SAX的技术手段,对xml解析,封装BeanDefiniton。
下方代码所代表的含义,实际上就是IOC的核心:
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
它包括以下几个问题:
通过Resource接口的实现类,比如ClassPathResource,得到InputStream。
以BeanDefinition的形式存在,用的最多的实现类是GenericBeanDefinition。
使用XmlBeanFactory中的XmlBeanDefinitionReader对象的方法。
Spring标识XmlBeanFactory过期了,可以用以下代码替换:
DefaultListableBeanFactory beanFactory1 = new DefaultListableBeanFactory();
Resource resource = new ClassPathResource("applicationContext.xml");
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory1);
xmlBeanDefinitionReader.loadBeanDefinitions(resource);
Object product1 = beanFactory1.getBean("product");
System.out.println("product1 = " + product1);
但是比较繁琐,我们分析源码还是使用XmlBeanFactory来分析。
Spring允许在一个工程中有多个Spring工厂同时出现 ,但是情况非常少见 。
比如SpringMVC中 父子容器
DispatcherServlet ---- childFactory
ContextLoaderListener ---- rootFactory
InputStream inputStream = encodedResource.getResource().getInputStream();
这行代码是封装成SAX的InputStream类型,对xml进行解析。
最主要的就是return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
来加载BeanDefinition。
Document doc = doLoadDocument(inputSource, resource);
这行代码得到的还是XML解析封装的对象。
int count = registerBeanDefinitions(doc, resource);
这行代码就是注册BeanDefinition的方法,并返回注册的数量。
parseDefaultElement(ele, delegate);用来解析基本标签
比如:
<bean id="" class="" scope="" parent="" init-method=""
<property name value
</bean>
<bean id="" class="" scope="" parent="" init-method=""
<construt-arg>
</bean>
delegate.parseCustomElement(ele);解析自定义标签
比如:
<context:propertyplace-holder
<context:component-scan
..
<tx:annotation-driven
<mvc:annotation-drvent
<aop:config
我们目前看基本标签的解析;
import标签
可以引入其他的配置文件
<import resource="applicationContext1.xml"/>
<import resource="applicationContext2.xml"/>
<import resource="applicationContext3.xml"/>
alias标签
别名
<bean id="product" name= "p" class="xxxx.xxx.Product"/>
name代表别名
也可以这样写
<bean id="user" class="xxxx.xxx.User"/>
<alias name="user" alias="u"/>
alias标签也可以写别名
beans标签上文已经讲过
bean标签——用的最多,着重分析
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
解析标签里的元素,封装成BeanDefinitionHolder
(对BeanDefinition做了一层包装)
其中有三个属性
private final BeanDefinition beanDefinition;
存储BeanDefinition
private final String beanName;
存储id值,如果没有id,就是name值
如果也没有name,会自动生成一个
private final String[] aliases;
存储别名
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
如果有自定义标签,再解析自定义标签
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
将BeanDefinition,以id为key存储到map中
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
发送注册完成的事件;此方法是空实现,可以自己实现
此方法用来解析id、别名,判断id是否唯一、调用parseBeanDefinitionElement重载2;若id,name都没有,生成id等操作。
此方法用来解析class标签,创建BeanDefinition、解析scope、abstract标签等。