本篇的主要是根据Spring的官方文档加以整理,旨在理解Spring的整体架构与核心技术的基本概念,建立Spring的基本模型.
1. Spring整体架构
Spring框架是一种分层架构,它包含了一系列的功能,大概由20种模块组成。 这些模块分为核心容器(Core Container)
, 数据访问/集成(Data Access/Integration)
, Web
, AOP
, 工具(Instrumentation)
, 消息(Messaging)
, 测试用例(Test)
.
1.1 核心容器(Core Container)
包含模块spring-core
, spring-beans
, spring-context
, spring-context-support
,spring-expression
.
spring-core
主要包含Spring框架基本的核心工具类spring-beans
包含访问配置文件、创建和管理bean以及进行IoC/DI操作的相关类. BeanFactoryspring-context
构建与Core
和Beans
之上,继承了Beans的特性,扩展添加了国际化、时间传播、资源加载和对Context的创建和支持。ApplicationContextspring-expression
提供 一个强大的表达式语言用于在运行时查询和操作对象,该语言支持设置/获取属性值,属性的分配,方法的调用,访问数组上下文、容器和索引器、逻辑和算是运算符、命名变量以及从Spring的容器中根据名称检索对象
1.2 AOP和Instrumentation
包含模块spring-aop
, spring-aspects
, spring-instrument
, spring-instrument-tomcat
spring-aop
提供了一个AOP联盟标准的面向方面编程的实现,它允许你定义方法拦截器与切入点,从而将逻辑代码与实现函数进行分离。spring-aspects
提供了与AspectJ
的集成spring-instrument
提供了类工具的支持与classloader
的实现,以便在特定的应用服务上使用。spring-instrument-tomcat
包含了spring对于Tomcat的代理
1.3 消息(Messaging)
spring framework 4 包含了spring-messaging
模块,其中使用了来自于spring integration
项目的关键抽象,如Message
, MessageChannel
, MessageHandler
等,他们可以作为基于消息的应用服务的基础。该模块还包含了一组可将消息映射到方法的注解,类似于spring-mvc的编程模型.
1.4 数据访问/集成(Data Access/ Integration)
包含spring-jdbc
, spring-tx
, spring-orm
, spring-oxm
, spring-jms
.
spring-jdbc
提供了JDBC抽象层,消除了冗长的JDBC编码和解析数据库厂商特有的错误代码.spring-tx
为实现了特定接口的类提供了可编程的声明式事务管理支持,对所有的POJOs都适用spring-orm
提供了对象相关映射(ORM)集成,包含JPA
,JDO
,Hibernate
,使用spring-orm
模块可以将这些框架与spring提供的特性结合在一起使用,比如事务管理.spring-oxm
提供了对Object/Xml Mapping实现的抽象,包括JAXB
,Castor
,XMLBeans
,JiBX
以及XStream
.spring-jms
包含了一些生产和消费消息的特性,从spring Framework 4.1
开始,提供了与spring-messaging
集成.
1.5 Web
包含spring-web
, spring-webmvc
, spring-websocket
, spring-webmvc-portlet
spring-web
提供了基于面向web集成的特性,如多文件上传功能、通过servlet listener初始化IoC容器与面向web的ApplicationContext
,它还包含了HTTP客户端与Spring远程支持的web相关的部分.spring-webmvc
(又名web-servlet
)包含了Spring对于Web应用的MVC与REST实现,Spring MVC框架提供了领域模型代码和Web表单之间的分离,并集成了Spring框架的所有其他特性.spring-webmvc-portlet
(又名web-portlet
)提供了基于Portlet环境使用MVC的实现.
1.6 Test
spring-test
模块通过Junit或TestNG对spring的组件提供了单元测试和集成测试
2. 核心技术
2.1 IoC容器
2.1.1 IoC介绍
IoC也成为DI(dependency injection), 它是对象定义其依赖关系的过程. 一般对象通过构造器参数、工厂方法参数或者构造(工厂方法返回实例)之后set相应的属性完成依赖配置.
容器在创建Bean的时候注入这些依赖,这个过程从根本上来说是反转,因此叫做IoC, 它通过直接构建类来控制其初始化或依赖类的位置。这种机制类似服务定位器
设计模式。
Spring Framework的IoC容器的基础包是org.springframework.beans
与org.springframe.context
. 其中接口BeanFactory
提供框架配置和基本功能,
其子接口ApplicationContext
增加了更多的企业级功能,如国际化资源处理、事件发布以及应用层特定的上下文(如用于web应用的WebApplicationContext
).ApplicationContext
是BeanFactory
完整的超集.
2.1.2 容器概述
ApplicationContext
接口相当于负责bean的初始化、配置和组装的IoC容器.
Spring为ApplicationContext
提供了一些开箱即用的实现, 独立的应用可以使用ClassPathXmlApplicationContext
或者FileSystemXmlApplicationContext
,web应用在web.xml
配置监听,提供xml位置和org.springframework.web.context.ContextLoaderListener
即可初始化WebApplicationContext
IoC容器.
2.1.2.1 配置元数据
配置元数据配置了应用中实例的实例化、配置以及组装的规则,SpringIoC容器通过此配置进行管理Bean. 配置元数据有以下几种方式:
- 基于XML配置: 清晰明了,简单易用
- 基于Java代码配置:无xml,通过
@Configuration
来声明配置、对象实例化与依赖关系 - 基于Java注解配置:少量的XML(
<context:annotation-config/>
),通过注解声明实例化类与依赖关系
后续的分析基于XML配置, 与Java代码和注解大体上的机制是一样
2.1.2.2 实例化容器
实例化容器非常简单,只需要提供本地配置路径或者根据ApplicationContext
的构造器提供相应的资源(Spring的另一个重要抽象)即可.
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
此处先给出类图, 稍后再做具体分析.
2.1.3 Bean概述
spring IoC容器管理了多个根据配置元数据创建的bean. 在容器内部,这些Bean可以描述为BeanDefinition
对象,它主要包含这些元数据:
- 全类名:通常为Bean的实际实现类
- Bean的行为配置元素,这种状态描述了bean在容器中的行为,如作用域、生命周期回调等等.
- 当前bean依赖bean的引用: 依赖项
- 新创建对象中的其他配置设置,如池对象bean的池大小限制等.
容器除了通过配置元数据管理bean之外, 还可以通过ApplicationContext
的方法getBeanFactory()
获取BeanFactory
的实现DefaultListableBeanFactory
来注册自己的bean, 但通过不建议.
Bean的实例化
可以将bean的定义想象为创建对象的菜谱,容器在请求时查看对应bean的配方(配置元数据),并使用该配方创建实际对象.
使用XML配置元数据的时候需要指定bean的class
属性,class属性强制作为BeanDefinition
的getBeanClassName()
值,但这个属性不一定是运行时的最终类名(静态工厂方法或者类继承).
使用Class属性有种方式:
- 通常,当容器本身通过反射调用其构造函数直接创建bean的时候需要制定Class,这与
new ...()
操作类似 - 指定包含静态工厂方法的实际类,该方法用于创建对象.
<bean id="clientService" class="examples.ClientService" factory-method="createInstance"/>
<bean id="clientService" factory-bean="serviceLocator" factory-method="createClientServiceInstance"/>
2.1.4 依赖
2.1.4.1 Dependency Injection
使用DI使得代码更加简洁,依赖解耦. 实际对象不需要知道依赖的类的具体实现或依赖项的位置。这更易于测试,尤其是基于接口进行依赖时.
依赖注入方式如下:
基于构造器的依赖注入
<beans> <bean id="foo" class="x.y.Foo"> <constructor-arg ref="bar"/> <constructor-arg ref="baz"/> </bean> <bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg type="int" value="7500000"/> <constructor-arg type="java.lang.String" value="42"/>