为什么开始看spring的源码
- 半路转行写代码快一年半了,从开始工作就在使用
spring
框架,虽然会用,会搭框架,但是很多时候不懂背后的原理,比如:spring是怎样控制事务的,springmvc是怎样处理请求的,aop是如何实现的...这让人感觉非常不踏实,那就开始慢慢边看书边研究spring的源码吧!!!
怎样高效的看源码
- 我的答案是带着具体的问题去看源码,不然非常容易陷入源码细节中不能自拔,然后就晕了,最后你发现这看了半天看的是啥玩意啊.
spring容器核心类结构图,方便我们理清思路,主要参考自书籍<<spring源码深度解析 >>
spring容器核心类结构图下面正式开始源码bug
- 创建一个简单的javaBean. 下面debug过程尽量只针对该bean的初始化过程进行跟踪,以免陷入源码细节出不来...
public class TestBean {
private String name;
public TestBean() {
}
public TestBean(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- 在
spring.xml
定义
<bean id="testBean" class="com.hunt.debug.TestBean">
<property name="name" value="spring"/>
</bean>
- 利用
spring
集成单元测试
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration(value = "classpath:src/main/webapp")
@ContextConfiguration({"classpath:spring.xml", "classpath:spring/spring-mvc.xml"})
@Transactional
public class DebugSpring {
private static final Logger log = LoggerFactory.getLogger(DebugSpring.class);
@Test
public void testLoad() throws IOException {
Resource resource = new ClassPathResource("spring.xml");
BeanFactory xmlBeanFactory = new XmlBeanFactory(resource);
TestBean testBean = xmlBeanFactory.getBean("testBean", TestBean.class);
log.debug("test bean name is :{}", testBean.getName());
}
}
-
开始debug
-
这里内部真正调用的是第二个构造器
XmlBeanFactory类结构图 -
初始化入口:
this.reader.loadBeanDefinitions(resource);
-
实际上是
XmlBeanDefinitionReader类结构图private final XmlBeanDefinitionReader reader
这个对象负责spring容器的初始化,包括:xml配置文件载入,验证,解析,bean的注册
-
继续进入
loadBeanDefinitions(Resource resource)
-
进入到的是
Paste_Image.pngXmlBeanDefinitionReader
中的loadBeanDefinitions(EncodedResource encodedResource)
:
-
继续进入
Paste_Image.pngXmlBeanDefinitionReader
中的doLoadBeanDefinitions(InputSource inputSource, Resource resource)`:
-
继续进入
Paste_Image.pngXmlBeanDefinitionReader
中的registerBeanDefinitions(Document doc, Resource resource)
:
-
准备数据,进入
Paste_Image.pngregisterBeanDefinitions(Document doc, XmlReaderContext readerContext)
:
-
开始进入解析流程
Paste_Image.pngdoRegisterBeanDefinitions(Element root)
:
-
终于做好了所有的准备,按照命名空间类别进行解析,解析规则是如果是<beans></beans>则按照默认方式否则按照自定义解析方式...跟进
Paste_Image.pngparseBeanDefinitions(root, this.delegate);
:
Paste_Image.png -
按照标签规则进行解析
Paste_Image.png -
组装
Paste_Image.pngBeanDefinitionHolder
并在容器中进行注册 ,为什么需要对容器对象进行包装呢,因为容器对容器和别名是分两个属性进行维护的.
-
组装
BeanDefinitionHolder
过程
-
创建容器数据对象过程,设置数据对象的属性
Paste_Image.png -
来看下容器对象中的数据对象到底是什么样子的:
-
回到
Paste_Image.pngprocessBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
,继续最后一步: 向容器中进行注册!!!
-
最后一步,向容器注册是在
DefaultListableBeanFactory
中的registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
进行实现的
-
到这里完成了bean向容器的注册,我们可以看下
Paste_Image.pngbeanDefinitionMap
容器已经有了testBean
,到这里我们定义的testBean
整个初始化过程就结束了
网友评论