# Springboot 常用注解
# Java 注解(Annotation)
首先了解一下注解。
这个是 Controller
的源代码,以它为例。
@Target({ElementType.TYPE}) | |
@Retention(RetentionPolicy.RUNTIME) | |
@Documented | |
@Component | |
public @interface Controller { | |
@AliasFor( | |
annotation = Component.class | |
) | |
String value() default ""; | |
} |
里面有六个个注解(注意有个 @interface
),注解可以作用于注解:
@Target
java.lang.annotation.Target
自身也是一个注解,它只有一个数组属性,用于设定该注解的目标范围。比如我要让这个注解作用于类或者作用于方法上。它为数组属性,可以同时设定多个值,就是可以同时作用于类或者方法上。这里说几个常用的作用的类型:
ElementType.TYPE
可以作用于 类、接口类、枚举类上
ElementType.FIELD
可以作用于类的属性上
ElementType.METHOD
可以作用于类的方法上
ElementType.PARAMETER
可以作用于类的参数
如果需要同时作用于类和方法上,那么可以这样写:
@Target({ElementType.TYPE,ElementType.METHOD})
可以看看
java.lang.annotation.ElementType
这个枚举类中提供的类型,一共提供了 11 个target
可以作用的类型。举栗子:
1.1 ElementType.TYPE,作用在类上。
@Service
public class DocServiceImpl extends ServiceImpl<DocMapper, Doc> implements DocService
1.2 ElementType.FIELD, 作用在类的属性上。
@Resource
private DocMapper docMapper;
1.3 ElementType.PARAMETER,作用在类的参数上。这里的
@Param
。void addS (@Param("sid") Integer sid, @Param("did") Integer did);
@Retention
java.lang.annotation.Retention
自身也是一个注解,它用于声明该注解的生命周期,就是在 Java 编译、运行的哪个环节有效。有三个值可以选择:SOURCE: 编译器将无视这个注解,就是这个注解相当于注释
CLASS: 注释由编译器记录在类文件中,在 VM 运行时不需要保留这些注释,已经默认保留。也就是在编译阶段是有效的。
RUNTIME: 在运行时有效。
@Documented
如果一个注解使用 Documted 进行注释,默认情况下,像 javadoc 这样的工具将在其输出中显示该注解中的元素(注解类型信息),而不使用 Documted 的注解将不会显示。就是说,用 @Documented 注解修饰的注解类会被 JavaDoc 工具提取成文档。
Javadoc(最初是 JavaDoc)是由 Sun Microsystems 为 Java 语言(现在由甲骨文公司拥有)创建的文档生成器,用于从 Java 源代码生成 HTML 格式的 API 文档,HTML 格式用于增加将相关文档链接在一起的便利性。Javadoc 不影响 Java 中的性能,因为在编译时会删除所有注释。编写注释和 Javadoc 是为了更好地理解代码,从而更好地维护代码。
一般都会添加这个注解。
@Component
这个是 Spring 的注解,把当前类对象存入 Spring 容器,Spring 会把这个类标记为 bean, 方便后期装配。
这个注解后面跟四大组件再一起说。
@interface
就是声明当前的 Java 类型是 Annotation,固定语法。@AliasFor
起别名。上面那个@Controller
用法使用这个注解时有点特殊。@AliasFor
可以用来对一个类中的不同属性起别名,起相同的别名,然后可以用这个别名互相调用这几个不同的属性。@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
@AliasFor("basePackages")
String[] value() default {};
@AliasFor("value")
String[] basePackages() default {};
...
}
意味着我们可以互换使用它们。所以,以下这三种用法是一样的。
@ComponentScan("com.baeldung.aliasfor")
@ComponentScan(basePackages = "com.baeldung.aliasfor")
@ComponentScan(value = "com.baeldung.aliasfor")
@Controller
特殊在哪呢,你发现它起的别名不是一个注解内的属性,而是跨注解的属性,所以@AliasFor
可以声明跨注解的属性别名。这里的意思就是@Component
和@Controller
互通。实际上,@Component
跟@Service
和@Controller
都互通(应该是有那么一点差异吧,但是可以实现一样的功能)。@AliasFor(
annotation = Component.class
)
除了注解中的注解需要了解之外,注解中的属性我们也需要知道,跟类的属性很像。有基础类型,属性名称(默认为 value
,在引用的时候可以忽略),default 代表的是默认值。
String value() default ""; |
我们正常引用一个注解,比如 @Service
@Service | |
public class StarServiceImpl extends ServiceImpl<StarMapper,Star> implements StarService |
也可以这样:
@Service(value="StarServiceImpl") | |
public class StarServiceImpl extends ServiceImpl<StarMapper,Star> implements StarService |
value
可以不写。
# @SpringBootApplication
这个注解实际包含了以下几个注解:
- @SpringBootConfiguration
- @Configuration
- @EnableAutoConfiguration
- @AutoConfigurationPackage
- @ComponentScan
这个注解就启动了自动配置和自动扫描。
@SpringBootApplication | |
public class Application { | |
public static void main(String[] args) throws Exception { | |
SpringApplication.run(Application.class, args); | |
} | |
} |
# 四大注解
添加这四个注解都会将这个类自动注册为 Spring Beans。这四个注解可以混着用,都是一样的作用,不过不建议四个注解当成一个注解用。
# @Component
通用的注解,可标识任意类为 Spring 组件。下面三个注解都是这个注解的拓展。当该类不知道属于以上三类的那一类时可以使用该注解。
# @Service
服务层,主要在这里编写逻辑
# @Repository
持久层也就是 Dao 层,负责数据库相关操作。
# @Controller
作用于 Web Bean,Spring 在处理传入的 Web 请求时会传到这个类。
# @RestController
表明这个注解下的类是一个 web @Controller
,所以 Spring 在处理传入的 Web 请求时会传到这个类。
区别 @Controller
, @RestController
返回结果字符串,即返回数据内容, @Controller
返回页面
@RestController
相当于 @Controlle
和 @ResponseBody
# @RequestMapping
提供路由信息,告诉 Spring 任何带有 /
路径的 HTTP 请求都映射到 home
方法。用于解析 URL 请求路径,这个注解默认是支持所有的 Http Method 的。
# @Autowire
依赖注入。 @SpringBootApplication
已经为我们自动装配和自动扫描好了,现在我们需要完成依赖注入。
为什么需要使用 @Autowire
去完成依赖注入呢? @Autowire
它的作用是什么?
我们都知道使用类的时候需要都需要实例化对象,需要去 new 一个对象,但是当我们需要实例化的对象太多了就会出现很多 new
实例对象,这样容易出错,也不好看。
所以我们使用 @Autowire
,在任何我们需要使用类(bean)的地方,用 @Autowired
注解标记,告诉 Spring 这里需要注入实现类的实例。项目启动过程中,Spring 会 自动 实例化服务实现类,然后 自动 注入到变量中。
前提条件是该类被注册为 Spring Bean。
@Service | |
public class AdminService |
@Autowired | |
AdminService adminService; |
我们也可以不使用 @Autowire
实现注入,我们也可以使用构造函数注入,似乎这是更推荐的方法。
private final AdminService adminService; | |
public AdminController (AdminService adminService) { | |
this.adminService = adminService; | |
} |
# @PathVariable
接收路径参数。
@GetMapping("/api/employeeswithvariable/{id}") | |
@ResponseBody | |
public String getEmployeesByIdWithVariableName(@PathVariable("id") String employeeId) { | |
return "ID: " + employeeId; | |
} |
输入网址:http://localhost:8080/api/employeeswithvariable/1
----
输出结果:ID: 1
@PathVariable
获取 url 中的数据。
# @RequestParam
@PostMapping("/api/foos") | |
@ResponseBody | |
public String addFoo(@RequestParam(name = "id") String fooId) { | |
return "ID: " + fooId; | |
} |
我们可以 @RequestParam(value = "id")
或者 @RequestParam("id")
@RequestParam
获取查询参数。
http://localhost:8080/spring-mvc-basics/api/foos?id=abc
----
ID: abc
@RequestParam(required = false)
说明这个参数不是必须的。
@GetMapping("/api/foos") | |
@ResponseBody | |
public String getFoos(@RequestParam(required = false) String id) { | |
return "ID: " + id; | |
} |
可以这样:
http://localhost:8080/spring-mvc-basics/api/foos?id=abc
----
ID: abc
也可以这样:
http://localhost:8080/spring-mvc-basics/api/foos
----
ID: null
# @RequestBody
@RequestBody
将 HttpRequest 主体映射到传输对象或域对象,从而支持将入站 HttpRequest 主体自动反序列化到 Java 对象。就是将传来的参数数据映射到我们的 Java 实体类中。
@requestBody
注解常用来处理 content-type(http 请求头)不是默认的 application/x-www-form-urlcoded 编码的内容,比如说:application/json 或者是 application/xml 等。一般情况下来说常用其来处理 application/json 类型。
感觉跟 @RequestParam
差不多,只不过就是映射的是一个对象多个属性,还有就是参数放在 request 体中,而不是在直接连接在地址后面。
@PostMapping("/request") | |
public ResponseEntity postController( | |
@RequestBody LoginForm loginForm) { | |
exampleService.fakeAuthenticate(loginForm); | |
return ResponseEntity.ok(HttpStatus.OK); | |
} |
public class LoginForm { | |
private String username; | |
private String password; | |
// ... | |
} |
写法就是像上面一样,然后我们传参数的话,将
POST 请求 body 传数据: {"username": "johnny", "password": "password"}
。这将会映射到我们的 LoginForm
这个实体类上。
# @ResponseBody
将返回值放在 response 内,而不是一个页面,通常用户返回 json 数据。
# @ExceptionHandler
@Target({ElementType.METHOD}) | |
@Retention(RetentionPolicy.RUNTIME) | |
@Documented | |
public @interface ExceptionHandler { | |
Class<? extends Throwable>[] value() default {}; | |
} |
@ExceptionHandler({RuntimeException.class}) |
作用在方法上。
用于全局处理控制器里的异常。是个数组,可以传多个 Class(一个 Class
实例包含了该 class
的所有完整信息,反射那边的知识吧)。
# @Scheduled
申明这是一个任务,包括 cron,fixDelay,fixRate
等类型。可以用它写定时任务。