1. 前言:
继续学习Spring Boot~
2. 概念
对Spring Boot的宏观理解,它的诞生是为了简化 Spring 应用的搭建和开发过程,具有 Spring 一切优秀特性,而且使用更加简单,功能更加丰富,性能更加稳定而健壮。在Spring Boot中我们使用基于注解和JAVA的配置方式,抛弃XML!
学习Spring Boot最好还是对Spring、Servlet有基本的理解。
2.1. 三层架构
注意区别MVC架构即可,MVC是表现层(Web层)的一个设计模式,真正意义的三层架构如下:
- A 表现层—Web层
- B 业务层—Service层
- C 持久层—Dao层
2.2. 控制反转—IoC
IoC——Inversion of Control,指的是将对象的创建权交给 Spring 去创建。使用 Spring 之前,对象的创建都是由我们自己在代码中new创建。而使用 Spring 之后。对象的创建都是给了 Spring 框架。控制反转可以用许多方式表达,依赖注入是其中一种方式。
2.3. 依赖注入—DI
Dependency Injection,当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者实例的工作通常由Spring容器来完成,然后注入调用者。
Spring框架的核心功能之一就是通过依赖注入的方式来管理Bean之间的依赖关系。DI 主要有两种变体,即通过构造函数参数形式和通过setter方法形式:
- Constructor-based dependency injection,当容器调用带有多个参数的构造函数类时,实现基于构造函数的 DI,每个代表在其他类中的一个依赖关系。
- Setter-based dependency injection,基于 setter 方法的 DI 是通过在调用无参数的构造函数或无参数的静态工厂方法实例化 bean 之后容器调用 beans 的 setter 方法来实现的。
2.4. 面向切面编程—AOP
先理解什么是切面。用刀把一个西瓜分成两瓣,切开的切口就是切面;炒菜,锅与炉子共同来完成炒菜,锅与炉子就是切面。web层级设计中,web层->网关层->服务层->数据层,每一层之间也是一个切面。编程中,对象与对象之间,方法与方法之间,模块与模块之间都是一个个切面。
其他的先忽略,需要仔细研究。
Spring 框架的 AOP 模块提供了面向方面的程序设计实现,可以定义诸如方法拦截器和切入点等,从而使实现功能的代码彻底的解耦出来。
2.5. 容器—Container
Spring 是一个容器,因为它包含并且管理应用对象的生命周期。Spring 容器是 Spring 框架的核心。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。这些对象被称为 Spring Beans。在Spring中BeanFactory是IOC容器的实际代表者。
2.6. “对象”—Bean
Bean是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。这些 bean 是由用容器提供的配置元数据创建的。把配置元数据提供给 Spring 容器有基于XML、注解和JAVA三种方式。Bean的重要属性有作用域(scope)、初始化与销毁和与依赖注入相关的constructor-arg、properties、autowiring mode等。
2.7. 自动装配—Autowire
Spring 容器可以在不使用<constructor-arg>
和<property>
元素的情况下自动装配相互协作的 bean 之间的关系。Spring中可以使用<bean>
元素的autowire属性为一个 bean 定义指定自动装配模式,选择由属性名或由属性数据类型自动装配。
以由属性名自动装配举例,在 XML 配置文件中 beans 的auto-wire属性设置为byName。然后尝试将它的属性与配置文件中定义为相同名称的 beans 进行匹配和连接。如果找到匹配项,它将注入这些 beans,否则,它将抛出异常。总的来说,如果在一个类A中使用了另一个类B作为属性,若不想显式的对B进行绑定,就可以使用自动装配。
Spring采用基于注解的方式配置时,@Autowired是最常用的注解之一,这个注解的功能就是为我们注入一个定义好的 bean。
2.8. Spring Boot starter
Spring Boot 将日常企业应用研发中的各种场景都抽取出来,做成一个个的 starter(启动器),starter 中整合了该场景下各种可能用到的依赖,用户只需要在 Maven 中引入 starter 依赖,SpringBoot 就能自动扫描到要加载的信息并启动相应的默认配置。starter 提供了大量的自动配置,让用户摆脱了处理各种依赖和配置的困扰。所有这些 starter 都遵循着约定成俗的默认配置,并允许用户调整这些配置,即遵循“约定大于配置”的原则。
以 spring-boot-starter-web 为例,它能够为提供 Web 开发场景所需要的几乎所有依赖,因此在使用 Spring Boot 开发 Web 项目时,只需要引入该 Starter 即可,而不需要额外导入 Web 服务器和其他的 Web 依赖。
spring-boot-starter-parent 是所有 Spring Boot 项目的父级依赖,它被称为 Spring Boot 的版本仲裁中心,可以对项目内的部分常用依赖进行统一管理。Spring Boot 项目可以通过继承 spring-boot-starter-parent 来获得一些合理的默认配置如默认 JDK 版本、默认字符集、依赖管理功能、资源过滤、默认插件配置、识别 application.properties(或yml)类型的配置文件。
2.9. 配置文件—Spring Boot profile
在实际的项目开发中,一个项目通常会存在多个环境,例如,开发环境、测试环境和生产环境等,不同环境的配置也不尽相同。
Spring Boot 的配置文件共有两种形式:.properties 文件和 .yml 文件,不管哪种形式,它们都能通过文件名的命名形式区分出不同的环境的配置,文件命名格式为:
application-{profile}.properties/yml
其中,{profile} 一般为各个环境的名称或简称,例如 dev、test 和 prod 等等。
2.9.1. 默认配置文件
通常情况下,Spring Boot 在启动时会将 resources 目录下的 application.properties 或 apllication.yml 作为其默认配置文件,我们可以在该配置文件中对项目进行配置,但这并不意味着 Spring Boot 项目中只能存在一个 application.properties 或 application.yml。
2.9.2. 外部配置文件
除了默认配置文件,Spring Boot 还可以加载一些位于项目外部的配置文件。我们可以通过如下 2 个参数,指定外部配置文件的路径:
- spring.config.location
- spring.config.additional-location
我们可以先将 Spring Boot 项目打包成 JAR 文件,然后在命令行启动命令中,使用命令行参数 —spring.config.location,指定外部配置文件的路径。
java -jar {JAR} --spring.config.location={外部配置文件全路径}
需要注意的是,使用该参数指定配置文件后,会使项目默认配置文件(application.properties 或 application.yml )失效,Spring Boot 将只加载指定的外部配置文件。
2.10. Spring Boot 配置
Spring Boot 不仅可以通过配置文件进行配置,还可以通过环境变量、命令行参数等多种形式进行配置。这些配置都可以让开发人员在不修改任何代码的前提下,直接将一套 Spring Boot 应用程序在不同的环境中运行。
2.10.1. 配置加载顺序
- 命令行参数
- 来自 java:comp/env 的 JNDI 属性
- Java 系统属性(System.getProperties())
- 操作系统环境变量
- RandomValuePropertySource 配置的 random.* 属性值
- 配置文件(YAML 文件、Properties 文件)
- @Configuration 注解类上的 @PropertySource 指定的配置文件
- 通过 SpringApplication.setDefaultProperties 指定的默认属性
以上所有形式的配置都会被加载,当存在相同配置内容时,高优先级的配置会覆盖低优先级的配置;存在不同的配置内容时,高优先级和低优先级的配置内容取并集,共同生效,形成互补配置。同一位置下,Properties 文件优先级高于 YAML 文件。
2.10.2. 自动配置
Spring Boot 的自动配置是基于 Spring Factories 机制实现的。
Spring Factories 机制是 Spring Boot 中的一种服务发现机制,这种扩展机制与 Java SPI 机制十分相似。Spring Boot 会自动扫描所有 Jar 包类路径下 META-INF/spring.factories 文件,并读取其中的内容,进行实例化,这种机制也是 Spring Boot Starter 的基础。具体来说,spring-core 包里定义了 SpringFactoriesLoader 类,这个类会扫描所有 Jar 包类路径下的 META-INF/spring.factories 文件,并获取指定接口的配置。
spring.factories 文件本质上与 properties 文件相似,其中包含一组或多组键值对(key=vlaue),其中,key 的取值为接口的完全限定名;value 的取值为接口实现类的完全限定名,一个接口可以设置多个实现类,不同实现类之间使用“,”隔开。
基于以上,Spring Boot的自动配置也是通过同样方式实现的,在 spring-boot-autoconfigure-xxx.jar 类路径下的 META-INF/spring.factories 中设置了 Spring Boot 自动配置的内容。
2.11. 拦截器
拦截器可以根据 URL 对请求进行拦截,主要应用于登陆校验、权限验证、乱码解决、性能监控和异常处理等功能上。
在 Spring Boot 项目中,使用拦截器功能通常需要以下 3 步:
- 定义拦截器;
- 注册拦截器;
- 指定拦截规则(如果是拦截所有,静态资源也会被拦截)。
2.11.1. 定义拦截器
只需要创建一个拦截器类,并实现 HandlerInterceptor 接口即可,该接口中定义以下 3 个方法(按需重写即可):
- boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler),该方法在控制器处理请求方法前执行,其返回值表示是否中断后续操作,返回 true 表示继续向下执行,返回 false 表示中断后续操作。
- void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView),该方法在控制器处理请求方法调用之后、解析视图之前执行,可以通过此方法对请求域中的模型和视图做进一步修改。
- void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex),该方法在视图渲染结束后执行,可以通过此方法实现资源清理、记录日志信息等工作。
2.11.2. 注册拦截器
创建一个实现了 WebMvcConfigurer 接口的配置类(使用了 @Configuration 注解的类),重写 addInterceptors() 方法,并在该方法中调用 registry.addInterceptor() 方法将自定义的拦截器注册到容器中。示例:
@Configuration
publicclassMyMvcConfigimplementsWebMvcConfigurer{
......
@Override
public void addInterceptors(InterceptorRegistryregistry){
registry.addInterceptor(newLoginInterceptor());
}
}
2.11.3. 指定拦截规则
在指定拦截器拦截规则时,可以调用两个方法,说明如下:
- addPathPatterns:该方法用于指定拦截路径,例如拦截路径为
/**
,表示拦截所有请求,包括对静态资源的请求。 - excludePathPatterns:该方法用于排除拦截路径,即指定不需要被拦截器拦截的请求。
示例:
registry.addInterceptor(newLoginInterceptor()).addPathPatterns("/**")
可以链式调用。
3. 常见注解介绍
3.1. @Autowired
这个注解是属于 Spring 的容器配置的一个注解,与它同属容器配置的注解还有:@Required,@Primary, @Qualifier 等等。
在 Spring 的世界当中,自动装配指的就是使用将 Spring 容器中的 bean 自动的和我们需要这个 bean 的类组装在一起,注入一个定义好的 bean。
用法:
- 应用于字段
- 应用于构造函数
- 应用于 setter 方法
- 应用于具有任意名称和多个参数的方法
- 添加到需要该类型数组(或容器)的字段或方法,则 Spring 会从 ApplicationContext 中搜寻符合指定类型的所有 bean
3.2. @RestController
用于标注控制层组件。在 Spring Boot 中,@Controller 注解是专门用于处理 Http 请求处理的,是以 MVC 为核心的设计思想的控制层。@RestController 则是 @Controller 的衍生注解,都是用来表示Spring某个类的是否可以接收HTTP请求。
@RestController是@Controller和@ResponseBody的结合体,两个标注合并起来的作用。@Controller类中的方法可以直接通过返回String跳转到jsp、ftl、html等模版页面。在方法上加@ResponseBody注解,也可以返回实体对象。@RestController类中的所有方法只能返回String、Object、Json等实体对象,不能跳转到模版页面。
用法(感觉有点问题):
@Controller: 一般应用在有返回界面的应用场景下.例如,管理后台使用了 thymeleaf 作为模板开发,需要从后台直接返回 Model 对象到前台,那么这时候就需要使用 @Controller 来注解。
@RestController: 如果只是接口,那么就用 RestController 来注解.如前端页面全部使用了 Html、Jquery来开发,通过 Ajax 请求服务端接口,那么接口就使用 @RestController 统一注解。
3.3. @…Mapping
表示路由请求,可以设置各种操作方法。最基本的是@RequestMapping,@GetMapping、@PostMapping、@PutMapping、@DeleteMapping 是 @RequestMapping 的子集,分别表示用不同的请求方式的对应路由。
举例:
@RequestMapping(value="/add",method = RequestMethod.POST),params="myParam=xyz"
表示路由为 /add 的 POST 请求,但仅仅处理头部包括 myParam=xyz 的请求。
@GetMapping("/add")等价于@RequestMapping(method = RequestMethod.GET,value = "/add")
3.4. @Configuration 和 @Bean
带有@Configuration的注解类表示这个类可以使用 Spring IoC 容器作为 bean 定义的来源。@Bean注解告诉 Spring,一个带有 @Bean 的注解方法将返回一个对象,该对象应该被注册为在 Spring 应用程序上下文中的 bean。例如:
@Configuration
public class HelloWorldConfig{
@Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
}
3.5. @SpringBootApplication
所有 Spring Boot 项目的主启动程序类上都使用了一个 @SpringBootApplication 注解,该注解是 Spring Boot 中最重要的注解之一 ,也是 Spring Boot 实现自动化配置的关键。
@SpringBootApplication 是一个组合元注解,其主要包含两个注解:@SpringBootConfiguration 和 @EnableAutoConfiguration,其中 @EnableAutoConfiguration 注解是 SpringBoot 自动化配置的核心所在。
3.5.1. @EnableAutoConfiguration
@EnableAutoConfiguration 注解用于开启 Spring Boot 的自动配置功能, 它使用 Spring 框架提供的 @Import 注解通过 AutoConfigurationImportSelector类(选择器)给容器中导入自动配置组件。
3.5.2. @SpringBootConfiguration
@SpringBootConfiguration继承自@Configuration,二者功能也一致,标注当前类是配置类,并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到spring容器中,并且实例名就是方法名。
3.6. @RequestBody
@RequestBody主要用来接收前端传递给后端的json字符串中的数据(请求体中的数据);而最常用的使用请求体传参的无疑是POST请求了,所以使用@RequestBody接收数据时,一般都用POST方式进行提交。
在后端的同一个接收方法里,@RequestBody与@RequestParam()可以同时使用,@RequestBody最多只能有一个,而@RequestParam()可以有多个。
3.7. @Service
对于业务层(service层)的类,在类上用 @Service 注解声明,表示是业务层组件。SpringBoot会将标注类自动注册到 Spring 容器中,可以通过指定value参数更改名称。
SpringBoot的企业级开发中经常采用Service+ServiceImpl的结构,一开始大多数项目都是直接在业务处理层的Service类中嵌入JDBC代码,这就使得这个Service类与数据库紧耦合,在换一种数据库后,就要修改Service类中的sql。于是就有了Controller+Service+ServiceImpl,Service类设计成一个接口,使控制层只依赖这个接口,这样,当某天这个应用要跑在其它数据库上时,就而只需要增加一个serviceImpl类。
3.8. @CrossOrigin
该注解用于解决跨域问题,可以有以下使用方法:
- 对@Controller中的方法使用
- 对@Controller使用
- 同时对Controller和其中的方法使用
@CrossOrigin中的2个参数:
- origins: 允许可访问的域列表
- maxAge:准备响应前的缓存持续的最大时间(以秒为单位)
除了这种细粒度的注解配置方式外,SpringBoot还提供全局配置的方式。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
//允许所有源
corsConfiguration.addAllowedOrigin("*");
//允许所有请求头
corsConfiguration.addAllowedHeader("*");
//允许所有方法
corsConfiguration.addAllowedMethod("*");
//允许跨域cookies
corsConfiguration.setAllowCredentials(true);
source.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(source);
}
}