spring源码分析01-持续更新

192 阅读3分钟

spring源码分析01

父子容器

mvc开发中,父子容器:

web.xml文件中,会配置DispatherServlet,这个servlet中封装了spring工厂,这个是child工厂;
另一个是 ContextLoaderLister 创建的工厂,这个是root工厂

父子容器问题:controller获取service时候,虽然配置了事务,但是事务没有生效。
原因:事务是在父工厂配置的,父工厂创建了service,添加了事务;子工厂创建的service没有事务,controller是dispatherservlet这个子工厂创建的,自然没有事务。
解决方案:子工厂不创建service,去调用父工厂的service。


springboot没有父子容器问题,因为tomcat是它内嵌的,不需要外部激活来创建。==>//todo 后续有专门章节演示
另一个好处,以jar包启动tomcat的进程==>单体应用,微服务拆分的优点

工厂:容器,创建、储存功能
ApplicationContext spring编程门面,集合了其他的工厂能力,功能最多。BeanFactory是spring最核心最底层的工厂。
DefaultListableBeanFactory,偏框架底层的工厂
spring编程中严格遵守了`类型单一原则`,因此工厂继承体系特别复杂

spring工厂分类

工厂的分类:
	BeanFactory:spring的底层工厂,提供了进行访问和操作的最基本功能:存,取
		- HierarchicalBeanFactory 父子容器的能力(分级豆工厂,继承)
			- ConfigurableBeanFactory:配置工厂:单实例,多实例,类型转换器,后置处理器
		- AutowireCapableBeanFactory:自动注入工厂:自动注入,生命周期
		- ListableBeanFactory:实现了beanFactory定义的绝大多数接口,功能强大;获取相关的配置信息,
			- DefaultListableBeanFactory:ListAbleBeanFactory接口的实现类
				- XmlBeanFactory:需要使用到此类解析xml配置文件,创建对应对象
		

1.学习目标

工厂使用方式:
BeanFactory beanFactory = new XmlBeanFactory(Resource-->xml);
ioc工厂核心内容:
beanFactory.getBean("")-->target
  
BeanFactory怎么创建工厂,获取对象?
  - 定义applicationContext.xml的配置文件
    - 工厂如何解析xml
      - 解析默认标签
      - 解析自定义标签
        - 封装为 beanDefinition
  - 存储为 BeanDefinition
  - 对象的创建(BeanFactory)
  - 完整对象

引申学习目标:

1.怎么读取配置文件,获得IO资源:通过resource接口
2.读取配置文件后,如何在spring中以对象的形式进行封装
3.根据配置信息生成对象:循环依赖
4.所创建对象的生命周期:注入

1.1Resource接口读取配置文件

Resource(资源)
  - ClassPathResource
  - ServletContextResource
实现类不重要,目的是通过该接口的某个实现类获得 InputStream ,从而进行解析(类似mybatis,第一步读取配置文件),最终在JVM中以对象的形式进行保存。保存的对象类型为:BeanDefinition(Interface)。
​
xml解析:mybatis使用xpath框架,spring使用sax框架

1.2创建BeanFactory工厂

1.2.1XmlBeanFactory内部实现:

public class XmlBeanFactory extends DefaultListableBeanFactory {
​
  private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
​
  public XmlBeanFactory(Resource resource) throws BeansException {
    this(resource, null);
  }
​
  public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
    super(parentBeanFactory);
    this.reader.loadBeanDefinitions(resource);
  }
}

1.2.2BeanDefiniton实现树:

BeanDefinition(I)
- AbstractBeanDefinition()
  - GenericBeanDefinition(最为广泛,这个可以实例化)
XmlBeanDefinitonReader
XmlBeanDefinitonReader是XmlBeanFactory的成员属性
new XmlBeanDefinitonReader(BeanFactory).loadBeanDefinitions(Resource)
// 使用顶层接口 BeanFactory 以屏蔽实现类差异BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
Product product = (Product) beanFactory.getBean("p");
System.out.println("product = " + product);
​
// XmlBeanFactory 工厂已过期
// DefaultListableBeanFactory + XmlBeanDefinitionReader 替换 XmlBeanFactoryDefaultListableBeanFactory beanFactory1 = new DefaultListableBeanFactory();
Resource resource = new ClassPathResource("applicationContext.xml");
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory1);
xmlBeanDefinitionReader.loadBeanDefinitions(resource);
​
Object product1 = beanFactory1.getBean("p");
System.out.println("product1 = " + product1);
​
正常编程中,我们使用:
ApplicationContect context = new ClassPathXmlApplicationContext("classpath:application.xml")
这个工厂进行开发,这也侧面证明了ApplicationContext工厂和XmlBeanFactory是较为高级的工厂,因为不需要显示调用Resource接口的实现

1.2.3xml文件的解析

xml解析方式
mybatis xml解析 xpath
spring xml解析 sax
​
spring允许同时存在多个工厂
new XmlBeanFactory()// 创建工厂对象
  获取inputStream输入流// 获取输入流
  	doLoadBeanDefinitions// 获取输入流
  		doLoadDocument/registerBeanDefinitions// 封装为Documen对象,再分装为BeanDefinitions
  			parseBeanDefinitions// 解析xml文件
  				parseDefaultElement// 解析默认标签
  					processBeanDefinition// 创建beanDefinitionHolder
  						registerBeanDefinition// 注册beanDefiniton
  							registerBeanDefinition// 获取名称,并进行注册