原文:SpringBoot 注解最全详解,建议收藏! (qq.com)

SpringMVC 相关

@Controller

通常用于修饰controller层的组件,由控制器负责将用户发来的URL请求转发到对应的服务接口,通常还需要配合注解@RequestMapping使用。

@RequestMapping

提供路由信息,负责URLController中具体函数的映射,当用于方法上时,可以指定请求协议,比如GETPOSTPUTDELETE等等。

@RequestBody

表示请求体的Content-Type必须为application/json格式的数据,接收到数据之后会自动将数据绑定到Java对象上去

@ResponseBody

表示该方法的返回结果直接写入HTTP response body中,返回数据的格式为application/json

比如,请求参数为json格式,返回参数也为json格式,示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 登录服务
*/
@Controller
@RequestMapping("api")
public class LoginController {

/**
* 登录请求,post请求协议,请求参数数据格式为json
* @param request
*/
@RequestMapping(value = "login", method = RequestMethod.POST)
@ResponseBody
public ResponseEntity login(@RequestBody UserLoginDTO request){
//...业务处理
return new ResponseEntity(HttpStatus.OK);
}
}

@RestController

@Controller一样,用于标注控制层组件,不同的地方在于:它是@ResponseBody@Controller的合集,也就是说,在当@RestController用在类上时,表示当前类里面所有对外暴露的接口方法,返回数据的格式都为application/json,示范代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
@RequestMapping("api")
public class LoginController {

/**
* 登录请求,post请求协议,请求参数数据格式为json
* @param request
*/
@RequestMapping(value = "login", method = RequestMethod.POST)
public ResponseEntity login(@RequestBody UserLoginDTO request){
//...业务处理
return new ResponseEntity(HttpStatus.OK);
}
}

@RequestParam

用于接收请求参数为表单类型的数据,通常用在方法的参数前面,示范代码如下:

1
2
3
4
5
6
7
8
9
10
/**
* 登录请求,post请求协议,请求参数数据格式为表单
*/
@RequestMapping(value = "login", method = RequestMethod.POST)
@ResponseBody
public ResponseEntity login(@RequestParam(value = "userName",required = true) String userName,
@RequestParam(value = "userPwd",required = true) String userPwd){
//...业务处理
return new ResponseEntity(HttpStatus.OK);
}

@PathVariable

用于获取请求路径中的参数,通常用于restful风格的api上,示范代码如下:

1
2
3
4
5
6
7
8
9
10
/**
* restful风格的参数请求
* @param id
*/
@RequestMapping(value = "queryProduct/{id}", method = RequestMethod.POST)
@ResponseBody
public ResponseEntity queryProduct(@PathVariable("id") String id){
//...业务处理
return new ResponseEntity(HttpStatus.OK);
}

@GetMapping

除了@RequestMapping可以指定请求方式之外,还有一些其他的注解,可以用于标注接口路径请求,比如GetMapping用在方法上时,表示只支持get请求方法,等价于@RequestMapping(value="/get",method=RequestMethod.GET)

1
2
3
4
@GetMapping("get")
public ResponseEntity get(){
return new ResponseEntity(HttpStatus.OK);
}

@PostMapping

用在方法上,表示只支持post方式的请求。

1
2
3
4
@PostMapping("post")
public ResponseEntity post(){
return new ResponseEntity(HttpStatus.OK);
}

@PutMapping

用在方法上,表示只支持put方式的请求,通常表示更新某些资源的意思

1
2
3
4
@PutMapping("put")
public ResponseEntity put(){
return new ResponseEntity(HttpStatus.OK);
}

@DeleteMapping

用在方法上,表示只支持delete方式的请求,通常表示删除某些资源的意思

1
2
3
4
@DeleteMapping("delete")
public ResponseEntity delete(){
return new ResponseEntity(HttpStatus.OK);
}

Bean 相关

@Primary

当一个接口有多个实现时,我们可以通过@Autowired注解搭配@Qualifier来注入我们想要的Bean。这里还有另一种情况:Bean之前分优先级顺序,一般情况下我们只会注入默认实现;这个时候可以采用@Primary注解,该注解标注于Bean上,指示了优先注入的类

