每日一例 | 自定義注解簡單應(yīng)用
經(jīng)常使用spring相關(guān)框架的小伙伴肯定知道什么是注解,而且springboot的配置很多都是通過注解直接注入的,今天我們就來看下如何定義自己的注解,然后通過它實(shí)現(xiàn)你自己的業(yè)務(wù)邏輯。
定義注解
這里簡單介紹下,好多小伙伴可能已經(jīng)忘記了注解方面的知識。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
public int id();
public String description() default "no description";
}
@Target和@Retention叫元注解,是jdk1.5開始引入的。target的作用是指定可以注解的類型,這里的類型有方法、類、屬性等(具體的自己去了解,1.8又增加了新的類型);
Retention的作用是指定注解起作用的時間,有運(yùn)行時(runtime),編譯時(class),源碼(SOURCE),只有運(yùn)行時才會在運(yùn)行時起作用。
注解是可以定義屬性的,當(dāng)然也可以不定義屬性。
定義注解的關(guān)鍵字是@interface。
簡單應(yīng)用
我們上面定義的注解是方法級的,所以只能加載方法上,下來我們加在方法上試一下。
public class PasswordUtils {
@UseCase(id = 47, description = "Passwords must contain at least one numeric")
public boolean validatePassword(String password) {
return (password.matches("\\w*\\d\\w*"));
}
@UseCase(id = 48)
public String encryptPassword(String password) {
return new StringBuilder(password).reverse().toString();
}
@UseCase(id = 49, description = "New passwords can't equal previously used ones")
public boolean checkForNewPassword(List<String> prevPasswords, String password) {
return !prevPasswords.contains(password);
}
}
然后編寫我們的處理器。注解的處理都是基于反射來實(shí)現(xiàn)的,所以這里我們的流程就是先獲取目標(biāo)類的所有方法,接著去獲取方法上的注解,如果存在我們加的注解,就進(jìn)行相應(yīng)的業(yè)務(wù)處理。
public class UseCaseTracker {
public static void trackUseCases(List<Integer> useCases, Class<?> cl) {
for (Method declaredMethod : cl.getDeclaredMethods()) {
UseCase uc = declaredMethod.getAnnotation(UseCase.class);
if (uc != null) {
System.out.println("Found Use Case:" + uc.id() + " " + uc.description());
useCases.remove(new Integer(uc.id()));
}
}
for (Integer useCase : useCases) {
System.out.println("Warning: Missing use case-" + useCase);
}
}
public static void main(String[] args) {
List<Integer> useCases = new ArrayList<>();
Collections.addAll(useCases, 47, 48, 49, 50);
trackUseCases(useCases, PasswordUtils.class);
}
}
加注解的好處特別多,一個特別明顯的好處就是可以實(shí)現(xiàn)業(yè)務(wù)解耦。有這樣一個場景:你有一個接口的鑒權(quán)系統(tǒng),但你并不是要對所有的業(yè)務(wù)接口進(jìn)行鑒權(quán),比如公共接口并不需要登陸,所以并不需要鑒權(quán)。如果不用注解的方式,隨著系統(tǒng)的不斷擴(kuò)展,需要鑒權(quán)的接口越來越多,每次增加新的接口都需要修改配置文件,特別不方便,也繁瑣;但如果是通過注解的方式實(shí)現(xiàn)的,那就很簡單了,你只需要在新接口上增加鑒權(quán)注解即可,方便又靈活。突然發(fā)現(xiàn),之前也發(fā)過:springboot攔截器解耦——自定義注解
上面說的這個場景也是我之前遇到過的,最終的解決方案就是通過注解方式,在攔截器內(nèi)部校驗(yàn)注解。另外一個特別常用的應(yīng)用場景就是實(shí)現(xiàn)業(yè)務(wù)去if-else,特別是對于一些接口系統(tǒng),二三十個接口,統(tǒng)一入口,需要根據(jù)接口請求參數(shù)的頭部信息,選擇調(diào)用對于的接口方法,看起來特別不友好:
int serviceNo;
if ("001".equals(serviceNo)) {
// ...
} else if ("002".equals(serviceNo)) {
// ...
} else if ("002".equals(serviceNo)) {
// ...
}
// ...
如果通過注解的方式,完全就可以干掉if-else了:先掃描你加了注解的接口類,將業(yè)務(wù)編號與業(yè)務(wù)處理類建立對應(yīng)關(guān)系(生成一個map),調(diào)用對應(yīng)業(yè)務(wù)的時候,從map中拿到對應(yīng)的交易處理類,然后處理并返回。這一塊的應(yīng)用,我前面已經(jīng)寫過了相關(guān)的實(shí)現(xiàn)方式,感興趣的小伙伴可以去看看:還在用if-else,新的解耦方式你確定不了解下?
好了,今天就到這里吧!
項(xiàng)目路徑:
https://github.com/Syske/example-everyday
本項(xiàng)目會每日更新,讓我們一起學(xué)習(xí),一起進(jìn)步,遇見更好的自己,加油呀
- END -