Fork me on GitHub

第一章 Spring基础知识

第一章 Spring基础知识

Spring 是一个开源框架,是为了解决企业应用程序开发复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许您选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。

Spring 框架

Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式,如图 1 所示。
图 1. Spring 框架的 7 个模块




组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:

  • 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
  • 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 IOC原理

    IOC是什么



    先来看看字面上怎么来解释:当一个对象创建时,它所依赖的对象由外部传递给它,而非自己去创建所依赖的对象(比如通过 new 操作)。因此,也可以说在对象如何获取它的依赖对象这件事情上,控制权反转了。这便不难理解控制反转和依赖注入这两个名字的由来了。

    有个这样的场景

    有个土豪老板,经常要出差,因此经常要订机票。定机票呢,可以通过去哪儿网订票,也可以通过携程订票。

    我们马上可以想到可以通过三个类来表达这个场景,BossQunarBookingServiceCtripBookingService。当然了,我们还应该提供一个BookingService接口,作为QunarBookingServiceCtripBookingService的公共抽象。
    1
    2
    3
    4
    5
    6
    7
    BookingService.java

    package com.dsky.iocdemo;

    public interface BookingService {
    void bookFlight();
    }
1
2
3
4
5
6
7
8
9
QunarBookingService.java

package com.dsky.iocdemo;

public class QunarBookingService implements BookingService {
public void bookFlight() {
System.out.println("book fight by Qunar!");
}
}
1
2
3
4
5
6
7
8
9
CtripBookingService.java

package com.dsky.iocdemo;

public class CtripBookingService implements BookingService {
public void bookFlight() {
System.out.println("book fight by Ctrip!");
}
}

好了,土豪出门谈生意,得订机票了,Boss就琢磨着怎么订票呢,Boss比较了一下价格,这一次决定用去哪儿,对应的Boss的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Boss.java

package com.tianmaying.iocdemo;

public class Boss {

private BookingService bookingService;

public Boss() {
this.bookingService = new QunarBookingService();
}

public BookingService getBookingService() {
return bookingService;
}

public void setBookingService(BookingService bookingService) {
this.bookingService = bookingService;
}

public void goSomewhere() {
bookingService.bookFlight();
}
}

Boss的构造函数中,将其 bookingService 成员变量实例化为 ​QunarBookingServicegoSomewhere() 函数中就可以调用 bookingService bookFlight方法了!

为了把这个场景Run起来,我们还需要一个main函数:

1
2
3
4
5
6
7
8
9
10
11
App.java
public class App {
public static void main(String[] args) {
bossGoSomewhere();
}

static void bossGoSomewhere() {
Boss boss = new Boss();
boss.goSomewhere();
}
}

使用IoC的场景

在这个例子中,我们看到 Boss 需要使用BookingService,于是 Boss 自己实例化了一个 QunarBookingService 对象。同志们想想,身为土豪 Boss,思考的都是公司战略的事儿,定个票还要自己选择通过什么方式来完成,这个 Boss 是不是当得实在太苦逼。

所以土豪赶紧给自己找了个美女秘书(别想歪!),Boss 要出差时,只需要说一声他需要订票服务,至于是哪个服务,让美女秘书选好后告诉他即可(注入啊!注入!)。(别跟我较真说美女秘书直接把票送上就行!)

这样的话,Boss是不是一身轻松了? 而这个美女秘书还是免费包邮的,这正是Spring扮演的角色!来看看使用Spring之后的代码。

