Spring 框架

Spring Framework是由Rod Johnson创建的一个轻量级的开源框架,它的目的是帮助开发团队构建简单,可移植,快速和灵活的基于JVM的系统和应用程序。

致力于提供构建企业级应用程序的一站式解决方案。Spring是模块化的,可以根据自己的需要进行组合,可以使用IoC容器,也可以只使用Hibernate集成代码或JDBC抽象层。

Spring框架支持声明式事务管理,通过RMI或Web服务远程访问业务逻辑,以及持久的存储数据。它提供了一个全功能的MVC框架,并能够将AOP透明地集成到正在开发的软件中。

Spring被设计为非侵入式的,这意味着逻辑代码通常不会对框架本身产生依赖。在集成过程中(如数据访问层),对数据访问技术和Spring库的将存在一些依赖关系。但是,可以很容易的将这些依赖关系与其余的代码隔离开。


Spring

如果你刚刚开始使用Spring,你可以通过创建一个基于Spring Boot的应用程序来开始使用Spring Framework。 Spring Boot提供了一种快速的方法来创建基于生产环境的Spring应用程序。它基于Spring框架,能够根据设定好的配置快速启动和运行。

Spring Framework是一个Java平台,为开发Java应用程序提供全面的基础架构支持。通过使用Spring处理基础架构,我们可以专注于应用程序。

Spring使我们从POJO开始构建应用程序,并将企业服务非侵入性地应用于POJO。 这个功能适用于Java SE编程模型和完整和部分Java EE。

作为应用程序开发人员,我们可以从Spring平台中受益良多,例如:

  • 使数据库事务中的Java方法执行,而不必处理事务API。
  • 使本地Java方法成为远程过程,而不必处理远程API。
  • 使本地Java方法成为管理操作,而不必处理JMX API。
  • 使本地Java方法成为消息处理程序,而不必处理JMS API。

依赖注入和控制反转

Java应用程序的运行范围可以从受限的嵌入式应用程序到n层服务器端企业应用程序,通常由协作形成应用程序的对象组成。因此,应用程序中的对象具有彼此依赖性。

虽然Java平台提供了丰富的应用程序开发功能,但它缺乏将基本构建块组织成一个整体的手段,这部分功能仍然需要架构师和开发人员来完成。虽然可以使用Factory,抽象工厂,构建器,装饰器和服务定位器等设计模式来组成应用程序的各种类和对象实例,但是这些模式只是形式化的,我们还必须在应用程序中自己去实现它。

Spring框架控制反转(IoC)组件,提供将完全不同的组件组合成我们需要的可以完成工作的应用程序。Spring框架将形式化的设计模式编译为可以集成到自己的应用程序中的一类对象。大量的应用通过控制反转方式使用Spring框架来设计强大的,可维护的应用程序。

模块

Spring框架由组织成约20个模块的特征组成。 这些模块分为核心容器,数据访问/集成框架,Web,AOP(面向切面的编程),工具,消息和测试,如下图所示:

Spring

核心容器由spring-core,spring-beans,spring-context,spring-context-support和spring-expression(Spring Expression Language)模块组成。

spring-core和spring-beans模块提供了框架的基本部分,包括IoC和依赖注入功能。 BeanFactory是一个复杂的工厂模式实现。它消除了编程单例的需要,并允许我们将依赖性的配置内容从实际的程序逻辑中分离出来。

Context(spring-context)模块建立在Core和Beans模块提供的实体基础之上:它是一种通过类似于JNDI注册表的框架样式方法访问对象的手段。Context模块从Beans模块继承其特性,并增加了对国际化(例如使用资源束),事件传播,资源加载以及通过例如Servlet容器的透明创建上下文的支持。Context模块还支持Java EE功能,如EJB,JMX和基本远程处理。 ApplicationContext接口是Context模块的焦点。spring-context-support提供支持将常见的第三方库集成到Spring应用程序上下文中,特别是用于缓存(EhCache,JCache)和调度(CommonJ,Quartz)。

