一些常用注解
# 一些常用注解
# 启动类相关
# @SpringBootApplication
@SpringBootApplication 标注在类上,说明这是一个SpringBoot应用,且该类是启动类,是程序的入口
@SpringBootApplication
public class DiyApplication {
public static void main(String[] args) {
//Spring 应用启动起来 且返回值为 ioc容器
SpringApplication.run(DiyApplication.class, args);
// ConfigurableApplicationContext ioc = SpringApplication.run(DiyApplication.class, args);
}
}
2
3
4
5
6
7
8
9
# @ComponentScan
@ComponentScan用于类或接口上主要是指定扫描路径,spring会把指定路径下带有指定注解的类自动装配到bean容器里。会被自动装配的注解包括@Controller
、@Service
、@Component
、@Repository
等等。
使用了@Component
、@Controller
、@Service
、@Repository
、@Configuration
等注解的类会被Spring框架扫描并注册为Spring管理的bean。这些bean默认是单例(Singleton)
的,即在整个应用中只有一个实例。
# 默认单例的原因
以下是几个主要原因:
- 性能优化:创建对象实例是有开销的,包括内存分配和初始化。单例模式确保每个bean在整个应用中只有一个实例,减少了重复创建对象的开销。减少了垃圾回收的频率和压力,提高了应用的性能。
- 共享状态:单例模式确保这些状态或资源在整个应用中是唯一的,避免了多实例之间的状态不一致问题。
- 全局访问:单例对象在整个应用中是全局可见的,可以在任何地方访问。这对于需要全局共享的服务和工具类非常有用。
- 线程安全:如果bean的设计是无状态的(即不包含可变的共享状态),那么单例模式是线程安全的。这使得单例模式在多线程环境中更加可靠。
补充:
锁(如
synchronized
关键字或ReentrantLock
)的作用是确保在同一时刻只有一个线程可以执行某段代码或操作某个对象。锁的作用范围是基于对象的,也就是说,锁是针对特定对象实例的。因此,如果改成多实例,会增加对共享资源控制的难度。
因为,即使你在一个方法上加上了锁,每个实例的锁也是独立的,不会影响其他实例,可能导致重复的修改数据。锁只能保护每个实例内部的变量,而不能保护跨实例的共享资源。
如果需要保护跨实例的共享资源(多实例的情况下),我们可能要考虑使用外部锁、静态锁或线程安全的数据结构。
# 常用属性如下
- basePackages:指定扫描路径,如果为空则以@ComponentScan注解的类所在的包为基本的扫描路径。只设置该属性时,属性名可以省略
- basePackageClasses:指定具体扫描的类
- includeFilters:指定满足Filter条件的类
- excludeFilters:指定排除Filter条件的类
@ComponentScan(basePackages = "com.sugar.pro.config")
//省略写法
@ComponentScan("com.sugar.pro.config")
2
3
# 组件相关
# @Configuration
@Configuration注解用于定义配置类,该类中通常包含着用于配置Spring Bean的方法,相当于以前spring中的配置文件如:beans.xml
文件
# 配合@Bean
@Configuration
和@Bean
注解常一起使用用于创建自定义的Spring Bean(给容器注册组件),等同于@Component、@Controller、@Service等
,同时这种方式默认也是单实例
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
//以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
}
2
3
4
5
6
7
8
9
10
接下来,我们可以使用@Autowired
注解来注入这个Bean的实例对象到其他类中。例如:
@Service
public class MyController {
@Autowired
private MyService myService;
// 使用myService进行其他操作
}
2
3
4
5
6
7
8
# 扩展
@Configuration注解有个属性proxyBeanMethods
,它的作用是在配置类中定义的Bean之间是否使用代理模式。
- 当
proxyBeanMethods = false
时,Spring容器在初始化配置类中的Bean时,不会使用代理模式来创建Bean之间的依赖关系。这意味着如果一个Bean需要依赖另一个Bean,那么它将被直接注入,而不是通过代理对象进行注入。这种情况下,如果一个Bean修改了它所依赖的另一个Bean的属性或方法,那么这种修改会影响到所依赖的Bean的实例本身,可能导致不可预测的行为。 - 当
proxyBeanMethods = true
时,Spring容器会使用代理模式来创建Bean之间的依赖关系。这意味着如果一个Bean需要依赖另一个Bean,那么它将被注入一个代理对象,而不是直接注入依赖的Bean本身。这种情况下,修改所依赖的Bean的属性或方法不会影响所依赖的Bean的实例本身,从而避免了不可预测的行为。
在调用上的体现则是:
- Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的】
- Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的】
总结:
@Configuration(proxyBeanMethods = false)
表示在配置类中定义的Bean之间不使用代理模式,而是直接注入依赖的Bean本身。可能导致循环依赖。 组件依赖必须使用Full模式默认。其他默认是否Lite模式该特性是springboot2,@since 5.2版本之后才有的特性,proxyBeanMethods的默认值为true
# @ConfigurationProperties
它是Spring Boot中用于绑定配置文件属性到Java对象的注解。
使用@ConfigurationProperties注解可以将配置文件中的属性
与类中的字段
进行绑定,从而将配置属性值注入到类中,这样就可以方便地通过修改配置文件来动态地修改程序的行为。
使用@ConfigurationProperties注解时,需要在注解中指定要绑定的配置属性前缀,例如:
@Component
@ConfigurationProperties(prefix = "hello")
public class HelloProperties {
private String name;
// ...getter and setter methods
}
2
3
4
5
6
7
8
配置文件:
hello.name = cogar
// 使用 注入的方式
@Autowired
HelloProperties helloProperties;
@RequestMapping("/hello")
public HelloProperties helloDemo(){
System.out.println("logggggg");
return helloProperties;
}
2
3
4
5
6
7
8
9
注意:直接通过关键字new创建的对象是无法将绑定的值是注入到对应属性上。或者说只有在Spring容器中的组件才能使用注入等强大的功能
# 注意
使用@ConfigurationProperties注解时,需要确保将其标记的类在Spring上下文中进行扫描。否则会报错。
通常可以使用以下两种方式
- @EnableConfigurationProperties注解+ @ConfigurationProperties
- @Component注解+@ConfigurationProperties
@EnableConfigurationProperties(HelloProperties.class)
public class MyConfigAuto{
}
// 在对应的配置类上 使用该注解并设置对应class
@ConfigurationProperties(prefix = "hello")
public class MyConfig{
}
// 方式一
2
3
4
5
6
7
8
9
10
@Component
@ConfigurationProperties(prefix = "hello")
public class MyConfig{
}
// 方式二
2
3
4
5
6
# @RestControllerAdvice
@RestControllerAdvice
是 Spring 框架中的一个注解,用于定义全局异常处理和数据绑定的增强类。它是 @ControllerAdvice
和 @ResponseBody
的组合注解,专门用于处理 RESTful Web 服务中的异常和数据绑定问题。其中@ControllerAdvice
继承了@Component
,因此也可以说@RestControllerAdvice本质上是个Component.
# 3个作用
- 全局异常处理:可以定义全局的异常处理器,捕获并处理所有控制器方法中抛出的异常。
- 数据绑定增强:可以定义全局的数据绑定和验证逻辑,处理数据绑定失败的情况。
- 统一响应格式:可以定义统一的响应格式,确保所有响应都遵循相同的结构。
- 全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理自定义异常
@ExceptionHandler(CustomException.class)
public ResponseEntity<ErrorResponse> handleCustomException(CustomException ex) {
ErrorResponse errorResponse = new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
}
}
2
3
4
5
6
7
8
9
10
在该类中,可以定义多个方法,不同的方法处理不同的异常,例如专门处理空指针的方法、专门处理数组越界的方法…,也可以直接向上面代码一样,在一个方法中处理所有的异常信息。
@ExceptionHandler 注解用来指明异常的处理类型,即如果这里指定为 NullpointerException,则数组越界异常就不会进到这个方法中来。
使用
@ControllerAdvice
处理异常时,如果定义了多个方法并且这些方法都能匹配同一个异常类型,
- 系统会使用更具体的异常类型来定义处理方法
- 或者你可以使用
@Order
注解来指定处理方法的优先级。较低的数字表示更高的优先级。// 处理自定义异常 @ExceptionHandler(CustomException.class) @Order(1)
1
2
3
- 全局数据绑定
@ControllerAdvice
public class GlobalController{
// 全局数据绑定
//应用到所有@RequestMapping注解方法
//此处将键值对添加到全局,注解了@RequestMapping的方法都可以获得此键值对
@ModelAttribute
public void addUser(Model model) {
model.addAttribute("msg", "此处将键值对添加到全局,注解了@RequestMapping的方法都可以获得此键值对");
}
}
2
3
4
5
6
7
8
9
10
定义完成后,在任何一个Controller 的接口中,都可以获取到这里定义的数据:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(Model model) {
Map<String, Object> map = model.asMap();
System.out.println(map.get("msg"));
return "msg";
}
}
2
3
4
5
6
7
8
9
- 数据预处理
有两个实体类,Book 和 Author,分别定义如下:
public class Book {
private String name;
private Long price;
//getter/setter
}
public class Author {
private String name;
private Integer age;
//getter/setter
}
2
3
4
5
6
7
8
9
10
给接口取别名:
@PostMapping("/book")
public void addBook(@ModelAttribute("b") Book book, @ModelAttribute("a") Author author) {
System.out.println(book);
System.out.println(author);
}
2
3
4
5
进行预处理:
@InitBinder("b")
public void b(WebDataBinder binder) {
binder.setFieldDefaultPrefix("b.");
}
@InitBinder("a")
public void a(WebDataBinder binder) {
binder.setFieldDefaultPrefix("a.");
}
2
3
4
5
6
7
8
@InitBinder(“b”) 注解表示该方法用来处理和Book和相关的参数,在方法中,给参数添加一个 b 前缀,即请求参数要有b前缀.
当然,关于它的属性也有,比如——basePackageClasses,这里就不展开,欢迎大家自行查阅资料。
其中关于RestController中的数据预处理,用的是以下链接中的例子:
# @Autowired
作用:它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。在开发中用得最多的是在类成员变量上
关于类成员变量的自动装配,@Resource
同样可以完成。
@Service
public class TestA {
@Autowired
private Person person;
}
2
3
4
5
- @Resource默认通过byName的方式实现,如果找不到对应的名称,则通过byType实现。
- 而@Autowired则是通过byType的方式实现,并且必须要求这个对象存在。
# @Component...等
它作用是将一个普通的Java类转化为Spring的组件。通过@Component注解标记的类会被Spring框架扫描并创建实例,以便在需要的地方进行依赖注入。
类似的注解还有一些,不过它们对于所属业务层有明确定义。
- @Repository:用于标注持久层组件,也就是用于进行数据库相关操作的层
- @Service:用于标注服务层组件,主要涉及一些复杂的逻辑。
- @Controller:用于标注控制层组件,对应SpringMVC控制层,
- @RestController:也是用于标注控制层,它是@Controller和@ResponseBody的组合。
# 数据解析相关
# @RequestMapping
是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
类似的注解还有
- @GetMapping = @RequestMapping(method = RequestMethod.GET)
- @PostMapping = @RequestMapping(method = RequestMethod.POST)
- @DeleteMapping = @RequestMapping(method = HttpMethod.DELETE)
- @PutMapping = @RequestMapping(method = HttpMethod.PUT)
# @RequestParam
用于获取请求中的参数值。认情况下,@RequestParam会根据参数的名称来匹配请求中的参数名。例如,如果方法参数为String name,则会尝试从请求中找到名为 "name" 的参数值。
@RequestParam:它用于url查询字符串、form-data、和 x-www-form-urlencoded参数格式解析。 但是它不能用于获取文件上传参数、大量参数或跨域请求中的参数。
支持的类型:url,支持数据类型:GET或POST,支持的Content-Type:所有
@RequestParam只能处理字符串类型的参数
该注解有三个属性:
- value:value用来指定要传入值的名称
- required:required用来指示参数是否必须含有;
- defaultValue:指定参数的默认值。如果这个参数不存在,或者如果它的值为空,或者如果它的值不是有效的类型,将会使用这个默认值。
@GetMapping("/users/{id}")
public User getUser(@PathVariable("id") Long id,
@RequestParam(value = "status", required = false, defaultValue = "active") String status) {
return userService.getUserById(id, status);
}
2
3
4
5
注意:如果前端传来的参数为Content-type: application/json,则使用@RequestParam无法获取,会报如下错误。 required string parameter ‘XXX‘is not present
# @RequestBody
它用于从请求的请求体中获取数据,用于application/json 参数格式解析。
支持的类型:Body,支持的请求类型:POST/PUT/DELETE/PATCH,支持的Content-Type:json
@PostMapping("/users")
public User createUser(@RequestBody User user) {
return userService.createUser(user);
}
2
3
4
上述例子中@RequestBody
用于从请求体中获取User
对象。
postman中常见的数据请求格式:
- multipart/form-data:可以上传文件或者键值对,最后都会转化为一条消息
- x-www-form-urlencoded:只能上传键值对,而且键值对都是通过&间隔分开的
- raw:对应的是入参是任意格式的可以上传任意格式的【文本】,可以上传text、json、xml、html等
- binary:相当于Content-Type:application/octet-stream,只可以上传二进制数据,通常用来上传文件,但是一次只能上传一个文件
# @PathVariable
它用于从请求的URL路径中获取数据。它用于处理URL路径中的参数。
支持的类型:url,支持的请求类型:Get,支持的Content-Type:所有
@GetMapping("/user/{id}")
public String getUser(@PathVariable("id") Integer id, @RequestParam("name") String name) {
// 处理获取用户信息请求
return "user " + id + " name " + name;
}
2
3
4
5
在这个例子中,@PathVariable("id")
用于从URL路径/users/{id}
中的{id}
部分获取值。
# @ResponseBody
作用:返回结果不会被解析为跳转路径,而是直接写入HTTP response body中。通常用来返回JSON数据或者是XML数据。
如果没有使用 @ResponseBody
注解,Spring 会将控制器方法的返回值解析为视图名称,而不是直接写入 HTTP 响应体。这意味着返回值将被视为一个视图名称,Spring 会根据这个视图名称找到对应的视图(如 JSP、Thymeleaf 模板等)并渲染视图,然后将渲染结果写入 HTTP 响应体中。
- 当前端以application/x-www-form-urlencoded格式上传数据时,后台可以使用@RequestParam或者不使用任何注解来获取参数。 后台不可以使用@RquestBody来获取参数,使用的话会报错误。
- 当前端以application/json格式上传即使用JSON字符串,后台使用@RequestParam是无法一一对应来获取参数的。当前端使用application/json来传递数据的时候,后端只能使用 @RequestBody 以及 Java bean或者 map 的方式来接收数据。
# 扩展
# lombok的使用
Lombok 是一个 Java 库,它通过注解来简化 Java 代码的编写,特别是减少样板代码(boilerplate code)。使用 Lombok 可以让你的代码更加简洁和易读。比如:通过在类上加@Data
可以替代Getter、Setter方法,以下是如何在项目中使用 Lombok 的步骤和常见注解的示例。
- 首先你需要添加依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version> <!-- 请使用最新版本 -->
<scope>provided</scope>
</dependency>
2
3
4
5
6
在 Maven 项目中,
<scope>provided</scope>
是一个依赖范围(Dependency Scope),用于指定依赖项在编译时需要,但在运行时由容器或 JDK 提供。这意味着这些依赖项不会被打包到最终的 JAR 或 WAR 文件中。
- 为了在 IDE 中支持 Lombok,你需要安装 Lombok 插件。以下是常见 IDE 的安装方法:
这里以 IntelliJ IDEA为例:
- 打开 IntelliJ IDEA。
- 进入
File
->Settings
(或Preferences
在 macOS 上)。 - 导航到
Plugins
。 - 搜索
Lombok
并安装插件。 - 重启 IntelliJ IDEA。
到此,引入步骤完成,现在你就可以使用lombok提供的注解了。
以下是一些常用注解的示例:
# @Data
@Data
注解是一个全能注解,它包含了 @ToString
、@EqualsAndHashCode
、@Getter
、@Setter
和 @RequiredArgsConstructor
的功能。
# @Getter 和 @Setter
@Getter
和 @Setter
注解分别用于生成 getter 和 setter 方法。
# @AllArgsConstructor 和 @NoArgsConstructor
@AllArgsConstructor
注解用于生成包含所有字段的构造函数,@NoArgsConstructor
注解用于生成无参构造函数。
# @ToString
@ToString
注解用于生成 toString
方法。
# @EqualsAndHashCode
@EqualsAndHashCode
注解用于生成 equals
和 hashCode
方法。
# @Accessors(chain = true) 注解解释
如果你希望在调用 setter 时能够链式地继续调用其他 setter 或者其他方法,你可以使用 @Accessors(chain = true) 注解。这将使得 setter 返回 this 对象本身,从而支持链式调用。
例如:
import lombok.Accessors;
@Accessors(chain = true)
public class User {
private String name;
public String getName() { return this.name; }
public User setName(String name) { this.name = name; return this; } // 注意返回类型和 return 语句
}
2
3
4
5
6
7
8
9
现在赋值就可以变为这样:
User user = new User()
.setName("John")
.setSomeOtherProperty("value");
2
3