Spring前置介绍
Core Container
Core和Beans模块是spring的基础部分,提供IOC和依赖注入特性。这里的基础概念是BeanFactory,它提供对Factory模式的经典实现来消除对程序性单例模式的需要,并且真正允许从程序逻辑中分离出依赖关系和配置。
- Core:主要包含Spring框架基本的核心工具类。
- Beans:它包含配置文件、创建和管理bean,以及IOC/DI操作相关的所有类。(BeanFactory的作用)
- Context:构建与Core和Beans模块基础上,提供了一种类似JNDI注册器的框架式对象访问方法。Context模块继承了Beans的特性,为Spring核心提供了大量扩展,添加了对国际化、事件传播、资源加载和对Context的透明创建的支持。
- Expression Language:模块提供了强大的表达式语言,用于在运行时查询和操纵对象。它是 JSP 2.1 规范中定义的unifed expression language 的扩展。 该语言支持设直/获取属 性的值,属性的分配,方法的调用,访问数组上下文(accessiong the context of arrays)、容器和索引器、逻辑和算术运算符、命名变量以及从Spring的IoC容器中根据名称检 索对象。 它也支持list投影、选择和一般的list聚合。
Spring Data Access/Integration
- JDBC:提供了一个JDBC抽象层,它可以消除冗长的JDBC编码和解析数据库厂商特有的代码错误。这个模块包含了Spring对JDBC数据访问进行封装的所有类
- ORM:如JPA、JDO、Hibernate、iBatis等,提供了一个交互层。利用ORM分装包,可以混合使用所有Spring提供的特性进行O/R映射。
- OXM:提供了一个对Object Xml映射实现的抽象层,Object/XML映射实现包括JAXB、Castor、XMLBeans、JiBX和XStrarn
- JMS:模块主要包含了一些制造和消费消息的特性。
- Transaction:支持编程和声明性的事务管理,这些事务类必须实现特定的接口,并对所有的POJO都适用。
Spring Web
web模块,提供了基础的面向Web的集成特性,如,文件上传、使用servlet listeners初始化Ioc容器以及一个面向web的应用上下文。
Spring Aop
- Aspects:模块提供了对AspectJ的集成支持。
- Instrumentation:提供了class instrumentation支持和classloader实现,使得可以在特定的应用服务器上使用。
Spring容器继承图
IOC
IOC是一种设计思想,即常说的控制反转,用来解决层层之间的耦合,Spring的DI(依赖倒置)就是对其的一种具体的实现。IOC的思想最核心的地方在于,资源不由使用资源的双方管理,而由不使用资源的第三方管理(IOC容器),这可以带来很多好处。第一,资源集中管理,实现资源的可配置和易管理。第二,降低了使用资源双方的依赖程度,也就是我们说的耦合度。
如上图所示:A、B、C、D各个对象之间相互依赖,相互耦合,如果对象A,修改了则B、C、D也会跟着变更,所谓牵一发而动全身。
如上图所示:如果借助第三方管理,即IOC容器,A、B、C、D、各个对象之间相互解耦,各自只需关注各自的功能,不会因为某个对象的修改而需要全部的改动。
如何将类注册到Spring的IOC容器中
context上下文
由上面可知,IOC是一个容器,存放着各种的对象,也就是所说的Bean。那么如何将类注册到IOC容器中,使得被IOC容器所管理,成为一个Bean呢?通常有两种入口的方式:
- xml配置方式
- 注解方式
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("xxx.xml");
context作为加载类对象的入口,并不是真正的生产Bean的地方。而是交给BeanFactory去生产Bean。在通过context.getBean()的时候可以看到。它既可以获取Bean也可以生产Bean。
BeanFactory
从上面的类图就可以看出,BeanFactory是Spring顶层核心接口,使用了简单工程模式,负责生产Bean。一个没有感情的生产机器~~
到这里可以知道,要想将类对象注册到IOC容器中成为Bean,首先需要通过context来加载xml配置类或者读取注解,然后再交给BeanFactory去生产Bean。那么,xml配置的方式和注解两种方式是两种不同的实现,要交给BeanFactory去生产Bean,就要用一个统一的内容格式。即BeanDefinition。如图所示例子。
BeanDefinition也是一个接口,封装了生产Bean的一切所需的原材料。
AbstractBeanDefinition继承了BeanDefinition接口。
那么生成图纸(BeanDefinition),是由谁来生成的?由上图例子可以知道,是通过设计师(BeanDefinitionRegistry)来生成,放入到图纸库(BeanDefinitionMap)中,然后工厂(BeanFactory)从中去取到相应的图纸(BeanDefinition)来生产Bean(窗帘、家具)。相应的有对应的销售人员(BeanDefinitionReader)来挖掘客户(读取配置类或xml文件),然后交给接待人员(BeanDefinitionScanner)来发掘真正有需求的客户(扫描带有注解的类)。
问题:ApplicationContext和BeanFactory两者都可以生成Bean,它们有什么区别?
| Feature | BeanFactory | ApplicationContext |
|---|---|---|
| Bean实例化/装配 | ✔ | ✔ |
| 生命周期管理 | ❌ | ✔ |
| 自动注册BeanPostProcessor | ❌ | ✔ |
| 自动注册BeanFactoryPostProcessor | ❌ | ✔ |
| 国际化 | ❌ | ✔ |
| ApplicationEvent发布机制(事件发布) | ❌ | ✔ |
Factory没有扫描@Component等注解的能力;Factory职责单一,只复杂生产Bean和维护Bean的关系。
以上是Bean注册到IOC容器中的一个大致流程,注册到IOC容器后,即开始了Bean的一系列操作,也就是Bean的生命周期就开始了。
Bean生命周期简述
bean的生命周期只有四个主要阶段,其他都是在这四个主要阶段前后的扩展点:
- 实例化(Instantiation):即通过反射或者工厂进行实例化(例如@Component是通过反射,@Bean通过工厂)。(反射是由Spring决定的,而工厂可以由开发者自己决定new的过程更加灵活)
- 填充属性(Populate):即对带有@Autowired、@Value等注解的属性进行赋值。
- 初始化(Initialization):initMethod、destroy等方法。
- 销毁(Destruction):Bean的销毁。
扩展点
- BeanFactoryPostProcessor:Bean工厂后置处理器,主要用于修改Bean定义(BeanDefinition)。
- BeanDefinitionRegistryPostProcessor:主要用于注册Bean定义,是BeanFactoryPostProcessor的子类。
以上两个扩展点,主要是对Bean定义(BeanDefinition)的操作。Bean也有其相应的扩展点,穿插在Bean的生命周期四个阶段中调用,总共会调用9次。
- BeanPostProcessor:Bean后置处理器,在Bean的实例化、填充属性、初始化操作的时候会进行调用。
在Bean的初始化后回去调用一堆的Aware。在BeanFactory中可以看到。
小结
上图并不是一个完整的IOC加载流程,仅仅是本篇涉及到的内容。
最后
通过本篇可以大致的了解以下几个问题:
- 什么是BeanFactory?
- BeanFactory和ApplicationContext有什么区别?
- 简述SpringIOC的加载过程。
- Bean的生命周期。
- Spring中有哪些扩展点和调用时机。