项目1 初识Spring 现代的Java应用开发大多是基于Spring的应用开发。使用Spring能够让开发人员可 以专注于业务逻辑的开发,把代码中的基础设施交给Spring负责,以减少开发时间,提高编 码效率。Spring框架在Java应用开发中占有重要地位,是大多数Java开发人员必须要学 习的一门技术。 任务1.1 了解Spring Spring的中文意思是春天,意味着Spring的出现将为Java开发人员带来一个舒适、便 捷的开发环境。本节将对Spring的相关知识做初步的介绍,包括Spring是什么、Spring能 做什么、Spring的发展等内容。 1.1.1 Spring简介 Spring是一个基于JavaEE应用程序开发的轻量级开源框架。该框架由罗德·约翰逊 (RodJohnson)于2002年创建,用于解决JavaEE 编程开发中的复杂性,实现敏捷开发。 Spring使开发人员能够使用普通的JavaBean实现业务流程,同时为所有的JavaBean提供 了一个统一的应用配置框架。Spring的两大核心技术就是控制反转(inversionofcontrol, IOC)和面向切片编程(aspectorientedprogramming,AOP)。 1.1.2 Spring的作用 Spring将从图1-1所示的7个方面助力Java应用开发。 图1-1 Spring助力Java 1.方便构建微服务 微服务架构是当前Java开发的主流。微服务使得应用程序代码能够以可管理的、独立 Spring 框架应用开发——基于Spring Boot(微课视频版) 的模块化形式交付,同时各模块业务功能相对隔离,能够使应用程序更容易维护。Spring 提供的SpringBoot框架使开发人员能够更方便、更快捷地构建微服务应用程序,另外,提 供的SpringCloud框架可以方便管理和监控各个微服务。 2.实现响应式编程 响应式编程是一种基于数据流的异步非阻塞编程模型,其本质是对数据流或某种变化 所作出的反应。在使用时,开发人员能利用响应式编程的背压机制更方便地进行流量控制。 在高并发场景下,能够更好地利用多核心CPU的能力构建弹性的消息驱动系统。 3.系统架构“云原生” “云原生”的架构不仅能够使开发完毕的系统更方便地迁移上云,而且使系统中的非业 务代码和业务代码最大化松耦合,对于系统中的非业务功能则交给Spring管理。Spring提 供的SpringCloud框架负责应用程序在云中运行的许多非功能业务,如网关API 、服务配 置、服务注册发现、负载均衡、状态跟踪,熔断机制等。 4.方便Web应用开发 Spring提供的许多子项目可以方便构建Web应用程序。例如,Spring提供的SpringBoot框架可以简化Web应用程序的配置。提供的SpringSecurity框架集成了许多行业标 准的身份验证协议,增强了Web应用程序的安全性。提供的SpringData框架便于Web应 用程序访问关系数据库和非关系数据库。 5.系统架构Serverles 化 Serverles 即无服务,无服务不是没有服务器,只是将服务器的运维、管理和分配都托 管给了云提供商,开发人员只需关注业务逻辑代码的开发,而不必关注底层计算、存储资源 的使用和运维。Spring产品组合为构建Serverles 系统提供了强大的功能集合,便于开发 人员构建Serverles 化的系统架构。 6.构建基于流的事件驱动系统 事件驱动系统采用基于事件的异步数据收发模式,这样能够减少数据收发两端不必要 的同步等待时间,提升系统效率。Spring提供的SpringCloudStream框架整合了诸如 Kafka、RabbitMQ等主流的流式消息组件,简化了构建事件驱动系统的复杂性。 7.方便构建批处理应用 批处理模式就是系统无须与用户交互即可自动、高效地处理大量信息,如定时汇总计 算、定时通知、定时任务调度等。Spring提供的SpringBatch框架能够创建高性能、可扩展、 弹性的批处理应用程序,同时利用SpringBoot框架简化构建批处理应用程序的复杂度。 1.3 Spig的发展 1.rn 在2000年左右,JavaEE程序开发开始兴起,当时JavaEE程序大多基于EJB开发,而 EJB是一个重量级的业务框架,有框架臃肿、开发效率低、运行开销大等缺点。为了解决上 述问题,RodJohnson编写了一个轻便、灵巧、易于开发、测试和部署的轻量级开发框架——— interface21框架。interface21框架就是Spring框架的前身。随后RodJohnson以interface21 框架为基础,经过重新设计于2004年3月24日正式发布了Spig1.Sprn 众视野。Spring的整个发展流程如图1-2所示。 rn0版,ig正式进入公 目前,Spring已经发展到了Spring6版本。Spring5到Spring6是一次大版本号升级, 图1-2 Spring发展历程 这次升级是阻断式的,加入了很多新特性,同时不向下兼容。Spring官方将Spring6称为 Spring下一个十年的新开端。 任务1.2 认识Spring 项目模板 Spring构建了一系列项目模板,便于我们搭建自己的应用程序。下面介绍一些常用的 项目模板。 1.SpringBoot Spring是一个大而全的框架。随着Spring整合了越来越多的框架和组件,Spring本身 变得越来越复杂,配置过多,容易让初学者陷入“配置灾难”。因此,Spring推出了Spring Boot框架,SpringBoot采用约定优于配置的原则,简化了Spring配置和应用程序部署,降 低了Spring框架使用门槛。SpringBoot可以基于最少配置创建独立的Spring应用程序, 实现应用一键启动和部署。一个SpringBoot应用就可以看作一个单体的微服务项目。 2.SpringCloud 当前主流软件架构大多是基于云原生的分布式架构,一个系统会根据业务功能做模块 拆分。每个业务功能模块作为一个单独的服务,可以使用SpringBoot框架来开发,不同的 服务之间进行相互调用。部署时,不同的服务将分布式部署在不同的服务器上。但是随着 服务数量的越来越多,服务之间的调用和管理也越来越复杂,需要定制一套行之有效的框架 来开发和管理分布式服务。 3 项目1 初识Spring SpringCloud的出现就是为解决微服务架构中的服务治理问题。SpringCloud完全基 于SpringBoot开发,它利用SpringBoot的开发便利性,简化了分布式服务的开发、配置和 部署。SpringCloud整合了一系列框架,提供了服务发现注册、配置中心、消息总线、负载均 衡、熔断、数据监控等功能。利用SpringCloud可以把多个SpringBoot单体微服务项目统 一管理起来,组成一个整体的微服务集群,实现有效管理。 3.SpringCloudDataFlow SpringCloudDataFlow是一个基于微服务的分布式数据处理框架,支持构建基于Spring CloudStream流处理和SpringCloudTask/SpringBatch批处理的SpringBoot微服务项目。 SpringCloudDataFlow的优势在于如果企业没有专业的大数据技术团队支持,只要熟悉Java 和SpringBoot,也能够利用SpringCloudDataFlow编程实现大数据处理任务。 4.SpringData SpringBoot框架底层默认采用SpringData框架统一访问各种数据库。SpringData 的作用就是为了简化数据库的访问,包括常见关系型数据库和非关系型数据库。 5.SpringSecurity SpringSecurity是一个安全访问控制框架。它利用了SpringIOC和AOP思想,为应 用系统提供声明式的安全访问控制功能,使应用系统能够更方便、更快捷地实现安全控制。 任务1.3 了解Spring 容器 Spring容器是Spring框架的核心。Spring利用容器来帮助我们管理普通的JavaBean 对象(在后续内容中JavaBean对象统一简称为Bean)。Spring提供了两种类型的容器:一 种是BeanFactory;另一种是ApplicationContext。下面分别对两者做介绍。 1.3.1 BeanFactory BeanFactory是访问Spring容器的根接口,该接口为Spring依赖注入功能提供支持。 BeanFactory接口在org.springframework.beans.factory.BeanFactory包中定义。BeanFactory提 供了基本的容器功能,包括实例化Bean和获取Bean。BeanFactory在应用启动时不会去实 例化Bean,只有程序访问Bean的时候才会去实例化。这样能够使应用启动时占用较少资 源,但是获取Bean的速度就会相对慢一些,因为临时创建Bean也需要时间。Spring中有 很多实现类和子接口继承了BeanFactory接口,因此开发中很少直接使用,而多使用其 子类。 1.3.2 ApplicationContext ApplicationContext是BeanFactory的子接口,是开发中常用的Spring 容器。它在 org.springframework.context.ApplicationContext包中定义。与BeanFactory 不同的是, ApplicationContext在启动时就会实例化所有的Bean,同时还可以选择性地为某些Bean配 置懒加载来延迟Bean的实例化。此外,ApplicationContext在BeanFactory的所有功能基 础上还添加了对国际化、资源访问、事件传播、Web应用等方面的支持。 4 Spring 框架应用开发——基于Spring Boot(微课视频版) 实例化ApplicationContext容器方法如下: ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringDemoConfig. class); 其中,AnnotationConfigApplicationContext类会从类路径ClassPath 中寻找标识为 @Configuration的Spring配置类,用于实例化ApplicationContext容器。 任务1.4 体验Spring 编程 目前,Java开发的主流工具是Idea且利用Maven工具进行项目管理。下面介绍如何 利用Idea构建一个基本的SpringMaven项目。 1.4.1 环境准备 (1)已安装Java17。本书所有章节代码都基于Spring6构建。Spring6支持的最低 Java版本为Java17,因此需要确保在计算机上已安装Java17,并配置环境变量JAVA_ HOME为Java17的安装路径。本书所使用的Java版本为Java17.0.4。 (2)安装Idea并配置Maven。Idea版本为2023。本书后续项目都使用Maven管理,Idea 自带Maven插件,不需额外安装。每个Maven项目都有一个pom.xml文件,Maven中的依赖 包是基于pom.xml文件里面的三个标签来定位的。其 中,groupId为项目组id,一般为公司域名的倒写。artifactId为构件id,一般为项目名。version 为项目的版本。例如要引入Spring的webmvc相关Jar包,版本为6.0.3。可以在pom.xml文 件中添加标签,在标签内部添加如下信息。 org.springframework spring-webmvc 6.0.3 除了标签外,pom.xml文件里也提供了很多其他标签,在后续编程中 如有出现,再进行介绍。 1.4.2 创建SpringMaven项目 下面展示如何利用Idea创建一个简单的SpringMaven项目。 创建SpringMaven项目 建立Spring开发环境步骤说明 5 项目1 初识Spring Spring 框架应用开发——基于Spring Boot(微课视频版) 1.3 认识注解 4. 在Spring编程中注解被大量使用。注解并不是Spring独有的,早在Java5中就引入 了注解的概念。Spring在Java的基础上又扩充了很多新的注解,以方便编程。使用注解首 先要学会看懂注解,这里就必须要了解一个概念———元注解。元注解用于描述注解,元注解 本身也是一种注解,但是它能够应用到其他注解上面,对之进行解释说明。 元注解分为@Retention、@Documented、@Target、@Inherited、@Repeatable五种,下 面做简单介绍。 1.@Retti @Retention(e) 用(o) 于(n) 描述注解的生命周期。@R(n) etention注解有三种取值,具体如表1-1所示。 表1- 1 @Retention注解 取值类型描述使用方法 RetentionPolicy.SOURCE 表示被修饰的注解只在源代码 中保留,编译器不保留@Retention(RetentionPolicy.SOURCE) RetentionPolicy.CLASS 表示被修饰的注解只在.clas 文 件中,JVM不保留@Retention(RetentionPolicy.CLASS) RetentionPolicy.RUNTIME 表示被修饰的注解会被JVM保 留,在运行时有效@Retention(RetentionPolicy.RUNTIME) 2.@Documented @Documented用于描述注解可以被加入Javadoc工具文档中。 3.@Target @Target用于描述注解的使用范围,包括类、方法、变量等。@Target取值如表1-2所示。 表1- 2 @Target注解 取值类型 ElementType.ANNOTATION_ TYPE ElementType.CONSTRUCTOR 描述 表示被修饰的注解只能应 用在其他注解上 表示被修饰的注解只能应 用在构造函数上 使用方法 @Target(ElementType.ANNOTATION_ TYPE) @Target(ElementType.CONSTRUCTOR) ElementType.FIELD ElementType.LOCAL_ VARIABLE ElementType.METHOD 表示被修饰的注解只能应 用在类属性上 表示被修饰的注解只能应 用在局部变量上 表示被修饰的注解只能应 用在方法上 @Target(ElementType.FIELD) @Target(ElementType.LOCAL_VARIABLE) @Target(ElementType.METHOD) ElementType.PACKAGE 表示被修饰的注解只能应 用在包上@Target(ElementType.PACKAGE) ElementType.PARAMETER 表示被修饰的注解只能应 用在方法参数上@Target(ElementType.PARAMETER) ElementType.TYPE 表示被修饰的注解只能应 用在类、接口、枚举等元素上@Target(ElementType.TYPE) 4.@Inherited 被@Inherited修饰的注解作用在某父类上,如果该父类的子类没有被任何其他注解修 饰,那么这个子类就继承了父类的注解。具体使用方法如下。 /*定义Father 注解,被@Inherited 修饰*/ @Inherited public @interface Father { } /*定义Person 父类,被Father 注解修饰*/ @Father class Person{} /*定义Person 的子类man,也被Father 注解修饰*/ class man extends Person{} 5.@Repeatable @Repeatable用于描述该注解可重复使用在同一类、方法和属性上。例如使用注解 @PropertySources加载多个配置文件,可以采用以下写法: @PropertySources({@PropertySource(value="config1.xml"), @PropertySource(value="config2.xml")}) public class Config{ } 这是因为@PropertySources注解中有以下定义: public @interface PropertySources { PropertySource[] value(); } 其中,PropertySource也是一个注解,并被@Repeatable修饰,修饰代码如下: @Repeatable(PropertySources.class) public @interface PropertySource { } 因此,才能在@PropertySources中多次重复使用@PropertySource加载配置文件。 Spring中的注解非常多,但它们共同被这五大元注解组合修饰。 1.4.4 基于注解方式的Spring编程 在1.3.2节中提到了我们可以通过ApplicationContext容器来管理Bean。要获取具体 的Bean有两种方式,分别是基于配置文件的方式和基于注解方式,其中基于注解方式因使 用便捷成为项目开发中的主流。因此,这里重点介绍基于注解方式获取Bean。 基于注解方式获取Bean要定义一个Java类作为Spring配置类并以@Configuration注解 修饰,在配置类中使用注解生成不同的Bean。获取Bean时,首先获取ApplicationContext对 象,然后调用getBean方法通过id或类型获取具体的Bean。本书后续大部分Spring相关配置 7 项目1 初识Spring 均基于注解方式实现。 下面介绍如何以注解方式实例化ApplicationContext容器。 在src/main/java目录下分别创建两个文件夹bean和config,如图1-3所示。bean文 件夹用于存放JavaBean,config文件夹用于存放Spring配置类。 图1-3 创建文件夹bean和config 基于注解的Spring基本编程 在config文件夹下创建SpringDemoConfig.java文件作为Spring配置类,在SpringDemoConfig. java中输入以下代码。其中,@Configuration用于将该类标识为Spring配置类,@ComponentScan ("bean")用于设置生成Bean时自动扫描路径为ClassPath项目下的bean文件夹。 【SpringDemoConfig.java】 package config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("bean") public class SpringDemoConfig { } 在bean文件夹下创建类Demo1.java。该类中提供一个say方法,该方法用于控制台输 出hellodemo1。Demo1.java中代码如下,其中,@Component注解用于将Demo1这个类 标识为一个Spring组件类的Bean。 【Demo1.java】 package bean; import org.springframework.stereotype.Component; @Component public class Demo1 { public void say(){ System.out.println("hello demo1"); } } 在项目根目录src/main/java 下创建一个测试类BeanTest.java,在测试类中调用 Demo1类中的say方法打印输出hellodemo1。传统方式需要编写以下代码,手动创建一个 Demo1实例对象,然后调用Demo1对象的say方法。 8 Spring 框架应用开发——基于Spring Boot(微课视频版) Demo1 demo1=new Demo1(); demo1.say(); 使用Spring后,Demo1实例对象的创建交给Spring容器来做,创建完毕可从Spring容 器中利用getBean方法获取Demo1实例对象并调用say方法输出内容。在BeanTest.java 中输入以下代码,代码中通过id和类型两种不同方式获取实例化Demo1对象。 import bean.Demo1; import config.SpringDemoConfig; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class BeanTest { public static void main(String[] args){ //实例化ApplicationContext 容器 ApplicationContext ctx= new AnnotationConfigApplicationContext(SpringDemoConfig.class); Demo1 deCtxByName=(Demo1)ctx.getBean("demo1"); deCtxByName.say(); Demo1 deCtxByType=ctx.getBean(Demo1.class); deCtxByType.say(); } } 运行BeanTest.java即可在控制台看到分别打印出2次hellodemo1,如图1-4所示。 证明通过Bean的id和类型两种方法均可获取实例化Bean并调用方法输出结果。 图1-4 输出hellodemo1 修改Demo1.java文件,在其中添加一个无参数构造方法,在构造方法中添加打印语句。 下面所示粗体代码为新增内容。 【Demo1.java】 package bean; import org.springframework.stereotype.Component; @Component public class Demo1 { public Demo1(){ System.out.println("Constructor Demo1"); } 9 项目1 初识Spring public void say(){ System.out.println("hello demo1"); } } 修改BeanTest.java文件,main方法中只保留第一条语句,用于获取ApplicationContext对 象。注释如下面黑体代码。 【BeanTest.java】 import bean.Demo1; import config.SpringDemoConfig; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class BeanTest { public static void main(String[] args){ //实例化ApplicationContext 容器 ApplicationContext ctx= new AnnotationConfigApplicationContext(SpringDemoConfig.class); /* Demo1 deCtxByName=(Demo1)ctx.getBean("demo1"); deCtxByName.say(); Demo1 deCtxByType=ctx.getBean(Demo1.class); deCtxByType.say();*/ } } 运行BeanTest.java,看到控制台打印出ConstructorDemo1,如图1-5所示。代码中即 使不获取Demo1实例对象,在实例化ApplicationContext容器对象时,Demo1的无参构造 方法已经被调用,Demo1实例对象已经创建完毕。 图1-5 输出ConstructorDemo1 任务1.5 了解Spring 控制反转(IOC) 在传统编程中,大多数应用程序都是由多个类通过彼此的合作来实现复杂的业务逻辑,当 需要使用类的对象时,一般会直接在程序中直接创建,对象和程序本身形成了硬编码关系,耦 合度太高。如果能够将创建对象的权限转移给第三方容器实现,需要时再通过第三方容器获 取对象的引用,这样能够降低代码的耦合度,有利于代码维护。这正是IOC产生的原因。 10 Spring 框架应用开发——基于Spring Boot(微课视频版)