我们在pom.xml文件中加入依赖(项目使用Maven作为构建工具):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
``` java
QunarBookingService.java

import org.springframework.stereotype.Component;

@Component
public class QunarBookingService implements BookingService {
public void bookFlight() {
System.out.println("book fight by Qunar!");
}
}

这里我们使用Spring@Component标注将 QunarBookingService 注册进SpringContext,这样它就可以被注入到需要它的地方!相应地,创建 QunarBookingService实例的责任也交给了Spring

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
SmartBoss.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class SmartBoss {
private BookingService bookingService;

@Autowired
public void setBookingService(BookingService bookingService) {
this.bookingService = bookingService;
}

public BookingService getBookingService() {
return bookingService;
}

public void goSomewhere() {
bookingService.bookFlight();
}
}

IoC的好处

回到正题,通过上面的例子,我们来看看IoC到底带来了哪些好处?

Boss 没有和某个具体的 BookingService 类耦合到一起了,这样 Boss 的维护和演化就更加方便。想象一下,如果 Boss需要改用 CtripBookingService,这时也不需要修改 Boss.java的代码,更换接口的实现非常方便,给 Boss 注入新的实现即可,轻松惬意。(当然,要做到热插拔还需要进一步的工作,要么得玩转类加载器这玩意,或者借助 OSGi 这样的神器)。这也是典型的开放-封闭原则的例子,即对现有模块,功能扩展应该是开放的,而对其代码修改应该是封闭的,即能够做到不需要修改已有代码来扩展新的功能。

想象一下,如果Boss自己直接去实例化 QunarBookingService,而 QunarBookingService 在另外一个Package中甚至另外一个Jar包中,你可得import进来才能使用,紧耦合啊!现在好了, Boss只依赖于抽象接口,测试更方便了吧,Mock一下就轻松搞定! BossQunarBookingService 彼此不知道对方,Spring帮两者粘合在一起。

为什么IoC是个大招,因为它会自然而然得促进你应用一些好的设计原则,会帮助你开发出更加“高内聚低耦合”的软件

资料整理来自:http://www.tianmaying.com/tutorial/spring-ioc

Spring AOP

AOP其实就是一种关注点分离的技术,在软件工程领域一度是非常火的研究领域。软件开发时我们往往不能专注于业务逻辑,比如我们写业务逻辑代码的同时,还要写事务管理、缓存、日志等等通用化的功能,而且每个业务功能都要和这些业务功能混在一起。为了将业务功能的关注点和通用化功能的关注点分离开来,就出现了AOP技术。这些通用化功能的代码实现,对应的就是我们说的切面(Aspect)。

业务功能代码和切面代码分开之后,责任明确,比如有以下好处:

  • 开发者就能各自专注解决问题
  • 代码可以优雅的组织
  • 设计更加高内聚低耦合
    ###AOP的实现技术###
    但是代码分开的同时,为了保证功能的完整性,业务功能依然需要有事务和日志等特性,即切面最终需要合并(专业术语叫做织入, Weave)到业务功能中,这涉及AOP的实现技术,有三种方式:

1.编译时织入在代码编译时,把切面代码融合进来,生成完整功能的Java字节码,这就需要特殊的Java编译器了,AspectJ属于这一类

2.类加载时织入在Java字节码加载时,把切面的字节码融合进来,这就需要特殊的类加载器,AspectJ和AspectWerkz实现了类加载时织入

3.运行时织入在运行时,通过动态代理的方式,调用切面代码增强业务功能,Spring采用的正是这种方式。动态代理会有性能上的开销,但是好处就是不需要扩展编译器或者类加载器,和写普通Java程序没有区别。

###关键概念###

  • 切面(Aspect):指的就是通用功能的代码实现。
  • 目标对象(Target):要被织入切面的对象,有了AOP,目标对象可以专注于核心业务逻辑代码了。
  • 切入点(Pointcut):定义通知应该切入到什么地方,Spring支持的切入点就是方法调用,切入点的定义可以使用正则表达式,用以描述什么类型的方法调用。
  • 通知(Advice):切面是一个类,而通知就是类里的方法以及这个方法如何织入到目标方法的方式,根据织入到目标方法方式的不同,一共可以分为5种:

    (1).前置通知(Before)

    (2).后置通知(AfterReturning)

    (3).异常通知(AfterThrowing)

    (4).最终通知(After)

    (5).环绕通知(Around)

  • 织入(Weaving):AOP实现的过程,即将切面应用到目标对象,从而创建一个新的代理对象的过程,对于Spring来说,就是初始化Context中的对象时,完成织入操作。
    资料整理来自:http://www.tianmaying.com/qa/24
-------------本文结束感谢您的阅读-------------
坚持技术分享,您的支持将鼓励我继续创作!