spring-expression模块提供了一个强大的表达式语言(SpEL),用于在运行时查询和操作对象图。它是JSP 2.1规范中规定的统一表达式语言的扩展。该语言支持设置和获取属性值,属性分配,方法调用,访问数组的内容,集合和索引器,逻辑和算术运算符,命名变量,以及通过Spring IoC容器中的名称检索对象。它还支持列表投影和选择以及公共列表聚合。

spring-aop模块提供了一个符合AOP联盟的面向切面的编程实现,允许我们定义例如方法拦截器和切入点来干净地解耦实现应该分离的功能的代码。 使用源级元数据功能,还可以以类似于.NET属性的方式将行为信息合并到代码中。

单独的Aspects模块提供与AspectJ的集成。

Aspects模块提供类监视器支持和类加载器的实现,以便在某些应用服务器中使用。spring-instrument-tomcat模块包含Spring的Tomcat的工具代理。

Spring Framework 4 开始包括一个spring-messaging模块,它具有来自Spring Integration项目的关键抽象,例如Message,MessageChannel,MessageHandler和其他,用作基于消息传递的应用程序的基础。该模块还包括一组用于将消息映射到方法的注释,类似于基于Spring MVC注释的编程模型。

Data Access/Integration模块由JDBC,ORM,OXM,JMS和Transactions模块组成。

spring-jdbc模块提供了一个JDBC抽象层,消除了对繁琐的JDBC编码和解析数据库供应商特定的错误代码的需要。

spring-tx模块支持实现特殊接口的类和所有POJO的编程和声明事务管理。

spring-orm模块为流行的对象关系映射API提供了集成框架,包括JPA和Hibernate。通过spring-orm模块,可以使用这些O/R映射框架结合Spring提供的所有其他功能,例如前面提到的简单声明性事务管理功能。

spring-oxm模块提供了一个支持对象/ XML映射实现的抽象层,例如JAXB,Castor,JiBX和XStream。

spring-jms模块(Java消息服务)包含用于生成和使用消息的功能。从Spring Framework 4.1开始,它提供了与spring-messaging模块的集成。

Web模块由spring-web,spring-webmvc和spring-websocket模块组成。

spring-web模块提供基本的面向Web的集成功能,例如多部分文件上传功能和使用Servlet侦听器和面向Web的应用程序上下文来初始化IoC容器。 它还包含一个HTTP客户端和Web的相关部分的Spring的远程支持。

spring-webmvc模块(也称为Web-Servlet模块)包含用于Web应用程序的Spring的模型视图控制器(MVC)和REST Web服务实现。Spring的MVC框架提供了域模型代码和Web表单之间的清晰分离,并与Spring框架的所有其他功能集成。

spring-test模块支持使用JUnit或TestNG对Spring组件进行单元测试和集成测试。它提供了Spring ApplicationContext的一致加载和这些上下文的缓存。它还提供了模拟对象,可以使用它来单独测试代码。

使用场景

之前描述的构建块使Spring成为许多场景中的逻辑选择,从在资源受限设备上运行的嵌入式应用程序到使用Spring的事务管理功能和Web框架集成的完善的企业应用程序。

下图是一个典型的完整Spring Web应用程序: Spring

Spring的声明式事务管理功能使Web应用程序具有完全事务性,就像使用EJB容器管理的事务一样。 所有的定制业务逻辑都可以通过简单的POJO实现,并由Spring的IoC容器管理。 其他服务包括独立于Web层的发送电子邮件和验证的支持,允许我们选择执行验证规则的位置。 Spring的ORM支持集成了JPA和Hibernate; 例如,当使用Hibernate时,可以继续使用现有的映射文件和标准的Hibernate SessionFactory配置。 表单控制器将Web层与域模型无缝集成,无需ActionForms或将HTTP参数转换为域模型值的其他类。

