一文速通 Spring Boot 常用注解,建議收藏!
基于 Spring Boot 平臺(tái)開(kāi)發(fā)的項(xiàng)目數(shù)不勝數(shù)。得益于 Spring Boot 提供的大量用于快速開(kāi)發(fā)的注解,開(kāi)發(fā)過(guò)程非常簡(jiǎn)單,基本上可以開(kāi)箱即用!
Spring Boot 為開(kāi)發(fā)者提供了多少注解?我們又該如何使用它們呢?關(guān)于這個(gè)問(wèn)題,我特意進(jìn)行了整理,以幫助你快速理解或回顧。
1. 組件相關(guān)注解
(1) @Controller:用于修飾 MVC 中控制器層的組件。Spring Boot 中的組件掃描功能會(huì)識(shí)別此注解,并為被修飾的類(lèi)實(shí)例化一個(gè)對(duì)象。它通常與@RequestMapping 一起使用。當(dāng) Spring MVC 收到請(qǐng)求時(shí),會(huì)將其轉(zhuǎn)發(fā)到指定路徑的方法進(jìn)行處理。
@Controller
@RequestMapping("/user/admin")
public class UserAdminController {
}
(2) @Service:通常用于修飾服務(wù)層的組件。聲明一個(gè)對(duì)象時(shí),會(huì)實(shí)例化該類(lèi)對(duì)象并將其注入到 bean 容器中。
@Service
public class UserService {
//...
}
(3) @Repository:用于修飾數(shù)據(jù)訪問(wèn)對(duì)象(DAO)層的組件。DAO 層的組件專(zhuān)注于系統(tǒng)數(shù)據(jù)的處理,例如數(shù)據(jù)庫(kù)中的數(shù)據(jù)。它們也會(huì)被組件掃描并生成實(shí)例化對(duì)象。
@Repository
public interface RoleRepository extends JpaRepository<Role, Long> {
//...
}
(4) @Component:一般指代組件。當(dāng)組件難以分類(lèi)時(shí),可以使用此注解進(jìn)行標(biāo)記。其功能與@Service 類(lèi)似。
@Component
public class DemoHandler {
//...
}
2. 與 Bean 實(shí)例和生命周期相關(guān)的注解
(1) @Bean:用于修飾方法,表示該方法將創(chuàng)建一個(gè) Bean 實(shí)例,并由 Spring 容器進(jìn)行管理。示例代碼如下:
@Configuration
public class AppConfig {
// 相當(dāng)于在 XML 中配置一個(gè) Bean
@Bean
public Uploader initFileUploader() {
return new FileUploader();
}
}
(2) @Scope:用于聲明 Spring Bean 實(shí)例的作用域。作用域如下:
- singleton:?jiǎn)卫J健T?Spring 容器中實(shí)例是唯一的,這是 Spring 的默認(rèn)實(shí)例作用域類(lèi)型。
- prototype:原型模式。每次使用時(shí)都會(huì)重新創(chuàng)建實(shí)例。
- request:在同一請(qǐng)求中使用相同的實(shí)例,不同請(qǐng)求創(chuàng)建新的實(shí)例。
- session:在同一會(huì)話中使用相同的實(shí)例,不同會(huì)話創(chuàng)建新的實(shí)例。
@Configuration
public class RestTemplateConfig {
@Bean
@Scope("singleton")
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
(3) @Primary:當(dāng)存在同一對(duì)象的多個(gè)實(shí)例時(shí),優(yōu)先選擇此實(shí)例。
@Configuration
@ComponentScan
public class JavaConfig {
// 首選
@Bean("b1")
@Primary
B b1() {
return new B();
}
@Bean("b2")
B b2() {
return new B();
}
}
(4) @PostConstruct:用于修飾方法,在對(duì)象實(shí)例創(chuàng)建和依賴注入完成后執(zhí)行,可用于初始化對(duì)象實(shí)例。
(5) @PreDestroy:用于修飾方法,在對(duì)象實(shí)例即將被 Spring 容器移除時(shí)執(zhí)行,可用于釋放對(duì)象實(shí)例持有的資源。
public class Demo {
public Demo() {
System.out.println("構(gòu)造方法...");
}
public void init() {
System.out.println("init...");
}
}
@PostConstruct
public void postConstruct() {
System.out.println("postConstruct...");
}
@PreDestroy
public void preDestroy() {
System.out.println("preDestroy...");
}
public void destroy() {
System.out.println("destroy...");
}
輸出:
構(gòu)造方法...
postConstruct...
init...
preDestroy...
destroy...
3. 依賴注入注解
(1) @Autowired:根據(jù)對(duì)象的類(lèi)型自動(dòng)注入依賴對(duì)象。默認(rèn)情況下,它要求注入的對(duì)象實(shí)例必須存在。可以配置 required = false 來(lái)注入可能不存在的對(duì)象。
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@Autowired(required = false)
private UserConfig userConfig;
}
(2) @Resource:默認(rèn)情況下,根據(jù)對(duì)象的名稱(chēng)自動(dòng)注入依賴對(duì)象。如果要根據(jù)類(lèi)型注入,可以設(shè)置屬性 type = UmsAdminService.class。
@Controller
@RequestMapping("/user")
public class UserController {
@Resource(name = "userServiceImpl")
private UserService userService;
}@Controller
@RequestMapping("/user")
public class UserController {
@Resource(name = "userServiceImpl")
private UserService userService;
}
(3) @Qualifier:當(dāng)存在同一類(lèi)型的多個(gè) bean 時(shí),使用@Autowired 導(dǎo)入會(huì)導(dǎo)致錯(cuò)誤,表示當(dāng)前對(duì)象不唯一,Spring 不知道要導(dǎo)入哪個(gè)依賴。此時(shí),我們可以使用@Qualifier 進(jìn)行更細(xì)粒度的控制并選擇其中一個(gè)實(shí)例。它通常與@Autowired 一起使用。示例如下:
@Autowired
@Qualifier("deptService")
private DeptService deptService;
4. SpringMVC 相關(guān)注解
(1) @RequestMapping:提供路由信息,負(fù)責(zé)將 URL 映射到 Controller 中的指定函數(shù)。當(dāng)用于方法上時(shí),可以指定請(qǐng)求協(xié)議,如 GET、POST、PUT、DELETE 等。
(2) @RequestBody:表示請(qǐng)求體的 Content - Type 必須是 application/json 格式的數(shù)據(jù)。接收到數(shù)據(jù)后,會(huì)自動(dòng)將數(shù)據(jù)綁定到 Java 對(duì)象。
(3) @ResponseBody:表示此方法的返回結(jié)果直接寫(xiě)入 HTTP 響應(yīng)體。返回?cái)?shù)據(jù)的格式為 application/json。 例如,如果請(qǐng)求參數(shù)是 json 格式,返回參數(shù)也是 json 格式,示例代碼如下:
@Controller
@RequestMapping("api")
public class LoginController {
@RequestMapping(value = "login", method = RequestMethod.POST)
@ResponseBody
public ResponseEntity login(@RequestBody UserLoginDTO request) {
//...
return new ResponseEntity(HttpStatus.OK);
}
}
(4) @RestController:與@Controller 類(lèi)似,用于注釋控制器層組件。不同之處在于它是@ResponseBody 和@Controller 的組合。 即,當(dāng)在類(lèi)上使用@RestController 時(shí),表示當(dāng)前類(lèi)中所有對(duì)外暴露的接口方法,返回?cái)?shù)據(jù)的格式都是 application/json。示例代碼如下:
@RestController
@RequestMapping("/api")
public class LoginController {
@RequestMapping(value = "/login", method = RequestMethod.POST)
public ResponseEntity login(@RequestBody UserLoginDTO request) {
//...
return new ResponseEntity(HttpStatus.OK);
}
}
(5) @RequestParam:用于接收請(qǐng)求參數(shù)為表單類(lèi)型的數(shù)據(jù)。通常用于方法的參數(shù)前面。示例代碼如下:
@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);
}
(6) @PathVariable:用于獲取請(qǐng)求路徑中的參數(shù)。通常用于 restful 風(fēng)格的 API。示例代碼如下:
@RequestMapping(value = "queryProduct/{id}", method = RequestMethod.POST)
@ResponseBody
public ResponseEntity queryProduct(@PathVariable("id") String id) {
//...
return new ResponseEntity(HttpStatus.OK);
}
(7) @GetMapping、@PostMapping、@PutMapping、@DeleteMapping:除了@RequestMapping 能夠指定請(qǐng)求方法外,還有一些其他注解可以用于注釋接口路徑請(qǐng)求。例如,當(dāng)@GetMapping 用于方法上時(shí),表示僅支持 get 請(qǐng)求方法。它等同于@RequestMapping(value = "/get", method = RequestMethod.GET)。
@GetMapping("get")
public ResponseEntity get() {
return new ResponseEntity(HttpStatus.OK);
}
@PostMapping("post")
public ResponseEntity post() {
return new ResponseEntity(HttpStatus.OK);
}
@PutMapping("put")
public ResponseEntity put() {
return new ResponseEntity(HttpStatus.OK);
}
@DeleteMapping("delete")
public ResponseEntity delete() {
return new ResponseEntity(HttpStatus.OK);
}
5. 配置相關(guān)注解
(1) @Configuration:表示聲明一個(gè)基于 Java 的配置類(lèi)。Spring Boot 提倡基于 Java 對(duì)象的配置,相當(dāng)于以前在 xml 中配置 bean。例如,聲明一個(gè)配置類(lèi) AppConfig,然后初始化一個(gè) Uploader 對(duì)象。
@Configuration
public class AppConfig {
@Bean
public Uploader initOSSUploader() {
return new OSSUploader();
}
}
(2) @EnableAutoConfiguration:@EnableAutoConfiguration 可以幫助 Spring Boot 應(yīng)用程序?qū)⑺蟹蠗l件的@Configuration 配置類(lèi)加載到當(dāng)前的 Spring Boot 中,創(chuàng)建與配置類(lèi)對(duì)應(yīng)的 Beans,并將 Bean 實(shí)體交給 IoC 容器管理。在某些場(chǎng)景下,如果我們想要避免某些配置類(lèi)的掃描(包括避免一些第三方 jar 下的配置),可以這樣處理。
@Configuration
@EnableAutoConfiguration(exclude = {
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class
})
public class AppConfig {
//...
}
(3) @ComponentScan:注釋哪些路徑下的類(lèi)需要被 Spring 掃描。用于自動(dòng)發(fā)現(xiàn)和組裝一些 Bean 對(duì)象。默認(rèn)配置是掃描當(dāng)前文件夾及子目錄中的所有類(lèi)。如果我們想要指定掃描某些包路徑,可以這樣處理。
@ComponentScan(basePackages = {"com.xxx.a", "com.xxx.b", "com.xxx.c"})
(4) @SpringBootApplication:相當(dāng)于使用了@Configuration、@EnableAutoConfiguration 和@ComponentScan 這三個(gè)注解。通常用于全局啟動(dòng)類(lèi)。示例如下:
@SpringBootApplication
public class PropertyApplication {
public static void main(String[] args) {
SpringApplication.run(PropertyApplication.class, args);
}
}
用這三個(gè)注解@configuration、@EnableAutoConfiguration 和@ComponentScan 替換@springBootApplication 也可以成功啟動(dòng),@springBootApplication 只是簡(jiǎn)化了這三個(gè)注解。
(5) @EnableTransactionManagement:表示啟用事務(wù)支持,相當(dāng)于 xml 配置方式中的 tx:annotation - driven/>。
@SpringBootApplication
@EnableTransactionManagement
public class PropertyApplication {
public static void main(String[] args) {
SpringApplication.run(PropertyApplication.class, args);
}
}
(6) @ConfigurationProperties:用于批量注入外部配置,并以對(duì)象的形式導(dǎo)入具有指定前綴的配置。例如,這里我們?cè)?application.yml 中指定前綴為 secure.ignored 的屬性:
secure:
ignored:
urls: # 安全路徑白名單
- /swagger-ui/
- /swagger-resources/**
- / **/*.htm1
- / **/*.js
- / **/*.css
- / **/*.png
- /favicon.ico
- /actuator/**
然后,在 Java 類(lèi)中定義一個(gè) urls 屬性,就可以導(dǎo)入配置文件中的屬性。
@Getter
@Setter
@Configuration
@ConfigurationProperties(prefix = "secure.ignored")
public class IgnoreUrlsConfig {
private List<String> urls = new ArrayList<>();
}
(7) @Conditional:從 Spring 4 開(kāi)始,@Conditional 注解可以用于有條件地加載 bean 對(duì)象。目前,在 Spring Boot 源代碼中,@Condition 注解已經(jīng)得到了廣泛的擴(kuò)展,用于實(shí)現(xiàn)智能自動(dòng)配置,以滿足各種使用場(chǎng)景。以下是一些常用的注解:
- @ConditionalOnBean:當(dāng)指定的 Bean 存在時(shí),配置生效。
- @ConditionalOnMissingBean:當(dāng)指定的 Bean 不存在時(shí),配置生效。
- @ConditionalOnClass:當(dāng)指定的類(lèi)在類(lèi)路徑中存在時(shí),配置生效。@ConditionalOnMissingClass:當(dāng)指定的類(lèi)在類(lèi)路徑中不存在時(shí),配置生效。
- @ConditionalOnExpression:當(dāng)給定的 SpEL 表達(dá)式的計(jì)算結(jié)果為 true 時(shí),配置生效。
- @ConditionalOnProperty:當(dāng)指定的配置屬性具有確定的值且匹配時(shí),配置生效。 具體應(yīng)用案例如下:
@Configuration
public class ConditionalConfig {
/**
* 當(dāng) Test 對(duì)象存在時(shí),創(chuàng)建一個(gè)對(duì)象 A
*
* @return
*/
@ConditionalOnBean(Test.class)
@Bean
public A createA() {
return new A();
}
/**
* 當(dāng) Test 對(duì)象不存在時(shí),創(chuàng)建一個(gè)對(duì)象 B
*
* @return
*/
@Conditional0nMissingBean(Test.class)
@Bean
public B createB() {
return new B();
}
/**
* 當(dāng) Test 類(lèi)存在時(shí),創(chuàng)建一個(gè)對(duì)象 C
*
* @return
*/
@Conditional0nclass(Test.class)
@Bean
public C createC() {
return new C();
}
/**
* 當(dāng) Test 類(lèi)不存在時(shí),創(chuàng)建一個(gè)對(duì)象 D
*
* @return
*/
@Conditional0nMissingClass(Test.class)
@Bean
public D createD() {
return new D();
}
/**
* 當(dāng) enableConfig 的配置為 true 時(shí),創(chuàng)建一個(gè)對(duì)象 E
*
* @return
*/
@Conditiona10nExpression("$ {enableConfig:false}")
@Bean
public E createE() {
return new E();
}
/**
* 當(dāng) filter.loginFilter 的配置為 true 時(shí),創(chuàng)建一個(gè)對(duì)象 F
*
* @return
*/
@Conditiona10nProperty(prefix = "filter", name = "loginilter", havingalue =
"true")
@Bean
public F createF() {
return new F();
}
}
(8) @Value:在任何 Spring 管理的 Bean 中,可以通過(guò)此注解獲取從任何源配置的屬性值。例如,在 application.properties 文件中,定義一個(gè)參數(shù)變量:
config.name=Dylan
在任何 bean 實(shí)例內(nèi),可以通過(guò)@Value 注解注入?yún)?shù)并獲取參數(shù)變量的值。
@RestController
public class HelloController {
@Value("${config.name}")
private String configName;
@GetMapping("config")
public String config() {
return JSON.toJSONString(configName);
}
}
(9) @ConfigurationProperties:在每個(gè)類(lèi)中使用@Value 獲取屬性配置值的做法實(shí)際上并不推薦。 在一般的企業(yè)項(xiàng)目開(kāi)發(fā)中,不會(huì)使用這種混亂的寫(xiě)法,而且維護(hù)也很麻煩。通常,一次讀取一個(gè) Java 配置類(lèi),然后在需要的地方直接引用這個(gè)類(lèi)進(jìn)行使用,這樣可以多次訪問(wèn)且便于維護(hù)。示例如下: 首先,在 application.properties 文件中定義參數(shù)變量。
config.name=demo_1 config.value=demo_value_1
然后,創(chuàng)建一個(gè) Java 配置類(lèi)并注入?yún)?shù)變量。
@Component
@ConfigurationProperties(prefix = "config")
public class Config {
public String name;
public String value;
//... get、set 方法
}
最后,在需要的地方,通過(guò) ioc 注入 Config 對(duì)象。
(10) @PropertySource:此注解用于讀取我們自定義的配置文件。例如,要導(dǎo)入兩個(gè)配置文件 test.properties 和 bussiness.properties,用法如下:
@SpringBootApplication
@PropertySource(value = {"test.properties", "bussiness.properties"})
public class PropertyApplication {
public static void main(String[] args) {
SpringApplication.run(PropertyApplication.class, args);
}
}
(11) @ImportResource:用于加載 xml 配置文件。例如,要導(dǎo)入自定義的 aaa.xml 文件,用法如下:
@ImportResource(locations = "classpath:aaa.xml")
@SpringBootApplication
public class PropertyApplication {
public static void main(String[] args) {
SpringApplication.run(PropertyApplication.class, args);
}
}
6. JPA 相關(guān)注解
(1) @Entity 和@Table:表示這是一個(gè)實(shí)體類(lèi)。這兩個(gè)注解通常一起使用。但是,如果表名與實(shí)體類(lèi)名相同,@Table 可以省略。
(2) @Id:表示此屬性字段對(duì)應(yīng)數(shù)據(jù)庫(kù)表中的主鍵字段。
(3) @Column:表示此屬性字段對(duì)應(yīng)的數(shù)據(jù)庫(kù)表中的列名。如果字段名與列名相同,可以省略。
(4) @GeneratedValue:表示主鍵的生成策略。有以下四個(gè)選項(xiàng):
- AUTO:表示由程序控制,是默認(rèn)選項(xiàng)。如果未設(shè)置,則為該選項(xiàng)。
- IDENTITY:表示由數(shù)據(jù)庫(kù)生成,使用數(shù)據(jù)庫(kù)自動(dòng)遞增。Oracle 不支持此方法。
- SEQUENCE:表示主鍵 ID 通過(guò)數(shù)據(jù)庫(kù)序列生成。MySQL 不支持此方法。
- TABLE:表示主鍵由指定數(shù)據(jù)庫(kù)生成。此方法有利于數(shù)據(jù)庫(kù)遷移。
(5) @SequenceGenerator:用于定義生成主鍵的序列。需要與@GeneratedValue 一起使用才能生效。以 role 表為例,相應(yīng)的注解配置如下:
@Entity
@Table(name = "role")
@SequenceGenerator(name = "id_seq", sequenceName = "seq_repair", allocationSize = 1)
public class Role implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "id_seq")
private Long id;
@Column(nullable = false)
private String roleName;
@Column(nullable = false)
private String roleType;
}
(6) @Transient:表示此屬性不映射到數(shù)據(jù)庫(kù)表的字段。ORM 框架將忽略此屬性。
@Column(nullable = false)
@Transient
private String lastTime;
(7) **@Basic(fetch = FetchType.LAZY)**:用于某些屬性上,可以實(shí)現(xiàn)懶加載的效果。即,當(dāng)使用此字段時(shí),才會(huì)加載此屬性。如果配置為 fetch = FetchType.EAGER,則表示立即加載,這也是默認(rèn)的加載方式!
@Column(nullable = false)
@Basic(fetch = FetchType.LAZY)
private String roleType;
(8) @JoinColumn:用于注釋表示表關(guān)系的字段。通常與@OneToOne 和@OneToMany 一起使用。例如:
@Entity
@Table(name = "tb_login_log")
public class LoginLog implements Serializable {
@OneToOne
@JoinColumn(name = "user_id")
private User user;
//... get、set
}
(9) @OneToOne、@OneToMany 和@ManyToOne:這三個(gè)注解相當(dāng)于 hibernate 配置文件中的一對(duì)一、一對(duì)多和多對(duì)一配置。例如,在以下客戶地址表中,可以通過(guò)客戶 ID 查詢客戶信息。
@Entity
@Table(name = "address")
public class AddressEO implements java.io.Serializable {
@ManyToOne(cascade = {CascadeType.ALL})
@JoinColumn(name = "customer_id")
private CustomerEO customer;
//... get、set
}
7. 異常處理相關(guān)注解
@ControllerAdvice 和@ExceptionHandler:它們通常一起使用來(lái)處理全局異常。示例代碼如下:
@Slf4j
@Configuration
@ControllerAdvice
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("統(tǒng)一異常處理器:", 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);
}
}
8. AOP 相關(guān)注解
- @Aspect:用于定義一個(gè)切面。切面是通知和切入點(diǎn)的組合,它定義了在何時(shí)何地應(yīng)用通知功能。
- @Before:表示前置通知。通知方法將在目標(biāo)方法調(diào)用之前執(zhí)行。通知描述了切面要執(zhí)行的工作以及執(zhí)行的時(shí)間。
- @After:表示后置通知。通知方法將在目標(biāo)方法返回或拋出異常后執(zhí)行。
- @AfterReturning:表示返回通知。通知方法將在目標(biāo)方法返回后執(zhí)行。
- @AfterThrowing:表示異常通知。通知方法將在目標(biāo)方法拋出異常后執(zhí)行。
- @Around:表示環(huán)繞通知。通知方法將包裝目標(biāo)方法,并在目標(biāo)方法調(diào)用前后執(zhí)行自定義行為。
- @Pointcut:定義切入點(diǎn)表達(dá)式,它定義了應(yīng)用通知功能的范圍。
- @Order:用于定義組件的執(zhí)行順序。在 AOP 中,它指的是切面的執(zhí)行順序。value 屬性的值越小,表示優(yōu)先級(jí)越高。 示例:
/**
* 統(tǒng)一日志處理切面
*/
@Aspect
@Component
@Order(1)
public class WebLogAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(WebLogAspect.class);
@Pointcut("execution(public * com.dylan.smith.web.controller.*.*(..))")
public void webLog() {
}
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
}
@AfterReturning(value = "webLog()", returning = "ret")
public void doAfterReturning(Object ret) throws Throwable {
}
@Around("webLog()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
WebLog webLog = new WebLog();
//...
Object result = joinPoint.proceed();
LOGGER.info("{}", JSONUtil.parse(webLog));
return result;
}
}
9. 測(cè)試相關(guān)注解
- @Test:指定一個(gè)方法為測(cè)試方法。
- @ActiveProfiles:一般應(yīng)用于測(cè)試類(lèi),用于聲明活動(dòng)的 Spring 配置文件。例如,指定 application - dev.properties 配置文件。
- @RunWith 和@SpringBootTest:一般應(yīng)用于測(cè)試類(lèi),用于單元測(cè)試。示例如下:
@ActiveProfiles("dev")
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestJunit {
@Test
public void executeTask() {
//...
}
}