1
2
3
4
5
@Primary
@Component
public class MyBean implements xxx {
//...
}

@Service

通常用于修饰service层的组件,声明一个对象,会将类对象实例化并注入到bean容器里面

1
2
3
4
5
@Service
public class DeptService {

//具体的方法
}

@Component

泛指组件,当组件不好归类的时候,可以使用这个注解进行标注,功能类似于于@Service

1
2
3
4
5
@Component
public class DeptService {

//具体的方法
}

@Repository

通常用于修饰dao层的组件,

@Repository注解属于Spring里面最先引入的一批注解,它用于将数据访问层 (DAO层 ) 的类标识为Spring Bean,具体只需将该注解标注在 DAO类上即可,示例代码如下:

1
2
3
4
@Repository
public interface RoleRepository extends JpaRepository<Role,Long> {
//具体的方法
}

为什么现在使用的很少呢?

主要是因为当我们配置服务启动自动扫描dao层包时,Spring会自动帮我们创建一个实现类,然后注入到bean容器里面。当某些类无法被扫描到时,我们可以显式的在数据持久类上标注@Repository注解,Spring会自动帮我们声明对象。

@Bean

相当于 xml 中配置 Bean,意思是产生一个 bean 对象,并交给spring管理,示例代码如下:

1
2
3
4
5
6
7
8
9
@Configuration
public class AppConfig {

//相当于 xml 中配置 Bean
@Bean
public Uploader initFileUploader() {
return new FileUploader();
}
}

@Bean 执行顺序先于 @Value

@Bean和@Value出现在同一个类中时,@Bean会比@Value先执行,这会导致当@Bean注解的方法中用到@Value注解的成员变量时,变量为null或为默认值的问题

解决:在@Bean方法的参数上使用@Value注入username和password

1
2
3
4
5
6
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor(@Value("${spring.cloud.config.username}") String username,
@Value("${spring.cloud.config.password}") String password) {
//这时username和password可以注入
return new BasicAuthRequestInterceptor(username, password);
}

@DependsOn

1
2
3
4
5
@Bean
// 在创建 eventConfig bean 之后再创建当前 bean
@DependsOn("eventConfig")
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
}

@Conditional

从 Spring4 开始,可以通过@Conditional注解实现按条件装载bean对象,目前 Spring Boot 源码中大量扩展了@Condition注解,用于实现智能的自动化配置,满足各种使用场景。下面我给大家列举几个常用的注解:

  • @ConditionalOnBean:当某个特定的Bean存在时,配置生效
  • @ConditionalOnMissingBean:当某个特定的Bean不存在时,配置生效
  • @ConditionalOnClass:当Classpath里存在指定的类,配置生效
  • @ConditionalOnMissingClass:当Classpath里不存在指定的类,配置生效
  • @ConditionalOnExpression:当给定的SpEL表达式计算结果为true,配置生效
  • @ConditionalOnProperty:当指定的配置属性有一个明确的值并匹配,配置生效

具体的应用案例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
@Configuration
public class ConditionalConfig {
/**
* 当AppConfig对象存在时,创建一个A对象
* @return
*/
@ConditionalOnBean(AppConfig.class)
@Bean
public A createA(){
return new A();
}

/**
* 当AppConfig对象不存在时,创建一个B对象
* @return
*/
@ConditionalOnMissingBean(AppConfig.class)
@Bean
public B createB(){
return new B();
}


/**
* 当KafkaTemplate类存在时,创建一个C对象
* @return
*/
@ConditionalOnClass(KafkaTemplate.class)
@Bean
public C createC(){
return new C();
}

/**
* 当KafkaTemplate类不存在时,创建一个D对象
* @return
*/
@ConditionalOnMissingClass(KafkaTemplate.class)
@Bean
public D createD(){
return new D();
}


/**
* 当enableConfig的配置为true,创建一个E对象
* @return
*/
@ConditionalOnExpression("${enableConfig:false}")
@Bean
public E createE(){
return new E();
}


/**
* 当filter.loginFilter的配置为true,创建一个F对象
* @return
*/
@ConditionalOnProperty(prefix = "filter",name = "loginFilter",havingValue = "true")
@Bean
public F createF(){
return new F();
}
}