下图是通过Spring中间层使用第三方Web框架: Spring

有时情况不允许你完全切换到不同的框架。Spring框架不强迫你使用它里面的一切。 使用Struts,Tapestry,JSF或其他UI框架构建的现有前端可以与基于Spring的中间层集成,这允许我们使用Spring事务功能。 我们只需要使用ApplicationContext连接我们的业务逻辑,并使用WebApplicationContext来集成我们的web层。

下图是一个远程使用场景: Spring

当我们需要通过Web服务访问现有代码时,可以使用Spring的Hessian-,Rmi-或HttpInvokerProxyFactoryBean类。 启用对现有应用程序的远程访问并不困难。

下图是一个EJB——封装现有POJO的场景: Spring

Spring Framework还为Enterprise JavaBeans提供了一个访问和抽象层,使您可以重用现有的POJO,并将其封装在无状态会话bean中,以用于可能需要声明性安全性的可扩展,故障安全的Web应用程序。

构建RESTful Web服务

我们将构建一个可以接受HTTP GET请求的服务,例如这样:

1
http://localhost:8080/greeting

然后使用Hello World的JSON表述来进行响应:

1
{"id":1,"content":"Hello, World!"}

我们可以在查询字符串中使用可选的名称参数自定义问候语:

1
http://localhost:8080/greeting?name=User

名称参数值覆盖默认值“World”,并反映在响应中:

1
{"id":1,"content":"Hello, User!"}

1.构建前的准备: - JDK 1.8或更新版本 - Maven 3.0+ - 你用来开发的文本编辑器或IDE

2.首先你设置一个基本的构建脚本。 创建以下子目录结构; 例如,使用mkdir -p src/main/java/hello:

1
2
3
4
└── src
└── main
└── java
└── hello

3.新建pom.xml文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.springframework</groupId>
<artifactId>gs-rest-service</artifactId>
<version>0.1.0</version>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.2.RELEASE</version>
</parent>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<properties>
<java.version>1.8</java.version>
</properties>


<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

<repositories>
<repository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories>
</project>

Spring Boot Maven插件提供了许多方便的功能: - 它收集类路径上的所有jar,并构建一个单独的,可运行的“über-jar”,这使得执行和传输服务更加方便。 - 它搜索public static void main () 方法来标记可运行类。 - 它提供了一个内置的依赖解析器,用于设置版本号以匹配Spring Boot依赖关系。你可以覆盖任何你想要的版本,但它会默认为Boot选择的版本集。

4.创建资源表示类

现在我们已经设置了项目和构建系统,可以创建我们的Web服务了。

通过使用服务交互开始该过程。

该服务将处理/greeting的GET请求,有选择性的在查询字符串中使用name参数。GET请求应在表示问候语的正文中返回带有JSON的响应“200 OK”。它应该看起来像这样:

1
2
3
4
{
"id": 1,
"content": "Hello, World!"
}

id字段是问候语的唯一标识符,content是问候语的文本表示。

要对问候表示进行建模,请创建资源表示类。 提供一个POJO对象,其中包含id和content数据的字段,构造函数和访问器,src/main/java/hello/Greeting.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package hello;

public class Greeting {

private final long id;
private final String content;

public Greeting(long id, String content) {
this.id = id;
this.content = content;
}

public long getId() {
return id;
}

public String getContent() {
return content;
}
}

下面的步骤中,Spring使用Jackson JSON库自动将Greeting类型的实例编译成JSON。

5.创建将提供这些问候的资源控制器。

在Spring构建RESTful Web服务的方法中,HTTP请求由控制器处理。这些组件很容易通过@RestController注释来识别,而GreetingController通过返回一个Greeting类的新实例来处理/greeting的GET请求,src/main/java/hello/GreetingController.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package hello;

import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingController {

private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();

@RequestMapping("/greeting")
public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) {
return new Greeting(counter.incrementAndGet(),
String.format(template, name));
}
}

