一、背景
springframework 从最初的2.5版本发展至今,期间已经发生了非常多的修正及优化。许多新特性及模块的出现,使得整个框架体系显得越趋庞大,同时也带来了学习及理解上的困难。
本文阐述了一些要点,并配合一些代码样例,这有助于快速理解 spring 框架。
二、spring架构
核心容器层
Core 模块
提供了框架的基本组成部分,包括 IoC 及依赖注入功能。
Bean 模块
实现 Bean 管理,包括自动装配机制等功能; 其中BeanFactory是一个工厂模式的实现。
Context 模块
建立在 Core 和 Bean 模块基础上,通常用于访问配置及定义的任何对象。ApplicationContext 是上下文模块的重要接口。
SpEL 模块
表达式语言模块提供了运行时进行查询及操作一个对象的表达式机制。
数据访问/集成
JDBC 模块
用于替代繁琐的 JDBC API 的抽象层。
ORM 模块
对象关系数据库映射抽象层,可集成JPA,JDO,Hibernate,iBatis。
OXM 模块
XML消息绑定抽象层,支持JAXB,Castor,XMLBeans,JiBX,XStream。
JMS 模块
Java消息服务模块,实现消息生产-消费之类的功能。
Transaction 模块
事务模块为各种 POJO 支持编程式和声明式事务管理。
Web应用
Web 模块
Web MVC 提供了基于 模型-视图-控制器 的基础web应用框架。
servlet 模块
实现了统一的监听器以及和面向web应用的上下文,用以初始化 IoC 容器。
Web-Portlet
实现在 portlet 环境中实现 MVC。
Web-Socket 模块
为 WebSocket连接 提供支持。
其他模块
AOP 模块
提供了面向切面的编程实现,允许开发者通过定义方法拦截器及切入点对代码进行无耦合集成,它实现了关注点分离。
Aspects 模块
提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。
Instrumentation 模块
实现instrumentation支持,一般用以应用服务器的监测。
Messaging 模块
为STOMP 提供了支持,STOMP协议是一种简单的文本定向消息协议,是 WebSocket 的子协议。
测试
支持 JUnit 、TestNG 框架的集成
三、基础工程
后续的工作将基于样例工程展开,首先需要准备JDK、Java IDE如Eclipse、Maven环境,此类工作较为简单,在此不作赘述。
- 创建Maven项目;
- 配置Spring依赖;
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.2.RELEASE</version> </dependency>
3. 编写配置文件及测试代码;
core-beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="randomID" class="org.springfoo.core.bean.RandomID" scope="prototype" init-method="init" destroy-method="destroy"> </bean> <bean id="message" class="org.springfoo.core.bean.Message" scope="prototype"> <property name="content" value="Hello sam" /> <property name="sender" value="bob" /> <property name="reciever" value="sam" /> </bean> </beans>
POJO定义
public class Message { private String content; private String sender; private String reciever; public String getContent() { return content; } public void setContent(String content) { this.content = content; } ...
测试代码
private static void tryAppContext() { ApplicationContext context = new ClassPathXmlApplicationContext("core-beans.xml"); Message message = context.getBean(Message.class); System.out.println(message); }
四、IOC 容器
IOC 即控制反转,将对象的生命周期管理、关系依赖通过容器实现,实现解耦。
ApplicationContext是最关键的入口,其包括几种实现:
- FileSystemXmlApplicationContext,从 XML 文件中加载被定义的 bean对象,基于文件系统路径加载配置;
- ClassPathXmlApplicationContext,从 XML 文件中加载被定义的 bean对象,基于类路径加载配置;
- WebXmlApplicationContext,从 XML 文件中加载被定义的 bean对象,基于 web 应用程序范围加载配置;
五、Bean 管理
5.1 作用域
singleton
每一个 Spring IoC 容器中保持一个单一实例(默认)。
prototype
bean 的实例可为任意数量。
request
该作用域将 bean 的定义限制为 HTTP 请求。只在 web-aware Spring ApplicationContext 的上下文中有效。
session
该作用域将 bean 的定义限制为 HTTP 会话。 只在web-aware Spring ApplicationContext的上下文中有效。
global-session
该作用域将 bean 的定义限制为全局 HTTP 会话。只在 web-aware Spring ApplicationContext 的上下文中有效。
5.2 生命周期
Bean 的初始化及销毁对应 init 及 destroy 两个行为,可通过实现 InitializingBean/DisposableBean 接口观察对象的初始化及销毁时机。
代码片段:
public void afterPropertiesSet() throws Exception { System.out.println(this + "-- properties set"); } public void init() { System.out.println(this + "-- init"); } public void destroy() { System.out.println(this + "-- destroy"); }
为了使spring获得 destroy 行为的监视机会,需要注册JVM关闭回调:
context.registerShutdownHook();
init/destroy拦截
实现 BeanPostProcessor 接口,并注册到配置文件
<bean class="xxx.MyBeanPostProcessor" />
5.3 bean模板
通常可将一组属性归集为bean模板以实现复用
<!-- template --> <bean id="template" abstract="true"> <property name="support" value="true" /> <property name="count" value="10" /> </bean> <bean id="tplbean" class="org.springfoo.core.bean.TplBean" parent="template"> <property name="message" value="I‘m inheritted from template" /> </bean>
POJO 定义
public class TplBean { private String message; private boolean support; private Integer count; ...
六、依赖注入
6.1 简单例子
- People 包含 Hand/Foot/Body;
- Hand/Foot 通过构造参数注入;
- Body通过属性参数注入;
beans.xml
<bean id="people" class="org.springfoo.di.bean.People" scope="prototype"> <constructor-arg ref="foot"/> <constructor-arg ref="hand"/> <property name="body" ref="body"/> </bean> <bean id="foot" class="org.springfoo.di.bean.Foot" scope="prototype"> <property name="label" value="FOOT" /> </bean> <bean id="hand" class="org.springfoo.di.bean.Hand" scope="prototype"> <property name="label" value="HAND" /> </bean> <bean id="body" class="org.springfoo.di.bean.Body" scope="prototype"> <property name="label" value="BODY---BB" /> </bean>
People.java
public class People { private Foot foot; private Hand hand; private Body body; public People(){ } public People(Foot foot, Hand hand) { super(); this.foot = foot; this.hand = hand; } public Foot getFoot() { return foot; } public void setFoot(Foot foot) { this.foot = foot; } public Hand getHand() { return hand; } ...
其余略
6.2 注入集合
可通过配置一组值的方式实现集合注入
集合POJO
@SuppressWarnings("rawtypes") public class CollectionBean { private List list; private Set set; private Map map; private Properties prop; public List getList() { return list; } public void setList(List list) { this.list = list; } public Set getSet() { return set; } public void setSet(Set set) { this.set = set; } public Map getMap() { return map; } public void setMap(Map map) { this.map = map; } public Properties getProp() { return prop; } public void setProp(Properties prop) { this.prop = prop; } }
beans.xml
<bean id="collection" class="org.springfoo.di.bean.CollectionBean"> <property name="list"> <list> <value>APPLE</value> <value>ORANGE</value> <value>PINAPPLE</value> </list> </property> <property name="set"> <set> <value>TABLE</value> <value>CHAIR</value> </set> </property> <property name="map"> <map> <entry key="b" value="BEER" /> <entry key="j" value="JUICE" /> </map> </property> <property name="prop"> <props> <prop key="sp">Single Player</prop> <prop key="tp">Two Player</prop> </props> </property> </bean>
6.3 自动装配
POJO定义
public class AutoWireBean { private String message; private Body body; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public Body getBody() { return body; } public void setBody(Body body) { this.body = body; } }
beans.xml
<bean id="autowire" class="org.springfoo.di.bean.AutoWireBean" autowire="byName" scope="prototype"> <property name="message" value="okok autowire going..."/> </bean>
autowire类型
- byName, 通过属性名称与配置中bean名称配对
- byType, 通过属性类型与配置中bean类型配对
- constructor, 通过构造函数中bean类型配对
七、总结
至此,关于 spring 的核心概念已经介绍完毕,接下来就是如何在实践中深化了。
相信只要理解了基础理念,在后续的项目中自然会得心应手,毕竟万变不离其宗。