Spring的主要特性:依赖注入(DI)和面向切面编程(AOP)
依赖注入
DamselRescuingKnight只能执行RescueDamselQuest探险任务
public class DamselRescuingKnight implements Knight {
private RescueDamselQuest quest;
public DamselRescuingKnight() {
quest = new RescueDamselQuest(); //DamselRescuingKnight 紧密地与RescueDamselQuest 耦合在一起
}
public void embarkOnQuest() throws QuestException {
quest.embark();
}
}
为DamselRescuingKnight类编写单元测试出奇的难,必须保证embarkOnQuest()被调用的同时embark()也被调用,没有哪种简明的方式能够实现。
耦合具有两面性:
①紧密耦合代码难测试、难复用、难理解,而且会引发连环bug;
②一定程度的耦合又是必须的,完全没有耦合的代码什么也做不了。
BraveKnight足够灵活,可以接受任何赋予他的探险任务
public class BraveKnight implements Knight {
private Quest quest;//探险类型是Quest接口,能够响应多种探险实现类
public BraveKnight(Quest quest) {
this.quest = quest; //依赖注入方式之一:构造器注入
}
public void embarkOnQuest() throws QuestException {
quest.embark();
}
}
依赖注入的最大好处:松耦合。若一个对象只通过接口来标明依赖关系,那么这种依赖就能够在对象本身毫不知情的情况下,用不同的具体实现进行替换。
以下为实例核心代码:
-> knights.xml
<bean id="knight" class="com.springinaction.knights.BraveKnight">
<constructor-arg ref="quest" />
</bean>
<bean id="quest" class="com.springinaction.knights.SlayDragonQuest" />
ApplicationContext context =
new ClassPathXmlApplicationContext("knights.xml");//加载spring上下文
Knight(接口) knight = (Knight) context.getBean("knight");
knight.embarkOnQuest();
应用切面
依赖注入让相互协作的软件组件保持松散耦合,而AOP允许你把遍布应用各处的功能分离出来形成可重用组件。AOP编程是一项分离关注点的技术。诸如日志、事务管理和安全的【系统服务】经常融入到自身的核心业务逻辑组件中,这些系统服务通常被称为横切关注点,因为他们总是跨越系统的多个组件。
示意图如下:
AOP使这些服务模块化,并以声明的方式将它们应用到需要影响的组件中。更高的内聚性,更加关注自身业务。总之AOP确保POJO保持简单。
没有使用AOP之前:
public class Minstrel {//诗人类
public void singBeforeQuest() {//探索前(前置通知)
...
}
public void singAfterQuest() {//探索后(后置通知)
...
}
}
public class BraveKnight implements Knight {
private Quest quest;
private Minstrel minstrel;//诗人
public BraveKnight(Quest quest,Minstrel minstrel) {
this.quest = quest;
this.minstrel = minstrel;
}
public void embarkOnQuest() throws QuestException {
minstrel.singBeforeQuest();
quest.embark();
minstrel.singAfterQuest();
}
}
这样会对BraveKnight类产生侵入。再假如我们有一个不需要吟游诗人的骑士,那还要考虑minstrel为null的情况,为其增加业务逻辑。但使用AOP可以声明吟游诗人必须歌颂骑士的探索事迹,而骑士就不再直接访问吟游诗人的方法。
<bean id="knight" class="com.springinaction.knights.BraveKnight">
<constructor-arg ref="quest" />
</bean>
<bean id="quest"
class="com.springinaction.knights.SlayDragonQuest" />
<bean id="minstrel"
class="com.springinaction.knights.Minstrel" /> <!--声明Minstrel bean-->
<aop:config>
<aop:aspect ref="minstrel">
<aop:pointcut id="embark"
expression="execution(* *.embarkOnQuest(..))" /> <!--声明切面,切入点id为embark。expression属性值采用AspectJ的切点表达式语言-->
<aop:before pointcut-ref="embark"
method="singBeforeQuest"/><!--声明前置通知-->
<aop:after pointcut-ref="embark"
method="singAfterQuest"/><!--声明后置通知-->
</aop:aspect>
</aop:config>
Bean应用上下文
在spring应用中,对象由spring容器创建、装配和管理。
容器是spring框架的核心。spring自带两类不同类型的容器。Bean工厂(BeanFactory,比较低级,较少用)、应用上下文(ApplicationContext,一般项目都是用这个容器)。
BeanFacotry是spring中比较原始的Factory。如XMLBeanFactory就是一种典型的BeanFactory。原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。
ApplicationContext接口,它由BeanFactory接口派生而来,因而提供BeanFactory所有的功能。ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,提供了许多丰富的功能,简化开发,提高开发效率。
三类常见的spring应用上下文:
FileSystemXmlApplicationContext->
从文件系统加载应用上下文
ClassPathXmlApplicationContext->
从类路径加载应用上下文
XmlWebApplicationContext->
读取web应用下的XML并加载上下文
ApplicationContext ctx = new FileSystemXmlApplicationContext("C:/XXX.xml");
ApplicationContext ctx = new ClassPathXmlApplicationContext("XXX.xml");
ApplicationContext ctx = new XmlWebApplicationContext("XXX.xml");
Bean生命周期
①spring对bean进行实例化;
②spring将值和引用注入bean对应的属性中;
③若bean实现了BeanNameAware接口,spring将bean的id传入setBeanName接口方法;④若bean实现了BeanFactoryAware接口,spring将调用setBeanFactory接口方法,将BeanFactory容器(spring容器)的
实例
传入;
⑤若bean实现了ApplicationContextAware接口,spring将调用setApplicationContext接口方法,将应用上下文(spring容器)的引用
传入;
说明
BeanPostProcessor接口包含两个method。
postProcessBeforeInitialization方法:在Spring调用任何bean的初始化钩子(例如InitializingBean.afterPropertiesSet或者init方法)之前被调用;
postProcessAfterInitialization方法:Spring在成功完成嵌入初始化以后调用它。
⑥ 若bean实现了BeanPostProcessor接口,先调用postProcessBeforeInitialization接口方法;
⑦若bean实现了InitializingBean接口,会调用afterPropertiesSet接口方法,若使用了init声明初始化方法也会被调用;
⑧若bean实现了BeanPostProcessor接口,会调用postProcessAfterInitialization接口方法;⑨准备就绪,可被程序使用,一直滞留在上下文中,直到该上下文被销毁。
Spring模块
按六个模块看 Spring的主要模块分别是核心Spring容器,spring的AOP模块,数据访问与集成,web和远程调用,测试。
- 核心spring容器:容器是spring框架最核心的部分,它负责spring应用中Bean的创建、配置和管理。
- Spring的AOP模块:在AOP模块中,spring对面向对象切面编程提供了丰富的支持。这个模块是spring应用系统开发切面的基础。
- 数据访问与集成:使用jdbc编写代码通常会导致大量的样板式代码,例如获得数据库连接、创建语句、处理结果集到最后关闭数据库连接。Spring的jdbc和dao模块封装了这些样板代码,使我们的数据库代码变得简单明了,还可以避免因为释放数据库资源失败而引发的问题。该模块在几种数据库服务的错误信息之上构建了一个语义丰富的异常层,以后我们再也不需要解释那些隐晦专有的sql错误信息了。
- Web和远程调用:mvc模式已经被普遍的接受为一种构建web应用的方法,它有助于将用户界面逻辑与应用逻辑分离。Spring虽然集成了多种主流的mvc框架,但他的web和远程调用模块自带了一个强大的mvc框架,有助于应用提升web层技术的松散耦合。
- 测试:鉴于开发者自测的重要性,spring提供了测试模块来测试spring应用。
按七个模块看 组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
- 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
- Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
- Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
- Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写 的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
- Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
- Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
- Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
总结
Spring致力于简化企业级java开发,促进代码松散耦合。成功关键在于依赖注入和AOP,这两者是Spring框架最核心的部分。
参考:《Spring实战(第3版)》
http://blog.csdn.net/liu904139492/article/details/44226985
http://blog.knowsky.com/200197.htm
作者: @nanphonfy
Email: nanphonfy (Nfzone) gmail.com 请将(Nfzone)换成@