文章目录
简介
Spring是Java程序员日常开发中最长应的应用框架之一,它是如此的流行甚至对Java语言本身的发展都起到了推动作用,目前Spring可以说是Java后端开发的事实标准。Spring的优点可以总结如下:
- Spring的两个最核心功能是IoC和Aop,为模块解耦合提供了基础支持;
- 基于Aop实现的声明式缓存和声明式事务大大简化了代码逻辑;
- 基于Spring的SpringMVC为快速接入JavaEE提供支持;
- Spring的test模块解决了应用程序的单元测试问题;
- Spring可以与很多优秀的框架集成,可以说跟谁都行有一腿;
- 基于Spring构建的SpringBoot、SpringCloud使得Spring在微服务领域迎来了第二个春天;
BeanFactory
在刚开始接触Spring的时候,有人说Spring就是一个生产bean对象的工厂,底层实际上就是一个Map,直到现在对此也非常认同,Spring是一个Map,但绝不仅仅是一个Map,下面先看看Spring的BeanFactory结构
从图中的类名称可以看出,Spring从BeanFactory扩展出了具有不同能力的BeanFactory,当然这还不包含ApplicationContext,所以我个人对Spring的理解是它在HashMap的基础上扩展处理成百上千个特性,这些特性让Spring成为了一个优秀的框架产品。
如果把Spring当成是一个生产Bean的工厂,那么这个Bean工厂上产Bean的原材料就是BeanDefinition,从名字上就可以看出来,BeanDefinition是定义Bean的Bean,也就是说BeanDefinition封装了每一个能够被Spring管理的Bean的元数据,例如类型、依赖、属性、初始化方法等
从Spring中获取一个bean对象的主流程包括两步
- 加载配置文件,从中解析出BeanDefinition
- 调用getBean(beanName)触发Bean的初始(从BeanDefinition到Bean)
Spring源码-初始化BeanDefinition
这里主要说说xml的解析,主要原因是相比注解的方式更加简单,以ClasspathXmlApplication为例,下面进入源码部分。
整个Spring初始的入口是ClasspathXmlApplication的构造方法
ClasspathXmlApplication
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
//入口在这里
refresh();
}
}
@Override
protected Resource[] getConfigResources() {
return this.configResources;
}
AbstractApplicationContext.java
@Override
public void refresh() throws BeansException, IllegalStateException {
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
}
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
}
AbstractRefreshableApplicationContext.java
@Override
protected final void refreshBeanFactory() throws BeansException {
/**
这里创建了BeanFactory的实例 - DefaultListableBeanFactory
所以说,我们开发中用到的ApplicationContext是BeanFactory的封装,
在BeanFactory的基础上提供了很多额外的功能,例如
事件发布与监听、组件扫描、国际化等
**/
DefaultListableBeanFactory beanFactory = createBeanFactory();
//从这里开始加载配置文件,注册BeanDefinition到BeanFactory
loadBeanDefinitions(beanFactory);
}
AbstractXmlApplicationContext.java implements ResourceLoader
*/
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//创建一个专门从Xml中读取BeanDefinition的XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setResourceLoader(this);
loadBeanDefinitions(beanDefinitionReader);
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
/**
当前类中的getConfigResources方法被ClasspathXmlApplicationContext重写了,
所以这里调用的是ClasspathXmlApplicationContext中的方法
*/
Resource[] configResources = getConfigResources();
reader.loadBeanDefinitions(configResources);
}
protected Resource[] getConfigResources() {
return null;
}
AbstractBeanDefinitionReader.java
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
loadBeanDefinitions(resource);
}
XmlBeanDefinitionReader.java
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
/**
这里是解析的核心逻辑
*/
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
//将配置文件转换成了InputStream流对象
InputStream inputStream = encodedResource.getResource().getInputStream();
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) }{
//从流对象得到Document对象
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
}
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//创建一个从Document中获取BeanDefinition的Reader
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
}
DefaultBeanDefinitionDocuemntReader.java
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
doRegisterBeanDefinitions(root);
}
protected void doRegisterBeanDefinitions(Element root) {
parseBeanDefinitions(root, this.delegate);
}
这里就开始解析Elemnent对象了
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
//如果是spring默认的标签,就有spring内核自己来解析,例如beans、bean、<property>等等
parseDefaultElement(ele, delegate);
}
else {
//如果是其他模块的标签或自定义的标签,例如 <aop:xxx> <tx:xxx>
//就通过对应的xml名称空间,从spring.handlers中找到对应的NamespaceHandler
//再由NamespaceHandler设置的parser进行解析
//这也是其他框架与spring进行集成的一个方式,例如dubbo的DubboNamespaceHandler就是用来解析<dubbo:xxx>的
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
最后实际上就是将解析出来的BeanDefinition通过BeanDefinitionRegistry提供的接口能力注册到DefaultListableBeanFactory中
实际上DefaultListableBeanFactory实现了BeanDefinitionRegistry接口,而最终BeanDefinition对象就会被添加到DefaultListableBeanFactory的
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
这个Map中。
下面我们看看BeanDefinition
可以说一目了然,我们所有的配置信息最终都会被解析到BeanDefinition中,Spring在创建Bean实例时,就会根据这些信息来执行不同的逻辑。
从这段逻辑中其实还能学点很多关于代码设计的知识点,比如在解析xml的时候通过BeanDefinitionReader/XmlBeanDefinitionDocumentReader等层层委托,遵循了面向对象设计原则的单一职责原则,再比如大量使用模板模式实现子类的灵活扩展。
Spring源码-对象初始化&依赖注入
前面讲了注册BeanDefinition的过程,有了创建Bean的原材料,接下来就是创建Bean对象了。
在Spring中创建Bean对象的入口有两个,一个是调用getBean()方法从容器中获取Bean对象,另外一个就是在Spring容器初始化的时候,会默认对单例对象进行初始化
AbstractApplicationContext.java
@Override
public void refresh() throws BeansException, IllegalStateException {
// 这里会对非懒加载的bean进行实例化,实际上也是调用getBean,所以
// 触发bean实例化的入口就是getBean,
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
}
下面来看一下getBean方法的逻辑
AbstractApplicationContext.java
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
/**
这里调用的是DefaultListableBeanFactory的getBean方法
前面说过,ApplicationContext实际上是对BeanFactory
的再次封装,此处还是基于BeanFactory来实现IoC容器
所以这里也就很容易理解了
*/
return getBeanFactory().getBean(name, requiredType);
}
AbstractBeanFactory中的doGetBean是Bean对象初始化的核心方法,化繁为简,以单例对象的创建过程为例来说明
protected <T> T doGetBean(
final String name, final C