创世纪1
创世纪1.0
知其然,知其所以然。从历史开始解读Spring前世今生。
大致浏览一下以下几个jar包,筛选出几个特别的类作为切入点(建议下载对应版本代码查阅)
- context 上下文环境
- core 核心,提供公共支持
- beans IOC/DI基础
- BeanWrapper/BeanWrapperImpl
- BeanFactory/AbstractBeanFactory/DefaultListableBeanFactory
- FactoryBean/PropertiesFactoryBean
- package:
- beans
- core
- util
- aop 切面支持
- AopProxy/Cglib2AopProxy
- AopProxyFactory/DefaultAopProxyFactory
- AopContext
- AdvisorAdapter/BeforeAdviceAdapter
- MethodMatcher
- Advisor
- package:
- aop
- metadata
- web spring框架对接web容器支持
- webapplicationContext/XmlWebApplicationContext
- contextloaderlistener/ContextLoaderServlet
- package:
- bind
- context
- filter
- multipart
- util
- dao
- orm
从选取出来的一些接口、类可以得知以下几点
上述设计模式可以移步spring中的设计模式阅读
以上几个包的关系可以理解为,context基于beans构建了spring的框架环境,core提供了公共支持,aop提供了切面编程的基础。dao、orm在后面的版本移除,不累述。
IOC/DI
通过xml配置bean,对象托管到spring,生命周期由spring控制。默认使用单例生成bean对象。初始化步骤如下
- spring初始化载入bean配置文件(需要指定),并解析为元数据注册到beanDefinitionMap(String:RootBeanDefinition),beanDefinitionNames(String)
- 在beanFactory中会先初始化单例且非懒加载的bean到缓存singlecache中,需要注意的是初始化时也是调用getBean方法,首先从缓存取,取不到时再以单例的方式获取
- 在注入bean对象时调用beanFactory中的getBean方法获取
- 先从缓存单例中取,有即返回
- 取不到则获取元定义信息调用createBean方法创建,最终调用xxx.class.newinstance方法生成实例并调用populateBean方法注入其中引用的对象
核心代码围绕着BeanFactory开始,核心类如下:
- AbstractBeanFactory,AbstractAutowireCapableBeanFactory,DefaultListableBeanFactory
- RootBeanDefinition
- BeanWrapperImpl
BeanFactory与FactoryBean
前面一直在说BeanFactory,那么FactoryBean又是什么又有什么作用了?
从上面BeanFactory的描述我们可以知道,我们Bean实例的获取均通过BeanFacotry,他统一管理了bean的实例化,实际上就是一个工厂
我们从FactoryBean接口定义来看,总共三个方法
- getObject
- getObjectType
- isSingleton
在看AbstractBeanFactory类中的getBean方法过程过程中我们发现在调用的getObjectForSharedInstance方法中有这么一段
// 简写后的逻辑,是工厂bean且不是工厂的引用
if (beanInstance instanceof FactoryBean) {
if (!this.isFactoryDereference(name)) {
FactoryBean factory = (FactoryBean)beanInstance;
beanInstance = factory.getObject();
}
}
<bean id="demo" class="com.jsmzr.demo.DemoFactory"></bean>
按照名字来获取bean实例时如果需要获取的是DemoFactory实例那么应该在名字前加"&"符号,即"&demo"
所以我们可以将FactoryBean与BeanFactory区分开了,BeanFactory是一个生产bean的工厂,而FactoryBean是一个工厂类型的bean,当从工厂中获取的bean是一个工厂bean且需要的不是工厂时会从中国FactoryBean中获取bean(bean的获取方式在FactoryBean中定义)。
如果还是有些混淆那么完全可以把FactoryBean理解为与一般的Bean一样,只是自身还带有工厂的特性。
框架环境
spring提供了一套运行时环境,我们可以将实例托管到spring。
从AbstractApplicationContext类中我们看到sprng初始化的步骤大概是
- 从配置文件获取bean配置
- 按照配置初始化bean
详见代码AbstractApplicationContext类refresh方法
web环境
我们知道spring只是一个框架,那么他是怎么接入web服务的了?用过老版本spring的人大概都记得,我们在spring+tomcat的时候会在tomcat的web.xml配置文件中配置用过监听器。web容器在初始化时会调用这个监听器中的初始化方法,即ContextLoaderListener的contextInitialized方法。
通过调用spring-web中的初始化方法,会在容器中初始化spring的环境,在这里spring提供了XmlWebApplicationContext作为web环境的支持。这里相当于是把spring环境嵌入了web容器,即我们web开发中的对象实例依然由spring来管理,容器依旧只是提供自己的容器功能,当容器关闭时也会销毁其中的spring环境
在这个版本中spring-web只是提供了一些较为基础的功能
- 托管到web容器
- 乱码解决过滤器
- 日志配置及支持
相关阅读
中文和合本: 创 1:20 神说:?水要多多滋生有生命的物,要有雀鸟飞在地面以上,天空之中。? 创 1:21 神就造出大鱼和水中所滋生各样有生命