这个控制器简洁和简单,我们来一步步地分解它。

@RequestMapping注释确保将/greeting的HTTP请求映射到greeting()方法。

上面的示例不指定GET与PUT,POST等,因为@RequestMapping默认映射所有HTTP操作。使用@RequestMapping(method = GET)缩小此映射。@RequestParam将查询字符串参数名的值绑定到greeting()方法的name参数中。此查询字符串参数显式标记为可选(缺省情况下为required = true),如果请求中不存在,将使用defaultValue“World”。

方法的实现基于计数器的下一个值创建并返回一个带有id和content属性的Greeting对象,并使用问候模板格式化给定的名称。

传统的MVC控制器和上面的RESTful Web服务控制器之间的主要区别是创建HTTP响应主体的方式。这个RESTful Web服务控制器不是依赖于视图技术来执行服务器端将问候数据呈现为HTML,而是简单地填充并返回Greeting对象。对象数据将作为JSON直接写入HTTP响应。

这个代码使用Spring 4的新的@RestController注释,它将类标记为一个控制器,每个方法都返回一个域对象而不是一个视图。它是@Controller和@ResponseBody的缩写。

Greeting对象必须转换为JSON。由于Spring的HTTP消息转换器支持,你不需要手动进行这种转换。因为Jackson 2在类路径上,所以Spring的MappingJackson2HttpMessageConverter会自动选择将Greeting实例转换为JSON。

6.编译应用程序

虽然可以将此服务打包为用于部署到外部应用程序服务器的传统WAR文件,但下面演示的通过更简单的方法创建了一个独立应用程序。 你把一切都包装在一个可执行的JAR文件中,由一个古老但是非常好使的main()方法来驱动。 你使用Spring的支持将Tomcat servlet容器嵌入为HTTP运行时,而无须部署到外部实例,src/main/java/hello/Application.java:

1
2
3
4
5
6
7
8
9
10
11
12
package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

@SpringBootApplication是一个标记,添加以下所有内容:

  • @Configuration将类标记为应用程序上下文的bean定义的源。
  • EnableAutoConfiguration告诉Spring Boot根据类路径设置,其他bean和各种属性设置开始添加bean。
  • 通常你会为Spring MVC应用程序添加@EnableWebMvc,但是Spring Boot在类路径上看到spring-webmvc时会自动添加它。这将应用程序标记为Web应用程序,并激活关键行为,如设置DispatcherServlet。
  • @ComponentScan告诉Spring在hello包中查找其他组件,配置和服务,使它能够找到控制器。
  • main()方法使用Spring Boot的SpringApplication.run()方法来启动应用程序。你注意到没有一行XML?也没有web.xml文件。这个Web应用程序是100%纯Java,你不必处理配置任何管道或基础设施。

7.构建可执行JAR

可以使用./maven spring-boot:run运行应用程序。或者,可以使用./mvn clean包构建JAR文件。 然后可以运行JAR文件:

1
$ java -jar target/gs-rest-service-0.1.0.jar

8.测试 现在服务已启动,访问 http://localhost:8080/greeting ,可以看到:

1
{"id":1,"content":"Hello, World!"}

使用 http://localhost:8080/greeting?name=User 提供name查询字符串参数。 注意content属性的值如何从“Hello,World!” 到“Hello User!”:

1
{"id":2,"content":"Hello, User!"}

这个演示了GreetingController中的@RequestParam按照预期的设计那样工作。name参数的默认值为“World”,但始终可以通过查询字符串显式覆盖。

还要注意id属性从1到2的变化。这证明你正在对多个请求的同一个GreetingController实例进行操作,并且它的计数器字段在每个调用中按预期增加。

9.下载示例的源代码,使用Git克:

1
2
git clone https://github.com/spring-guides/gs-rest-service.git
cd into gs-rest-service /initial

更多内容请访问官网:

http://spring.io/guides