我们可以通过GitHub或者码云下载spring-framework源码,这边是基于5.X版本进行下载学习的。
地址:https://github.com/spring-projects/spring-framework
分析Spring源码是非常一件的难的事情,只能一步步学习,一步步记录。
前面在第一章Spring整体架构中,bean是Spring中最核心的部分,在没有接触Spring的时候,我们使用bean是通过new 的方式进行创建,spring bean容器就是将这些对象交给spring去创建和管理,我们只需要在配置文件或者注解的方式告诉spring容器需要创建哪些bean对象。所以需要先在配置文件中定义好需要创建的bean对象,这些配置统称为bean定义配置元数据信息,spring容器通过读取这些bean配置元数据信息来构建和组装我们需要的对象,
我们通过一个入门案例来揭开Spring 容器是如何实现的
1. 创建一个简单的bean
public class TestBean {private String msg;public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}
}
2. 定义配置元数据信息,通过XML的方式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="testBean" class="com.spring.demo.beans.TestBean"><property name="msg" value="put test bean msg"/></bean>
</beans>
3. 测试通过Spring获取bean
public class TestBeanMain {@Testpublic void testBeanLoad(){//在3.2版本以后不推荐使用 这里方便了解Spring内部原理// spring主要有2个容器,一个BeanFactory 一个ApplicationContext,后者是前者一个扩展容器BeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("bean-config.xml"));TestBean testBean = (TestBean) xmlBeanFactory.getBean("testBean");System.out.println(testBean.getMsg());}
}
运行结果:
用于实现上面功能的是org.springframework.bean.jar
功能分析
通过上面的一个简单案例,主要完成的功能步骤如下:
- 读取配置文件bean-config.xml
- 根据配置文件中的配置元信息找到对应类的配置,并进行反射实例化
- 调用实例化的实例
源码分析
XmlBeanFactory对DefaultListableBeanFactory进行了扩展,主要用于从XML文档中读取BeanDefinition,注册和获取bean都是从父类通过继承的方式去实的。代码如下:
进入XmlBeanDefinitionReader类的loadBeanDefinitions方法,这是资源加载的真正实现。
@Overridepublic int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {// 对资源文件进行编码处理return loadBeanDefinitions(new EncodedResource(resource));}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {// 资源不可为空验证Assert.notNull(encodedResource, "EncodedResource must not be null");if (logger.isTraceEnabled()) {logger.trace("Loading XML bean definitions from " + encodedResource);}// 通过属性来记录已经加载过的资源Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();// 添加失败抛出异常 当已存在if (!currentResources.add(encodedResource)) {throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");}//从encodedResource中获取已经封装好的resource资源并从中获取inputStreamtry (InputStream inputStream = encodedResource.getResource().getInputStream()) {InputSource inputSource = new InputSource(inputStream);if (encodedResource.getEncoding() != null) {// 设置编码inputSource.setEncoding(encodedResource.getEncoding());}//真正进入加载核心内容return doLoadBeanDefinitions(inputSource, encodedResource.getResource());}catch (IOException ex) {throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), ex);}finally {//加载完记录中移除currentResources.remove(encodedResource);if (currentResources.isEmpty()) {this.resourcesCurrentlyBeingLoaded.remove();}}}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try {// 获取XML文件的验证模式,对XML进行加载并得到对应的DocumentDocument doc = doLoadDocument(inputSource, resource);// 返回根据XML文件中注册bean的个数int count = registerBeanDefinitions(doc, resource);if (logger.isDebugEnabled()) {logger.debug("Loaded " + count + " bean definitions from " + resource);}return count;}//省略其他代码.......}
后续会对上面XML验证、加载以及获取bean信息进行深入。