Java筆記:常用的Spring Boot 註解

來源:https://segmentfault.com/a/1190000021669345

前言

本篇隨筆將對 Spring Boot 中的常用註解做一個簡單的整理歸檔,寫作順序將從啟動類開始並逐步向內外擴展,目的即為了分享也為了方便自己日後的回顧與查閱。

1. Application

啟動類示例如下:

<code>@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}/<code>

第一個要講解的註解是:@SpringBootApplication,從直觀的感受來看,他是 SpringApplication 能夠進入一系列複雜啟動流程的先決條件。進入源碼我們可以觀察到這是一個組合註解,其切面之上還有三個註解,分別為:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan。

@SpringBootConfiguration 中真正起作用的是 @Configuration,即標註當前類為 JavaConfig 配置類(這裡擴展一下,任何標註了 @Configuration 的類都為配置類,任何標註了 @Bean 的方法其返回值都是一個 Bean 的定義)。

@EnableAutoConfiguration 是構成上訴組合註解的核心,從名稱上就能獲取到淺顯的信息:啟用自動配置,他藉助 @Import 將所有符合條件的 @Configuration 配置都注入到 IoC 容器中,定義如下:

<code>@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class>[] exclude() default {}; String[] excludeName() default {};}/<code>

@ComponentScan 顧名思義,他會掃描帶有特定標註的組件(如 @Controller、@Component、@Service、@Repository),並將其注入到 IoC 容器中。

2. Test

測試類示例如下:

<code>@RunWith(SpringRunner.class)@SpringBootTestpublic class ApplicationTests { @Test public void contextLoads() { }}/<code>

@RunWith(SpringRunner.class) 翻譯一下就是使用 Spring 的 IoC 容器運行測試;@SpringBootTest 創建了 SpringApplication 的上下文;@Test 標註測試方法。在此推薦閱讀 “SpringBoot單元測試” ,寫得很詳細,我就不再贅述了,待有空補幾篇複雜測試的案例分析。

3. 基本註解

3.1 @Service & @Repository

他們是在 Spring Boot 中輕鬆實現面向接口編程的關鍵,一個用於邏輯層,一個用於數據層,示例如下:

<code>public interface HelloService { String notSay();}/<code>

<code>@Servicepublic class HelloServiceImpl implements HelloService { @Override public String notSay() { return "shut up"; }}/<code>

個人認為此處非常形象地體現了 “約定優於配置”,可以理解為 Spring Boot 默認配置了這麼一條 Bean:

<code><bean>/<code>

3.2 @Component

標註組件,可以作用在任何層次。

3.3 @Controller

控制器示例如下:

<code>@RestControllerpublic class HelloController { private final HelloService helloService; @Autowired public HelloController(HelloService helloService) { this.helloService = helloService; } @GetMapping("/{id}") public String say(@PathVariable("id") Integer id, @RequestParam("name") String name) { return (String.format("id=%d,name=%s;please %s", id, name, helloService.notSay())); }}/<code>

@RestController 查看源碼可觀察出其為 @Controller + @ResponseBody 的組合註解:

<code>@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Controller@ResponseBodypublic @interface RestController { @AliasFor(annotation = Controller.class) String value() default "";}/<code>

@GetMapping 其實就是對 @RequestMapping(method = RequestMethod.GET) 的進一步封裝,同理的還有 Post、Delete、Put 等等,不同類型的請求都有其對應封裝,能少打不少代碼。

其他的在示例中也一目瞭然了:@Autowired 自動轉配;@PathVariable 從 Url 中取值;@RequestParam 從參數中取值。

4. 異常處理

示例如下:

<code>@ControllerAdvicepublic class GlobalException { @ResponseBody @ExceptionHandler public String processException(Exception e) { return "error: " + e.getMessage(); }}/<code>

沒啥好說的,@ExceptionHandler 可以過濾具體的異常類型:@ExceptionHandler(Exception.class)

5. 配置

通過 @Value 可以直接拿到配置文件中的屬性,不過意義不是很大,例:

<code>@Value("${my.name}") private String name; /<code>

更多的時候應該去拿到一個對象,例:

<code>@Component@ConfigurationProperties(prefix = "my")public class My { private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; }}/<code>

@Profiles 按環境變量激活,我覺得很不是很好的解決方案,沒怎麼用過,示例:

<code>@profile("dev") @profile("prod") /<code>

Spring Boot 提倡約定優於配置,但有的時候我們不想守約,如下:

<code>@Configuration public class DbConfiguration { private final Db db; @Autowired public DbConfiguration(Db db) { this.db = db; } @Bean(name = "dataSource") public DataSource dataSource() { BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName(db.driverClassName); dataSource.setUrl(db.driverUrl); dataSource.setUsername(db.driverUsername); dataSource.setPassword(db.driverPassword); return dataSource; } @Bean public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(dataSource()); } } /<code>

6. 其他

@Qualifier 是為了解決一個接口對應多個實現的衝突,不過在設計上一般都會避免這種情況,所以不是很常用,示例:

<code>@Service("service1")public class HelloServiceImpl1 implements HelloService {}@Service("service2")public class HelloServiceImpl2 implements HelloService {}/<code>

<code>@Autowired@Qualifier("service1")HelloService helloService;/<code>

@Resource(name="name",type="type") 和 @Autowired 類似,不常用。