第一章的主要内容介绍
- Spring的bean容器
- 介绍Spring的核心模块
- 更为强大的Spring生态系统
- Spring的新功能
Tips: POJO的内在含义是指那些没有从任何类继承、也没有实现任何接口,更没有被其它框架侵入的java对象。
当一个Pojo可序列化,有一个无参的构造函数,使用getter和setter方法来访问属性时,他就是一个JavaBean。
简化JAVA开发
Spring 目的是解决了企业级应用开发的复杂性,javabean的实现变得简单,全方面的简化java 开发的复杂性
- 基于POJO的轻量级和最小侵入性编程;
- 通过依赖注入和面向接口实现松耦合;
- 基于切面和惯例进行声明式编程;
- 通过切面和模板减少样板式代码。
激发POJO的潜能
Spring 不会强迫实现 Spring 规范的接口,并且类没有任何痕迹表明使用了Spring
eg:一个类或许有Spring 注解,但是仍然是POJO
如图,这是一个简单的JAVA类,POJO没有任何的地方看出使用了Spring
依赖注入(DI)
传统的做法是,每个对象自己负责管理与自己协作的对象的引用(依赖的对象)。 但是会导致高度耦合和难以测试。
DamselRescuingKnight在它的构造函数中自行创建了Rescue DamselQuest。这使得DamselRescuingKnight紧密地和RescueDamselQuest耦合到了一起,特定的类型。
并且编写测试很困难,必须保证当骑士的embarkOnQuest()方法被调用的时候,探险的embark()方法也要被调用。 (困难在于无法确保实例quest 已经被创建)
耦合具有两面性:一方面使得代码难以测试,复用,难以理解。另一方面,一定程度的耦合是必须的,不然完成不了任何功能(类之间不能交互和调用)。
通过DI 对象的依赖关系由系统中的第三方组件在创建对象的时候设定,对象无需自行的创建和管理依赖关系。依赖关系会自动交给对象,而不是由对象自己获取依赖。
BraveKnight没有自行创建探险任务,而是在构造的时候把探险任务作为构造器参数传入。这是依赖注入的方式之一,即构造器注入(constructor injection)。
并且BraveKnight 可以实现任何类型的Quest 接口,这就是DI最大的收益,松耦合
测试BraveKnight
mock框架Mockito去创建一个Quest接口的mock实现。通过这个mock对象,就可以创建一个新的BraveKnight实例,并通过构造器注入这个mock Quest。
调用embarkOnQuest()方法时,可以要求Mockito框架验证Quest的mock实现的embark()方法仅仅被调用了一次。
将Quest注入到Knight中
SlayDragonQuest实现了Quest接口,这样它就适合注入到BraveKnight中去了。
So,现在有两个问题:
如何将SlayDragonQuest交给BraveKnight呢?
如何将PrintStream交给SlayDragonQuest呢?
采用XML 的方式装配bean
BraveKnight和SlayDragonQuest被声明为Spring中的bean。
BraveKnight bean来讲,它在构造时传入了对SlayDragonQuest bean的引用,将其作为构造器参数
基于Java 的装配
尽管BraveKnight依赖于Quest,但是它并不知道传递给它的是什么类型的Quest,也不知道这个Quest来自哪里。编码阶段并不知道具体的实现。
Spring通过应用上下文(Application Context)XML装载bean的定义并把它们组装起来,Spring自带了很多种上下文实现。区别仅仅是如何装配
注意这个类完全不知道我们的英雄骑士接受哪种探险任务,而且完全没有意识到这是由BraveKnight来执行的。只有knights.xml文件知道哪个骑士执行哪种探险任务。
应用切面AOP
DI可以让相互协作的软件保持松耦合,面向切面编程(aspect-oriented programming,AOP)允许你把遍布应用各处的功能分离出来形成可重用的组件。
日志、事务管理和安全这样的系统服务可以跨越多个系统组件。
如果AOP可以使得这些服务模块化,并且以声明的方法,加入到需要的组件中,使得组件会具有高内聚的特定,更加关注自身业务实现。AOP能够确保POJO的简单性
借助AOP可以使用各种功能层去包裹核心业务层,这些层可以以声明的方式加入到切入点。
AOP应用
在之前的程序中,加入吟游诗人的角色
改变Knight 的代码
这个程序中,骑士对吟游诗人进行了管理,这是不符合逻辑的。骑士需要知道吟游诗人,所以就必须把吟游诗人注入到BarveKnight类中。这不仅使BraveKnight的代码复杂化了。并且吟游诗人不可复用,
利用AOP 可以将吟游诗人声明为一个切面,然后注入骑士的类中。
首先,需要把Minstrel声明为一个bean,然后在<aop:aspect>元素中引用该bean。
两种通知方法:
前置通知(before advice):(使用<aop:before>)在embarkOnQuest()方法执行前调用Minstrel的singBeforeQuest()方法。
后置通知(after advice):同时声明(使用<aop:after>)在embarkOnQuest()方法执行后调用singAfter Quest()方法。
模板消除样版式代码 (感觉不重要)
样板式代码的一个常见范例是使用JDBC访问数据库查询数据。举个例子,如果你曾经用过JDBC,那么你或许会写出类似下面的代码。
使用Spring的JdbcTemplate(利用了 Java 5特性的JdbcTemplate实现)重写的getEmploy
eeById()方法仅仅关注于获取员工数据的核心逻辑,而不需要迎合JDBC API的需求
容纳BEAN
在Spring中,应用对象生存于Spring容器(container)Spring容器负责创建对象,装配它们,配置它们并管理它们的整个生命周期,从生存到死亡。
容器是Spring的核心,容器使用DI构成应用组件。
Spring容器可以归为两种:
bean 工厂(由org.springframework. beans.factory.eanFactory接口定义)是最简单的容器
应用上下文(由org.springframework.context.ApplicationContext接口定义)基于BeanFactory构建,并提供应用框架级别的服务
使用应用上下文
无论是从文件系统还是类路径,bean 加载到bean工程的工程类似
bean的生命周期
Spring模块
Spring 核心容器
核心容器包括了Spring bean 工厂,提供了DI 。该模块也提供了许多企业服务,例如Email
、JNDI访问、EJB集成和调度。
Spring AOP 模块
帮助应用解耦
数据访问集成
Spring的JDBC和DAO 模块抽象了这些板式代码,简化了数据库的代码。并且提供了ORM模块
WEB 与远程调用
MVC 模式是一种普遍被接受的构建Web 应用的方法。Spring能够与多种MVC框架集成。
Spring远程调用功能集成了RMI(Remote MethodInvocation)、Hessian、Burlap、JAX-WS
。Spring还提供了暴露和使用REST API
Instrumentation
提供了为JVM添加代理(agent)的功能
测试
Spring 提供了测试模块,发现Spring为使用JNDI、Servlet和Portlet编写单元测试提供了一系列的mock对象实现。