1.1 什么是Spring
1.1.1 简单介绍
很久之前,人们想吃饭就得自己做,既需要自己准备各种食材,又需要自己切菜,烧火,按照步骤把食材放入锅内,还要把握好佐料的量。一旦步骤没做对,做出来的饭菜可能会很难吃。这时候就很难受了,重新做一份嫌麻烦,吃下去嫌难吃,进退两难,只能自己忍受。直到一个叫Spring的人开了个餐馆,人们可以不用自己做饭了,想吃什么可以直接在菜单上点,想要什么样的口味可以写在菜的后面。之后就等着服务员上菜就可以了。餐馆呢,根据客人的需求做饭菜,做好了就让服务员端给食客。如果食客觉得上的饭菜难吃、不满意,就不吃,告诉服务员哪道菜哪里出了问题,让重新做一份。
Spring就像上面的餐馆一样。Spring提供了一个容器,相当于上面的餐馆。这个容器通常称为Spring上下文,他们会创建和管理应用组件,这些组件相当于上面的食材、佐料。这些组件,即bean会在Spring应用上下文中装配在一起,形成一个完整的应用程序,相当于做菜,按照食材和佐料,按照工序做在一起就做成了一道菜。
1.1.2 Spring IoC和DI
SpringIoC是Spring的核心,贯穿Spring的始终。而DI是IoC动态的向某个对象提供所需的其他对象的实现。
下面阐述内容参考了Iteye的开涛这位技术牛人对Spring框架的IOC的理解,原文地址:IoC之2.1 IoC基础 ——跟我学Spring3 。有些地方与原文理解不同,请自己选择。
-
SpringIoC(Spring invertion of Control),即“控制反转”,将设计好的类交给容器控制,而不是在对象内部直接控制。一看这个词就知道重点在于,“控制”和“反转”两个词。不经想到“谁控制谁,控制了什么?”,“什么是反转,反转了什么?”。这也是控制反转的重点。
- 谁控制谁,控制什么:传统的Java SE程序设计,是在对象内部通过new进行创建对象,是程序主动创建对象,也就是程序控制对象的创建;而IoC有一个专门的容器用来控制对象的创建,也就是容器控制对象的创建。对象创建需要外部资源,所以控制的是外部资源的获取(包括基本数据、对象等)。
- 什么是反转,反转什么:“反转”一般会联想到“正”。“正”指的是传统应用程序是在对象中主动去获取依赖对象;而“反转”则是由容器创建并注入对象所依赖的对象。即,对象被动的等待容器查找或创建并注入依赖对象。因为在传统设计中,依赖对象的获取是主动创建并注入的,但是在IoC中是由容器来实现的,所以依赖对象的获取方式反转了,由主动变成了被动。
-
DI(Dependency Injection),即“依赖注入”。组件之间是存在依赖关系的,在IoC中这种依赖关系是由容器在运行时决定的,即在运行时,由容器动态的将某个以来关系注入到组件之间。依赖注入明显的提高了组建的宠用频率,为系统搭建了一个灵活、可扩展的平台。 正因为依赖注入的存在,程序员只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:
- 谁依赖谁: 对象依赖于外部资源。
- 为什么需要依赖: 某些业务逻辑需要多个组件共同完成,所以组件之间需要依赖(其实是存在更好)。
- 谁注入谁: IoC容器注入应用程序某个依赖于外部资源的对象。
- 注入了什么: 注入某个依赖于外部资源的对象所需要的外部资源(基本数据、对象、常量数据)。
1.2初始化Spring应用
初始化Spring应用的方案很多。下面介绍Spring Initializr方式
1.2.1 Spring Initializr方式
Spring Initializr是一个基于浏览器的Web应用,同时也是一个REST API,能够生产一个Spring项目结构的骨架,我们还可以使用各种想要的功能来填充它。使用Spring Initializr的几种方式如下:
- 通过地址为start.spring.io/ 的web应用;
- 在命令行中使用curl命令;
- 在命令行中使用Spring Boot命令行接口;
- 在Spring Tool Suite中创建新项目;
- 在IntelliJ IDEA中创建新项目;
- 在NetBeans中创建新项目。
1.2.2 使用IDEA初始化Spring项目
要在IDEA初始化Spring项目,首先点击New Project,点击后会出现新的对话框如图1.2。
图1.2 在IDEA中使用Initializr初始化一个新项目
接下来选择Spring Initializr,默认Default是选中的。之后点击next会出现图1.3。
图1.3 为应用指定通用的项目信息
Group是组织名称,Artifact是项目2名称,Type是选择项目组织方式,language是编程语言,Packaging是项目压缩格式,version是语言版本。根据自己的需求填写这些信息。之后点击next。会弹出图1.4的新对话框。
图1.4 选择Starter依赖
在这个界面选择依赖项、Spring Boot版本等。点击Next后出现图1.5。
图1.5 项目名称及地址
在图1.5填写项目名称及项目地址。这样一个Spring项目就初始化好了。
1.2.3Maven新建项目目录结构及每个目录的作用
Program Name
|——src
| |——main
| | |——java //源码
| | | |——com.hututublogs.tacocloud
| | | | |——TacoCloudApplication.java //Spring Boot主类,会启动项目
| | |——resources //资源
| | | |——static //存放为浏览器服务的静态内容(图片、样式表、JavaScript)
| | | |——templates //存放用于渲染内容到浏览器的模板文件
| | | |——application.properties //提供了改写配置属性的地方
| |——test
| | |——java //测试代码
| | | |——com.hututublogs.tacocloud
| | | | |——TacoCloudApplicationTests.java
| |——.gitignore
| |——HELP.md
| |——mvnw //Maven包装器(wrapper)脚本。
| |——mvnw.cmd //Maven包装器(wrapper)脚本。
| |——pom.xml //Maven构建规范
| |——taco-cloud.iml
探索构建规范
在填充Initializr表单的时候,我们声明项目要使用Maven来进行构建。因此Spring Initializr所生成的pom.xml文件已经包含了我们所选择的依赖。程序清单1.1展示了Initializr为我们提供的完整pom.xml。
程序清单1.1 初始的Maven构建规范
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hututublogs</groupId>
<artifactId>taco-cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> ⬅打包为JAR
<name>taco-cloud</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies> ⬅Starter依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin> ⬅Spring Boot插件
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
parent 元素,更具体来说是他的 version 子元素。这表明我们的项目要以Spring-boot-starter-parent作为父POM。除了其他的伊邪功能之外,这个父POM为Spring项目常用的一些库提供了依赖管理,现在不需要指定他们的版本,因为这是通过父POM来管理的。这里的2.4.3表明要使用Spring Boot2.4.3。
注意到3个依赖的artifact ID上都有Starter这个单词。Spring Boot starter 依赖的特别之处在于他们本身并不包含库代码,而是传递性地拉去其他的库。这种starter依赖主要由3个好处:
- 构建文件会显著健翔并且易于管理,因为这样不必为每个所需的依赖库都声明依赖。
- 我们能够根据他们所提供的功能来思考依赖,而不是根据库的名称。如果是开发Web应用,那么你只需要添加web starter就可以了,而不必添加一堆单独的库再编写Web应用。
- 我们不必再担心库版本的问题。你可以直接相信给定版本的Spring Boot,传递性的引入的库的版本是兼容的。现在,你只需要关心使用的是哪个版本的Spring Boot就可以了。
最后,构建规范还包含一个Spring Boot插件。这个插件提供了一些重要的功能。
- 它提供了一个Maven goal,允许我们使用Maven来运行应用。
- 它会确保依赖的所有库都会包含在可执行JAR中,并且能够保证它们在运行时类路径下是可用的。
- 它会生成一个manifest文件,将引导类(....Application.java)声明为可执行JAR的主类。
1.3 Spring Boot DevTools
提供了一些便利的开发期工具,其中包括
- 代码变更后应用会自动重启:
DevTools 会检测变更,当项目中的代码和属性文件发生变化后,这些变更很快就能发挥作用。准确来说,DevTools运行时,应用程序会被加载到Java虚拟机两个独立的类加载器中。其中一个类加载器加载经常变动的内容,也就是Java代码、属性文件和项目中”src/main/“路径下的几乎所有文件。另一个加载器加载不太可能经常发生变化的内容,也就是依赖库。
当探测到变化时,DevTools只会重新加载包含项目代码的类加载器,并重启Spring的应用上下文,在这个过程中另外一个类加载器和JVM会不动。这样只重新加载一个类加载器,能够减少应用重启的时间。
这种策略的一个不足之处就是自动重启无法反映依赖项的变化。因为包含依赖项的类加载器不会自动重新加载。
- 当面向浏览器的资源(如模板、JavaScript、样式表)等发生变化时,会自动刷新浏览器;自动禁用模板缓存;
像Thymeleaf和FreeMarker这样的模板方案在配置时会缓存模板解析的结果。这样,在为每个请求提供服务的时候,就可以不用重新解析模板了。这种方式在生产环境中能够带来性能上的提升,但是在开发阶段就不是那么好了。因为,如果缓存模板,就算我们刷新浏览器也无法看到变更的效果,除非我们重新启动应用。
DevTools通过禁用模板缓存解决了这个问题。DevTools会和应用程序同时自动启动一个LiveReload服务器。这个服务器本身没多大作用,但是结合浏览器的插件就能够在模板、图片、样式表、JavaScript等发生变化时自动刷新浏览器。
- 如果使用H2数据库的话,内置了H2控制台。
如果使用H2数据库进行开发,DevTools将会自动启用H2.这样我们就能通过浏览器访问http://localhost:8080/h2-console ,看到应用所使用的数据。
1.4俯瞰Spring风景线
要想了解Spring的整体状况,只需查看完整的Spring Initializr Web表单上的那一堆复选框列表即可。
1.4.1 Spring核心框架
Spring核心框架是Spring领域中一切的基础。它提供了核心容器和依赖注入框架,另外还提供了一些其他重要的特性。
1.4.2 Spring Boot
我们已经看到了Spring Boot带来的很多收益,包括starter依赖和自动配置。除了这些,Spring Boot还提供了大量其他有用的特性:
- Actuator能够洞察应用运行时的内部工作状况,包括指标、线程dump、应用的健康状况以及应用可用的环境属性;
- 灵活的环境属性规范;
- 在核心框架的测试辅助功能之上提供了对测试的额外支持。 除此之外Spring Boot还提供了一个基于Groovy脚本的编程模型,称为Spring Boot命令行接口(Command-Line Interface,CLI)。使用CLI可以讲真各应用编写为Groovy脚本的集合,并通过命令行运行它们。
1.4.3 Spring Data
尽管Spring核心框架提供了基础的数据持久化支持,但是Spring Data提供了非常令人惊叹的功能:将应用程序的数据repository定义为简单的Java接口,在定义驱动存储和检索数据的方法时使用一种命名约定即可。
此外,Spring Data能够处理多种不同类型的数据库,包括关系型数据库(JPA)、文档数据库(Mongo)、图数据库(Neo4j)等。
1.4.4 Spring Security
Spring Security是Spring健壮的安全框架,包括身份验证、授权和API安全性。
1.4.5 Spring Integration 和 Spring Batch
Spring Integration和Spring Batch为基于Spring的应用程序提供了集成其他应用或本应用其他组件的模式。
1.4.6 Spring Cloud
微服务是一个热门话题,解决了开发期和运行期的一些实际问题。然而这样做的过程中,带来了一些挑战。Spring Cloud是使用Spring开发云原生应用程序的一组项目,直面解决这些挑战。
附录、注解
-
@SpringBootApplication:一个组合注解,组合了以下三个注解:
@SpringBootConfiguration: 将该类声明为配置类;
@EnableAutoConfiguration:启用Spring Boot 的自动配置;
@ComponentScan:启用组件扫描。
-
@RunWith:是JUnit的注解,它会提供一个测试运行器(runner)来指导JUnit如何运行测试。