目录
17.在Spring MVC框架中,向客户端响应JSON格式的数据
1.pom文件详解
<?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.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- Generated by https://start.springboot.io -->
<!-- 优质的 spring/boot/data/security/cloud 框架中文文档尽在 => https://springdoc.cn -->
<!--当前项目的信息-->
<groupId>cn.tedu</groupId>
<artifactId>csmall-product</artifactId>
<!--版本可自由设定-->
<version>0.0.1</version>
<!--当前项目的属性配置-->
<properties>
<java.version>1.8</java.version>
</properties>
<!--当前项目使用的依赖项-->
<dependencies>
<!--lombok依赖项用于实体类的相关操作,简化代码-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<!--scope标签是配置依赖项的作用域-->
<scope>provided</scope>
</dependency>
<!--mybatis整合springboot依赖项-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<!--mysql依赖项-->
<!--当添加了数据库编程依赖项,无论是启用还是测试都会尝试链接数据库,读取配置信息,所以同时必须在配置文件中添加数据库配置信息-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--springboot基础依赖项-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--springboot测试依赖项-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
2.mysql对应java数据类型
tinyint / smallint / int | Integer |
bigint | Long |
varchar / char / text 系列 | String |
decimal | BigDecimal |
datetime | LocalDateTime |
3.yml
文件
YAML是一种编写配置文件的语法,表现为以.yml
作为扩展名的文件。
相比.properties
文件,其语法的改变有:
- 原属性名中有小数点的部分,改为使用冒号+换行后空2格
- 原属性名与属性值使用等于号分隔,改为使用冒号+1个空格
- 如果多个配置中,属性名有相同的部分,则不必配置相同的部分,保持对应的空格(缩进)即可
4.关于Profile配置
application.properties
是主配置文件,其中的所有配置都是默认加载的- 以
application-自定义名称.properties
作为文件名的全部是Profile配置,默认是不加载的,必须激活这些文件中的配置才会被加载 - 在
application.properties
(主配置文件)中,使用spring.profiles.active
属性,可以激活Profile配置,此属性的值就是Profile配置的文件名的自定义部分,如果有多个Profile配置需要激活,使用逗号分隔即可 - 如果在
application.properties
(主配置文件)中,与在Profile配置中,存在完全相同的属性的配置,则以Profile配置为准
5.关于Spring Boot的配置文件
在Spring Boot项目中,在src/main/resources
文件夹下存在application.properties
文件,此文件是Spring Boot会自动读取的配置文件。
Spring Boot定义了许多特定用途的配置,在application.properties
中,需要按照特定的属性名进行配置,则Spring Boot读取到了这些特定的配置后,会自动应用起来!
例如,添加连接数据库的配置:
spring.datasource.url=jdbc:mysql://localhost:3306/mall_pms?characterEncoding=utf-8&useUnicode=true&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
spring.profiles.active=dev
mybatis.mapper-locations=classpath:mapper/*.xml
6.添加与Mybatis相关的配置
在每个项目中,当需要使用Mybatis实现数据库编程时,都需要添加2项一次性配置:配置Mapper接口所在的包(package
)、配置XML文件在哪里。
关于配置Mapper接口所在的包,可以(以下做法二选一即可):
- 【推荐】在配置类上使用
@MapperScan
注解,并指定注解的参数,此参数值就是包名 - 在每个Mapper接口上添加
@Mapper
注解
则在项目的根包下创建config.MybatisConfiguration
类,在此类上添加@Configuration
注解,则可以将此类标记为“配置类”,然后,再添加@MapperScan
注解来指定Mapper接口所在的包:
package cn.tedu.csmall.product.config;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("cn.tedu.csmall.product.mapper")
public class MybatisConfiguration {
}
另外,关于“配置XML文件在哪里”,需要通过配置文件(application.properties
/ application.yml
/ 相关Profile文件)中的mybatis.mapper-locations
进行配置。由于此项配置的值,不会因为切换开发环境、测试环境等环境而变化,也不会因为使用不同的电脑来开发而变化,所以,应该将其配置在主配置文件中!
先在src/main/resources
下创建mapper
文件夹,此文件夹将用于存放配置SQL语句的XML文件。
在application.yml
中添加配置:
mybatis:
mapper-locations: classpath:mapper/*.xml
classpath是指main包下的两个文件夹,只是放的文件意义不一样,编译打包都是在一个文件夹下
7.使用Mybatis访问数据
首先,需要创建接口,通常每张数据表都有一个对应的Mapper接口,并在接口中声明抽象方法
抽象方法的声明:
返回值类型:如果要执行的数据访问操作是增、删、改类型的,始终使用int
作为返回值类型,表示“受影响的行数”,如果要执行数据访问操作是查询类型的,只需要保证返回值类型能够“放得下”查询结果即可
方法名称:自定义,建议不要重载,《阿里巴巴Java开发手册》提供的参考:
1) 获取单个对象的方法用 get 做前缀。
2) 获取多个对象的方法用 list 做前缀。
3) 获取统计值的方法用 count 做前缀。
4) 插入的方法用 save/insert 做前缀。
5) 删除的方法用 remove/delete 做前缀。
6) 修改的方法用 update 做前缀。
然后,需要准备好XML文件,在XML文件中配置抽象方法映射的SQL语句。
XML文件的内部详解:
-
根标签必须是
<mapper>
,且此标签必须配置namespace
属性,取值为对应的接口的全限定名(包名加类名) -
在根标签的子级,可以使用
<insert>
/<delete>
/<update>
/<select>
这些标签来配置增、删、改、查对应的SQL语句,这些标签都必须配置id
属性,取值为对应的抽象方法的名称- 其实,
<update>
和<delete>
这2个标签可以随意调换使用,例如,配置DELETE
语句可以使用<update>
标签,甚至,在不考虑获取自动编号的ID时,<insert>
标签和<update>
、<delete>
也可以随意调用使用,因为这3种数据访问操作在JDBC的底层实现是一样的,当然,这种乱用的方式肯定是非常不建议的
- 其实,
-
在
<insert>
这4种标签的子级,编写SQL语句,参数部分使用#{名称}
格式的占位符来表示,其中,占位符中的“名称”应该是参数名称,或封装类型中的属性名 -
严格说来,在
#{}
格式的占位符中的名称,将被用于生成Setter & Getter的名称,然后,Mybatis框架会自动调用实体类的get和set方法,#{}里面的是属性,会被拼上get+属性名,
属性名首字母大写 -
如果配置的是
<insert>
标签,并且,插入数据的表的主键是自动编号的,应该在此标签上配置useGeneratedKeys="true"
和keyProperty="主键属性"
这2个属性,以获取自动编号的ID值,创建的实体的参数id插入前和插入后是不一样的,插入前是null,插入后是自动编号的id,本质是通过set方法,设置值 -
如果涉及批量操作,需要通过
<foreach>
标签来遍历参数对象,关于此标签的使用:collection
属性:表示被遍历的对象,当抽象方法的参数只有1个,且没有添加@Param
注解时,如果参数是数组或可变参数,则此属性的值为array
,如果参数是List
集合,则此属性的值为list
;当抽象方法的参数超过1个,需要添加@Param
注解,则此属性的值为注解的配置值item
属性:表示遍历过程中各元素的名称,是自定义名称,并且,在<foreach>
子级的#{}
占位符中,也使用此名称表示被遍历到的元素separator
属性:表示遍历过程中各值之间的分隔符号<foreach>
标签是Mybatis的“动态SQL”标签之一
-
关于动态SQL的
<if>
标签,可以对参数进行判断,从而确定SQL语句中应该包含或不包含哪些片段-
需要注意,没有所谓的
else
标签,如果一定要实现类似Java中if...else...
的效果,可以使用2个条件完全相反的<if>
标签(虽然执行效率会差一些),或者,使用<choose>
系列标签,语法格式如下:<choose> <when test="条件"> 满足条件时的SQL片段 </when> <otherwise> 不满足条件时的SQL片段 </otherwise> </choose>
-
-
如果涉及修改数据的操作,当使用了
<if>
实现动态SQL时,通常,应该使用<set>
标签将更新列表框住,并且,SQL语句中不需要写SET
关键字 -
如果配置的是
<select>
标签,此标签必须配置resultType
或resultMap
这2个属性中的某1个- 当
resultType
的值是基本数据类型时,直接使用类型名称作为此属性值即可,例如resultType="int"
- 当
resultType
的值是引用数据类型时,需要使用类型的全限定名作为此属性值,例如resultType="cn.tedu.xxx.User"
,但是,如果类型是java.lang
包下的,则可以不写包名,例如resultType="Integer"
- 当
-
在编写查询的SQL语句时,可以使用
<sql>
标签封装查询的字段列表,并使用<include>
标签来引用封装的查询字段列表- 由于IntelliJ IDEA会检查每个标签的子级内容的语法,所以,在
<sql>
标签下直接写字段列表,IntelliJ IDEA会提示错误,但是并不影响运行,可以使用<if test="true">
将字段列表框住,以“欺骗”IntelliJ IDEA使之不报错 - 通常,在
<include>
标签的子级并不编写任何代码,所以,此标签推荐使用单标签格式
- 由于IntelliJ IDEA会检查每个标签的子级内容的语法,所以,在
-
建议为所有的“非统计查询”配置
<resultMap>
8.编写SQL语句时的代码提示
在设置中,指定SQL Dialects配置,如果完成配置后,在XML文件中编写SQL语句仍没有提示,可以尝试删除并重新配置Database面板,或将方言在MariaDB和MySQL之间切换。
9.使用测试检验开发的数据访问功能
在Spring Boot项目中,所有的测试类都应该创建在src/test/java
下的根包
当需要执行的测试是基于加载整个项目环境的(例如需要读取配置文件、需要使用@Autowired
自动装配等),测试类必须添加@SpringBootTest
注解。方法上添加@test
如果@Autowired
自动装配爆红,可能是idea软件的问题,也有可能是mapper接口上没有添加@Repository注解,也可以不处理,不推荐使用required = false
10.关于SLF4j日志
在开发实践中,通常是禁止使用System.out.println()
这种语句输出信息的
在Spring Boot项目中,基础依赖项(spring-boot-starter
)中已经包含了日志相关的依赖项,可以直接使用日志框架来输出信息!
在添加了Lombok后,在任何类的声明之前,添加@Slf4j
注解,则编译期会自动声明一个名为log
的变量,所以,可以在类中通过此变量来输出日志。
如果没有使用Lombok,可以自行声明日志变量,例如:
private static Logger logger = LoggerFactory.getLogger(Slf4jTests.class);
在日志框架中,根据日志信息的重要程度,划分了几个等级
trace
:跟踪信息debug
:调试信息info
:一般信息warn
:警告信息error
:错误信息
在没有加载Spring Boot的情况下,日志的默认显示级别是debug
,只会显示此级别及更加重要的级别的日志,如果加载了Spring Boot(例如在测试类上添加了@SpringBootTest
注解),日志的默认显示级别是info
可以在配置文件(application.properties
/ application.yml
/ 相关Profile配置)中配置logging.level.包名
属性,以指定某个包下的所有类的默认日志显示级别,此属性的值为5个级别中的某1个
配置包名时,不必把包名配置得特别具体,可以作用于其子孙包下所有的类,但是,必须至少配置1级包名,例如配置到cn
这一级包,不可以完全不配置包名
log.info("x = {}, y = {}, x + y = {}", x , y , x + y); // 使用日志输出变量的做法
SLF4j其实是一种日志框架的标准,并没有具体实现日志的输出功能,通常,是使用log4j
或logback
这些日志框架来实现具体功能的!
11.关于Service
在《阿里巴巴Java手册》中的强制规约:
强制】对于 Service 和 DAO 类,基于 SOA 的理念,暴露出来的服务一定是接口,内部
的实现类用 Impl 的后缀与接口区别。
正例:CacheServiceImpl 实现 CacheService 接口
12.关于抛出异常
当使用抛出异常的方式表示“操作失败”时,不可以使用任何已有的异常(JDK中原生的异常类型,及添加的依赖项中包含的异常类型),必须自定义异常,则后续捕获并处理时,一定符合抛出异常时的情景。
定义异常必须继承自某个已存在的异常类型,强烈建议继承自RuntimeException
,其原因有:
- 原因1:在项目中将使用全局异常处理器统一处理异常,要想统一处理,则Service组件、Controller组件都必须抛出异常,才能由Spring MVC框架捕获到异常,进而通过全局异常处理器进行统一的处理!
RuntimeException
不会受到异常的相关语句约束,而非RuntimeException
一旦被抛出,方法的声明、方法的调用者的声明等都需要声明抛出此异常,由于抛出异常是固定的做法,没有必要在各个方法上都声明抛出此异常,所以,应该使用RuntimeException
- 原因2:配合Spring JDBC框架实现事务管理!
13. 添加Web开发的依赖项
在现有的项目中,只需要将spring-boot-starter
改为spring-boot-starter-web
,此依赖项中包含了spring-boot-starter
这个基础依赖项
当添加了以上依赖项,你的项目会有以下明显的变化:
- 启用项目时,会自动启用Tomcat(你的项目也会部署到这个Tomcat上),默认占用
8080
端口 - 在
src/main/resources
下的static
文件夹会是默认的静态资源文件夹,在此文件夹下的资源(例如网页、图片等)可以直接通过HTTP协议的URL直接访问- 如果创建项目时勾选了
Web
依赖项,会自动创建此文件夹,如果创建项目时未勾选Web
依赖项,而是手动添加spring-boot-starter-web
,不会自动创建此文件夹,但可以手动创建,是等效的
- 如果创建项目时勾选了
在配置文件中,可以通过server.port
属性指定Tomcat占用的端口号,默认8080,端口号的最大值是65535
14.
控制器
在类上添加@RestController
注解,在类中自动装配Service
的对象,并且,自定义方法处理请求
调用顺序controller>service>mapper
开发顺序mapper>service>controller
在方法上添加@RequestMapping,
在Spring MVC框架中,@RequestMapping
注解的主要作用是配置“请求路径”与“处理请求的方法”的映射关系
在@RequestMapping
的源代码中,可以看到它的声明
在配置路径时,Spring MVC会自动处理必要的/
(如果缺少,则添加,如果多余,则去除)
Spring MVC框架还提供了基于@RequestMapping
的衍生注解,@GetMapping、@PostMapping等
15.关于Knife4j框架
Knife4j是一款在线API文档框架,可以基于当前项目的控制器类中的配置生成文档,并自带调试功能
- 添加依赖
- **注意:**本次使用的Knife4j的版本,要求项目中的Spring Boot版本必须是2.6以下版本(不包含2.6)
- 在主配置文件(
application.properties
/application.yml
)中开启增强模式- 配置
knife4j.enable
属性,取值为true
- 配置
- 添加配置类
- 是相对固定的代码,复制粘贴即可
- **注意:**需要检查配置类中所配置的包名,必须是当前项目中控制器类所在的包
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.9</version>
</dependency>
完成后,启用项目,通过 doc.html 即可访问在线API文档,即:http://localhost:8080/doc.html
前提是在类、方法、POJO类型的属性、请求参数上添加注解,才会有效果
16.处理请求的方法的返回值
在前后端分离的做法中,服务器端是不处理视图的,而是将处理请求后得到的数据响应到客户端,由客户端决定如何处理此数据
使用@ResponseBody
注解,方法的返回值会直接响应到客户端去!
@ResponseBody
注解添加在控制器类上,则当前控制器类中所有处理请求的方法都是响应正文的
而@Controller
注解的类会被作为控制器类,两个注解也可以改为使用@RestController
17.
在Spring MVC框架中,向客户端响应JSON格式的数据
处理请求的方法必须是响应正文的
开启注解驱动
- 如果是使用XML配置的Spring MVC项目,需要在XML配置文件中添加
<annotation-driven/>
- 如果是使用注解配置的Spring MVC项目,需要在配置类上添加
@EnableWebMvc
- 如果是Spring Boot项目,不需要添加任何配置
添加jackson-databind
依赖项
-
在
spring-boot-starter-web
依赖项中包含此依赖项
使用自定义的数据类型作为处理请求的方法的返回值类型
18.Spring MVC的统一处理异常机制
类上添加@RestControllerAdvice注解,将可以作用于整个项目中任何处理请求的过程中,方法上添加@ExceptionHandler
在Spring MVC框架中,处理请求的方法都是被框架所调用的,所以,处理请求的方法抛出的异常也都会被框架捕获到,则框架会自动的使用此异常对象来调用处理异常的方法!
这样就不用try..catch...
捕获异常了。
19.响应结果中的null值
null
值的属性响应到客户端去是没有任何意义的
属性上配置@JsonInclude
注解,也可以将此注解添加在类上,则类中每个属性都是此配置,还可以在配置文件中通过spring.jackson.default-property-inclusion
属性进行作用于整个项目的全局配置
20.请求头的设计,RESTFUL风格
类上添加@RequestMapping("/xxx"),方法上@PostMapping("/{id}/delete"),方法的参数上添加@PathVariable
@PostMapping("/{id}/delete")
public ??? delete(@PathVariable Long id) {
// 暂不关心方法的实现
}
@PostMapping("/{id}/delete")
public ??? delete(@PathVariable("id") Long albumId) {
// 暂不关心方法的实现
}
可以在占位符名称的右侧、在右大括号的左侧添加1个冒号,并在冒号的右侧可以添加正则表达式,以限制参数值的基本格式@PostMapping("/{id:[0-9]+}/delete")
客户端提交的请求路径中,占位符位置的内容无法被转换成Long
类型时,将出现400
错误
占位符位置的内容不匹配以上正则表达式时,将出现404
错误。
21.检查请求参数
Spring Validation框架是用于检查请求参数的基本格式的框架
1.添加spring-boot-starter-validation
依赖项
2.在处理请求的方法的被检查参数上添加@Valid
或@Validated
注解,表示需要对此参数进行检查
3.在POJO类的属性上添加注解,例如@NotNull
注解,@NotNull
上可以配置message
属性,用于配置“检查不通过时的提示文本”
如果检查不通过,会出现BindException,包含全部错误信息。可以在全局异常处理器中配置,提示全部文本,或者提示某一个,可以在配置类添加快速失败机制,检查到一个错误马上返回
对于检查未封装的请求参数,与上面不同
类上添加@Validated
注解,检查的参数上添加检查注解
@PostMapping("/{id:[0-9]+}/delete")
public String delete(@Range(min = 1, max = 10000) @PathVariable Long id) {
// 暂不关心方法的具体实现
}
这种检查抛出的异常类型是ConstraintViolationException,也可以在全局异常处理中配置
使用Validation框架检查数据的基本格式时,常用的检查注解有:
@NotNull
:不允许为null
值,即客户端必须提交此参数,可用于任何类型的参数@NotEmpty
:不允许为空字符串,即不允许是长度为0的字符串,仅用于字符串类型的参数@NotBlank
:不允许为空白的字符串,即不允许仅由空格、TAB制表位、换行等空白组成的字符串,仅用于字符串类型的参数@Length
:限制字符串的长度,也可以用于检查集合等数据的长度,但不常见,通常仅用于字符串类型的参数@Pattern
:通过正则表达式检查字符串的格式,此注解的regexp
属性是定义正则表达式的属性- 仅用于字符串类型的参数
@Min
:限制最小值,仅用于整型数值类型的参数@Max
:限制最大值@Range
:限制取值区间,默认最小值为0
,最大值是long
类型的上限值,仅用于整型数值类型的参数
检查请求参数的原则,服务器端对客户端提交的请求参数的值应该保持“不信任”的态度,而且客户端仍有必要对即将提交的请求参数进行检查
22.处理跨域访问的错误
当客户端向服务器端提交跨域(提交请求的、被请求的,不在同一台服务器,或不是同一个服务器同一端口)**的异步请求时,默认情况下,服务器端都是不支持的,所以,在客户端的浏览器的控制台会提示错误
要解决这个问题,服务器端必须允许跨域访问!
在基于Spring MVC的项目中,需要自定义配置类,实现WebMvcConfigurer
接口,重写其中的addCorsMappings()
方法,在其中配置允许跨域的访问。
@Slf4j
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedHeaders("*")
.allowedMethods("*")
.allowCredentials(true)
.maxAge(3600);
}
}
23.如何接受客户端参数,@RequestBody
当客户端提交请求时,使用整个对象(this.ruleForm
)作为请求参数,如果服务器端处理请求的方法的参数之前没有使用@RequestBody
,将接收不到客户端提交的请求参数,即:对于服务器端而言,各请求参数均是null
值!
当请求参数上添加了@RequestBody
后,在Knife4j的API文档中,调试界面将不再提供各请求参数的输入框,而是需要自行组织JSON格式的请求参数进行调试!
当服务器端没有在请求参数之前添加@RequestBody
时,客户端提交的请求参数必须是FormData格式的,例如:
let fromData = 'name=' + this.ruleForm.name
+ '&description=' + this.ruleForm.description
+ '&sort=' + this.ruleForm.sort;
总结:要么在参数前添加注解,要么把请求参数转化为FromData格式
24.Spring JDBC框架的事务管理
事务(Transaction):是数据库(例如MySQL等)中的能够保障若干个写操作(增、删、改)要么全部成功,要么全部失败的机制
使用@Transcational
注解,即可使得对应的方法是“事务性”的。
25.Spring框架
Spring框架主要解决了创建对象、管理对象的相关问题。
所有由Spring框架创建的对象,会被Spring框架保存在ApplicationContext
(应用程序上下文)中,后续,当需要这些对象时,Spring会自动从ApplicationContext
中取出并使用。
由于Spring的ApplicationContext
中会保存若干个对象,所以通常也称之为“Spring容器”。
Spring框架的核心包括:
- IoC = Inversion of Controller,即控制反转
- AOP 面向切面编程
在Spring Boot项目中,启动类上添加了@SpringBootApplication
注解,此注解使用了@ComponentScan
作为其元注解。
使用@ComponentScan
注解,即可实现:当加载此配置类时,Spring框架会执行组件扫描,扫描特定的包及其子级包下是否存在组件类,如果找到组件类,则Spring框架会自动创建此组件类的对象。
如果使用@ComponentScan
时,没有配置注解参数,扫描的根包就是当前配置类所在的包;使用@ComponentScan
注解时,还可以配置此注解的basePackages
/ value
属性来指定需要扫描的若干个包。
如果被扫描的类添加了组件相关注解,此类就会被视为“组件类”,在Spring框架中,组件注解有:
@Component
:通用注解@Controller
:添加在控制器类上@Service
:添加在业务实现类上@Repository
:添加在存取数据的类(例如对数据库做增删改查的类)上
在Spring中,还有一个非常特殊的组件注解:
@Configuration
在Spring MVC中,还新定义了注解用于标识组件类,这些新的注解都是基于@Component
注解:
@RestController
@ControllerAdvice
@RestControllerAdvice
在配置类中,可以自定义方法,返回特定类型的对象,并在此方法上添加@Bean
注解,则Spring框架加载此配置类时,会自动调用这些方法,从而得到方法返回的对象。
关于用法的选取
如果需要Spring创建的是自定义类的对象,推荐优先选取“组件扫描”的做法。
如果需要Spring创建的不是自定义类的对象,则无法选取“组件扫描”的做法,因为你无法在别人写的类上添加组件注解,只能使用“@Bean方法”的做法。
关于Spring Bean的名称
由Spring框架创建的对象均可称之为Spring Bean。每个Spring Bean都有名称。
如果使用组件扫描创建的对象,Spring Bean的名称:默认情况下,当类名的第1个字母是大写的,且第2个字母是小写的,则Spring Bean的名称就是将类名的首字母改为小写,例如CategoryServiceImpl
类的Spring Bean名称就是categoryServiceImpl
,如果不满足以上条件,则Spring Bean名称就是类名。如果需要自定义为其它名称,可以配置组件注解的参数,例如@Service("categoryService")
。
如果使用@Bean
方法创建的对象,Spring Bean的名称默认是方法名称,也可以配置@Bean
注解的参数,例如@Bean("categoryService")
。
Spring框架创建的对象的作用域
由Spring框架创建的对象,默认是“单例”的。
但Spring框架并不是使用了单例模式,只是它管理的对象具有与单例模式的特点。
可以通过@Scope
注解修改Spring管理的对象的作用域,在此注解中配置参数值为"prototype"
时,对象将不再是单例的,与普通的局部变量的作用域相同,当此注解的参数值是"singleton"
时,对象是单例的,由于单例是默认的状态,所以,通常不会使用到此值。
如果是通过组件扫描的方法来创建对象,则在类的声明上使用@Scope
注解
如果是通过@Bean
方法来创建对象,则在方法的声明上使用@Scope
注解
由Spring框架创建的对象,如果是“单例”的,默认是“饿汉式”的。
如果希望被创建的单例对象是“懒汉式”的,可以通过@Lazy
注解进行配置。与@Scope
注解的使用方式相同,如果是通过组件扫描创建的对象,可以在类上添加此注解,如果是通过@Bean
方法创建的对象,可以在方法上添加此注解。
26.自动装配
Spring的自动装配机制表现为:当特定的量(类的属性,或被Spring自动调用的方法的参数)需要值时,使用待定的做法,可以使得Spring使用容器中的对象为这些量自动赋值。
最常见的用法是在类的属性上使用@Autowired
注解
关于@Autowired
与@Resource
的区别:
@Resource
是Java注解(是javax.annotation
包中的),@Autowired
是Spring框架的注解@Resource
注解是优先按照名称进行匹配,再检查类型是否相同,@Autowired
是先根据类型查找匹配的对象,如果超过1个,再尝试根据名称进行匹配- 提示:如果有且仅有1个类型匹配的Spring Bean,这2个注解都可以成功装配,如果匹配类型的Spring Bean超过1个,只要其中1个能匹配名称,这2个注解都可以成功装配,如果都不匹配名称,这2个注解都无法成功装配
Spring在处理自动装配时,有多种装配机制:
-
属性注入
-
Setter注入
-
构造方法注入
通过构造方法注入时:
- 如果类中仅有1个构造方法,不必添加
@Autowired
注解 - 如果类中有多个构造方法,默认情况下,Spring会自动尝试调用无参数构造方法(如果存在的话)
- 如果类中有多个构造方法,希望Spring调用特定的某个构造方法,需要在此构造方法上添加
@Autowired
注解
在使用@Autowired
时,如果存在多个匹配类型的Spring Bean,还可以使用@Qualifier
注解来指定装配的Spring Bean的名称