@Import

@Import 经常用于 SpringBoot 自动配置机制中,通过这种方式,可以自动注册一些默认的 Bean 实例来简化开发工作

1
2
3
4
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {

}

@Autowired

自动导入依赖的bean对象,默认时按照byType方式导入对象,而且导入的对象必须存在,当需要导入的对象并不存在时,我们可以通过配置required = false来关闭强制验证。

1
2
@Autowired
private DeptService deptService;

@Resource

也是自动导入依赖的bean对象,JDK提供,默认是按照byName方式导入依赖的对象;而@Autowired默认时按照byType方式导入对象,当然@Resource还可以配置成通过byType方式导入对象。

1
2
3
4
5
6
7
8
9
10
11
/**
* 通过名称导入(默认通过名称导入依赖对象)
*/
@Resource(name = "deptService")
private DeptService deptService;

/**
* 通过类型导入
*/
@Resource(type = RoleRepository.class)
private DeptService deptService;

@Qualifier

当有多个同一类型的bean时,使用@Autowired导入会报错,提示当前对象并不是唯一,Spring不知道导入哪个依赖,这个时候,我们可以使用@Qualifier进行更细粒度的控制,选择其中一个候选者,一般于@Autowired搭配使用,示例如下:

1
2
3
@Autowired
@Qualifier("deptService")
private DeptService deptService;

@Scope

用于声明一个spring bean的作用域,作用的范围一共有以下几种:

  • singleton:唯一 bean 实例,Spring 中的 bean 默认都是单例的。
  • prototype:每次请求都会创建一个新的 bean 实例,对象多例。
  • request:每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
  • session:每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。
1
2
3
4
5
6
7
8
/**
* 单例对象
*/
@RestController
@Scope("singleton")
public class HelloController {

}

配置相关

@Configuration

表示声明一个 Java 形式的配置类,Spring Boot 提倡基于 Java 的配置,相当于你之前在 xml 中配置 bean,比如声明一个配置类AppConfig,然后初始化一个Uploader对象。

1
2
3
4
5
6
7
8
@Configuration
public class AppConfig {

@Bean
public Uploader initOSSUploader() {
return new OSSUploader();
}
}

@EnableAutoConfiguration

@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置类,全部都加载到当前SpringBoot里,并创建对应配置类的Bean,并把该Bean实体交给IoC容器进行管理。

