每日一例 | 自定义注解简单应用
经常使用spring
相关框架的小伙伴肯定知道什么是注解,而且springboot
的配置很多都是通过注解直接注入的,今天我们就来看下如何定义自己的注解,然后通过它实现你自己的业务逻辑。
定义注解
这里简单介绍下,好多小伙伴可能已经忘记了注解方面的知识。
@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
的作用是指定注解起作用的时间,有运行时(runtime
),编译时(class
),源码(SOURCE
),只有运行时才会在运行时起作用。
注解是可以定义属性的,当然也可以不定义属性。
定义注解的关键字是@interface
。
简单应用
我们上面定义的注解是方法级的,所以只能加载方法上,下来我们加在方法上试一下。
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);
}
}
然后编写我们的处理器。注解的处理都是基于反射来实现的,所以这里我们的流程就是先获取目标类的所有方法,接着去获取方法上的注解,如果存在我们加的注解,就进行相应的业务处理。
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);
}
}
加注解的好处特别多,一个特别明显的好处就是可以实现业务解耦。有这样一个场景:你有一个接口的鉴权系统,但你并不是要对所有的业务接口进行鉴权,比如公共接口并不需要登陆,所以并不需要鉴权。如果不用注解的方式,随着系统的不断扩展,需要鉴权的接口越来越多,每次增加新的接口都需要修改配置文件,特别不方便,也繁琐;但如果是通过注解的方式实现的,那就很简单了,你只需要在新接口上增加鉴权注解即可,方便又灵活。突然发现,之前也发过:springboot拦截器解耦——自定义注解
上面说的这个场景也是我之前遇到过的,最终的解决方案就是通过注解方式,在拦截器内部校验注解。另外一个特别常用的应用场景就是实现业务去if-else
,特别是对于一些接口系统,二三十个接口,统一入口,需要根据接口请求参数的头部信息,选择调用对于的接口方法,看起来特别不友好:
int serviceNo;
if ("001".equals(serviceNo)) {
// ...
} else if ("002".equals(serviceNo)) {
// ...
} else if ("002".equals(serviceNo)) {
// ...
}
// ...
如果通过注解的方式,完全就可以干掉if-else
了:先扫描你加了注解的接口类,将业务编号与业务处理类建立对应关系(生成一个map
),调用对应业务的时候,从map
中拿到对应的交易处理类,然后处理并返回。这一块的应用,我前面已经写过了相关的实现方式,感兴趣的小伙伴可以去看看:还在用if-else,新的解耦方式你确定不了解下?
好了,今天就到这里吧!
项目路径:
https://github.com/Syske/example-everyday
本项目会每日更新,让我们一起学习,一起进步,遇见更好的自己,加油呀
- END -