Java 小記 — Spring Boot 註解
前言
本篇隨筆將對 Spring Boot 中的常用註解做一個簡單的整理歸檔,寫作順序將從啟動類開始並逐步向內外擴展,目的即為了分享也為了方便自己日後的回顧與查閱。
1. Application
啟動類示例如下:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
第一個要講解的註解是:@SpringBootApplication,從直觀的感受來看,他是 SpringApplication 能夠進入一系列復雜啟動流程的先決條件。進入源碼我們可以觀察到這是一個組合註解,其切面之上還有三個註解,分別為:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan。
@SpringBootConfiguration 中真正起作用的是 @Configuration,即標註當前類為 JavaConfig 配置類(這裏擴展一下,任何標註了 @Configuration 的類都為配置類,任何標註了 @Bean 的方法其返回值都是一個 Bean 的定義)。
@EnableAutoConfiguration 是構成上訴組合註解的核心,從名稱上就能獲取到淺顯的信息:啟用自動配置,他借助 @Import 將所有符合條件的 @Configuration 配置都註入到 IoC 容器中,定義如下:
@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 {};
}
@ComponentScan 顧名思義,他會掃描帶有特定標註的組件(如 @Controller、@Component、@Service、@Repository),並將其註入到 IoC 容器中。
2. Test
測試類示例如下:
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {
@Test
public void contextLoads() {
}
}
@RunWith(SpringRunner.class) 翻譯一下就是使用 Spring 的 IoC 容器運行測試;@SpringBootTest 創建了 SpringApplication 的上下文;@Test 標註測試方法。在此推薦閱讀 “SpringBoot單元測試” ,寫得很詳細,我就不再贅述了,待有空補幾篇復雜測試的案例分析。
3. 基本註解
3.1 @Service & @Repository
他們是在 Spring Boot 中輕松實現面向接口編程的關鍵,一個用於邏輯層,一個用於數據層,示例如下:
public interface HelloService {
String notSay();
}
@Service
public class HelloServiceImpl implements HelloService {
@Override
public String notSay() {
return "shut up";
}
}
個人認為此處非常形象地體現了 “約定優於配置”,可以理解為 Spring Boot 默認生成了這麽一條 Bean:
<bean id="HelloService" class="com.youclk.annotation.service.impl.HelloServiceImpl"></bean>
3.2 @Component
標註組件,可以作用在任何層次。
3.3 @Controller
控制器示例如下:
@RestController
public 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()));
}
}
@RestController 查看源碼可觀察出其為 @Controller + @ResponseBody 的組合註解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
@AliasFor(annotation = Controller.class)
String value() default "";
}
@GetMapping 其實就是對 @RequestMapping(method = RequestMethod.GET) 的進一步封裝,同理的還有 Post、Delete、Put 等等,不同類型的請求都有其對應封裝,能少打不少代碼。
其他的在示例中也一目了然了:@Autowired 自動轉配;@PathVariable 從 Url 中取值;@RequestParam 從參數中取值。
4. 異常處理
示例如下:
@ControllerAdvice
public class GlobalException {
@ResponseBody
@ExceptionHandler
public String processException(Exception e) {
return "error: " + e.getMessage();
}
}
沒啥好說的,@ExceptionHandler 可以過濾具體的異常類型:@ExceptionHandler(Exception.class)
5. 配置
通過 @Value 可以直接拿到配置文件中的屬性,不過意義不是很大,例:
@Value("${my.name}")
private String name;
更多的時候應該去拿到一個對象,例:
@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;
}
}
@Profiles 按環境變量激活,我覺得很不是很好的解決方案,沒怎麽用過,示例:
@profile("dev")
@profile("prod")
Spring Boot 提倡約定優於配置,但有的時候我們不想守約,如下:
@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());
}
}
6. 其他
@Qualifier 是為了解決一個接口對應多個實現的沖突,不過在設計上一般都會避免這種情況,所以不是很常用,示例:
@Service("service1")
public class HelloServiceImpl1 implements HelloService {
}
@Service("service2")
public class HelloServiceImpl2 implements HelloService {
}
@Autowired
@Qualifier("service1")
HelloService helloService;
@Resource(name="name",type="type") 和 @Autowired 類似,不常用。
結語
近期正在尋覓新的工作機會,若有意向,歡迎留言,微信: youclk。
Java 小記 — Spring Boot 註解