某些场景下,如果我们想要避开某些配置类的扫描(包括避开一些第三方jar包下面的配置,可以这样处理。

1
2
3
4
5
6
7
@Configuration
@EnableAutoConfiguration(exclude = { org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class
})
public class AppConfig {

//具有业务方法
}

@ComponentScan

标注哪些路径下的类需要被Spring扫描,用于自动发现和装配一些Bean对象,默认配置是扫描当前文件夹下和子目录下的所有类,如果我们想指定扫描某些包路径,可以这样处理。

1
@ComponentScan(basePackages = {"com.xxx.a", "com.xxx.b", "com.xxx.c"})

@SpringBootApplication

等价于使用@Configuration@EnableAutoConfiguration@ComponentScan这三个注解,通常用于全局启动类上,示例如下:

1
2
3
4
5
6
7
@SpringBootApplication
public class PropertyApplication {

public static void main(String[] args) {
SpringApplication.run(PropertyApplication.class, args);
}
}

@SpringBootApplication换成@Configuration@EnableAutoConfiguration@ComponentScan这三个注解,一样可以启动成功,@SpringBootApplication只是将这三个注解进行了简化!

@EnableTransactionManagement

表示开启事务支持,等同于 xml 配置方式的<tx:annotation-driven />

1
2
3
4
5
6
7
8
@SpringBootApplication
@EnableTransactionManagement`
public class PropertyApplication {

public static void main(String[] args) {
SpringApplication.run(PropertyApplication.class, args);
}
}

@EnableAsync

开启异步任务支持,方法上配合注解 @Async,配置项为 spring.task.execution

@EnableScheduling

开启定时任务支持,方法上配合注解 @Scheduled,配置项为 spring.task.scheduling

@value

可以在任意 Spring 管理的 Bean 中通过这个注解获取任何来源配置的属性值,比如你在application.properties文件里,定义了一个参数变量!

1
config.name=zhangsan

在任意的bean容器里面,可以通过@Value注解注入参数,获取参数变量值。

1
2
3
4
5
6
7
8
9
10
11
@RestController
public class HelloController {

@Value("${config.name}")
private String config;

@GetMapping("config")
public String config(){
return JSON.toJSONString(config);
}
}

也可以写到方法参数上

1
2
3
4
5
6
7
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor(
@Value("${spring.cloud.config.username}") String username,
@Value("${spring.cloud.config.password}") String password) {
//这时username和password可以注入
return new BasicAuthRequestInterceptor(username, password);
}

@ConfigurationProperties

上面@Value在每个类中获取属性配置值的做法,其实是不推荐的。

一般在企业项目开发中,不会使用那么杂乱无章的写法而且维护也麻烦,通常会一次性读取一个 Java 配置类,然后在需要使用的地方直接引用这个类就可以多次访问了,方便维护,示例如下:

首先,在application.properties文件里定义好参数变量。

1
2
config.name=demo_1
config.value=demo_value_1

然后,创建一个 Java 配置类,将参数变量注入即可!

1
2
3
4
5
6
7
8
@Component
@ConfigurationProperties(prefix = "config")
public class Config {
public String name;
public String value;

//...get、set
}

最后,在需要使用的地方,通过ioc注入Config对象即可!

@PropertySource

这个注解是用来读取我们自定义的配置文件的,比如导入test.propertiesbussiness.properties两个配置文件,用法如下:

1
2
3
4
5
6
7
@SpringBootApplication
@PropertySource(value = {"test.properties","bussiness.properties"})
public class PropertyApplication {
public static void main(String[] args) {
SpringApplication.run(PropertyApplication.class, args);
}
}

@ImportResource

用来加载 xml 配置文件,比如导入自定义的aaa.xml文件,用法如下:

1
2
3
4
5
6
7
@ImportResource(locations = "classpath:aaa.xml")
@SpringBootApplication
public class PropertyApplication {
public static void main(String[] args) {
SpringApplication.run(PropertyApplication.class, args);
}
}

异常处理相关

@ControllerAdvice@RestControllerAdvice + @ExceptionHandler

通常组合使用,用于处理全局异常。@RestControllerAdvice 相当于 @ControllerAdvice + @ResponseBody

示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@ControllerAdvice
@Configuration
@Slf4j
public class GlobalExceptionConfig {

private static final Integer GLOBAL_ERROR_CODE = 500;

@ExceptionHandler(value = Exception.class)
@ResponseBody
public void exceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception e) throws Exception {
log.error("【统一异常处理器】", e);
ResultMsg<Object> resultMsg = new ResultMsg<>();
resultMsg.setCode(GLOBAL_ERROR_CODE);
if (e instanceof CommonException) {
CommonException ex = (CommonException) e;
if(ex.getErrCode() != 0) {
resultMsg.setCode(ex.getErrCode());
}
resultMsg.setMsg(ex.getErrMsg());
}else {
resultMsg.setMsg(CommonErrorMsg.SYSTEM_ERROR.getMessage());
}
WebUtil.buildPrintWriter(response, resultMsg);
}
}

测试相关

@ActiveProfiles

一般作用于测试类上, 用于声明生效的 Spring 配置文件,比如指定application-dev.properties配置文件。

@RunWith@SpringBootTest

一般作用于测试类上, 用于单元测试用,示例如下:

1
2
3
4
5
6
7
8
9
10
@ActiveProfiles("dev")
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestJunit {

@Test
public void executeTask() {
//测试...
}
}