我们可以通过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 {
@Test
public 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方法,这是资源加载的真正实现。
@Override
public 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资源并从中获取inputStream
try (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进行加载并得到对应的Document
Document 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信息进行深入。