
1. 前言
Java 1.5 引入了注解,極大的友善了将中繼資料添加到 Java 代碼中,簡化了開發。現在很多架構都嚴重依賴 Java 注解,尤其是 Spring 架構,很多面試者都把這個作為 Spring 架構的一個特色,雖然不夠貼切,但是也不是沒有一點道理。在本文中,我們将介紹一個非常有用的 Spring 特性,該功能允許我們基于一個或多個 Spring 注解建立自己的注解。
2. 複合注解
我們在 Spring 開發中也經常用到一些注解,而且有些注解會高頻率的一起使用來完成一些邏輯。我們一遍又一遍的重複使用這兩個注解。我們的代碼上寫滿了注解,看起來非常笨重。我們如何來簡化對它們的使用呢?接下來我們來研究一下。
請注意本文講的是 Spring 的特性,而不是 Java 提供的功能。如果将其他架構和庫的注解添加到你自定義的複合注解中可能無法正常工作。
2.1 最簡單的寫法
比如我們經常使用
@Service
和
@Transactional
組合來進行服務層的邏輯開發。事實上我們可以建立一個複合注解來把一些注解 “捆綁” 到一起。
@Service
@Transactional(rollbackFor = Exception.class,timeout=5)
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface TransactionalService {
}
然後我們就能使用我們自定義的來對服務類進行标記:
@TransactionalService
public class YourService {
//todo your business
}
跟我們使用
@Service
@Transactional
一樣的效果。
2.2 進階寫法
章節 2.1 提供的例子中如果我們希望
@Transactional
的另一個屬性
timeout
在使用時保證多樣性而不是固定的值
5
怎麼辦?我們來研究一下這個客觀存在的需求。
會 Spring MVC 的都知道
@GetMapping
是
@RequestMapping(method = {RequestMethod.GET})
的縮寫。
package org.springframework.web.bind.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping {
/**
* Alias for {@link RequestMapping#name}.
*/
@AliasFor(annotation = RequestMapping.class)
String name() default "";
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] value() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] path() default {};
/**
* Alias for {@link RequestMapping#params}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] params() default {};
/**
* Alias for {@link RequestMapping#headers}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] headers() default {};
/**
* Alias for {@link RequestMapping#consumes}.
* @since 4.3.5
*/
@AliasFor(annotation = RequestMapping.class)
String[] consumes() default {};
/**
* Alias for {@link RequestMapping#produces}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] produces() default {};
}
從上面可以看到,我們通過在
@GetMapping
上聲明
@RequestMapping
的
method
屬性,其它屬性通過
@AliasFor
來進行處理(有點覆寫的味道)讓開發者使用時可以對其它屬性進行聲明。這樣就完成了一個特殊的
@RequestMapping
。
在 Spring 中我們使用這種方式的的複合注解還有
@RestController
您可以通過檢視 Spring 源代碼中這些注釋的定義來自己驗證。
@SpringBootApplication