快来自定义一个属于你自己的java注解吧
java宝典
共 14038字,需浏览 29分钟
· 2021-05-21
“大家好,我是公众号:【java小杰要加油】,最近在项目中,发现了很多地方都用到了自定义注解, 根据自定义的注解,再去做一些个性化的操作,非常方便,今天来分享给大家
话不多说,直接开车
注解大致介绍
首先,让我们来声明一个注解
// 注解可以作用在哪里
@Target({ElementType.TYPE})
// 该注解的生命周期
@Retention(RetentionPolicy.RUNTIME)
// 指示默认情况下,带有类型的注释将由javadoc *和类似工具来记录
@Documented
// 可以继承父类注解
@Inherited
// bean
@Component
public @interface DIYClassAnnotation {
DIYEnum diyEnum();
// 年龄默认24 岁
int age() default 24;
}
可以注意到,我们声明的这个注解,他自己又带着很多元注解,我们依此来解释下,对应可取的值也如下
@Target : 指此注解可以标注在哪些地方,是字段?还是类?还是方法? TYPE :类,接口(包括注释类型)或枚举声明 FIELD:字段声明(包括枚举常量) METHOD:方法声明 PARAMETER:形式参数声明 CONSTRUCTOR:构造函数声明 LOCAL_VARIABLE:局部变量声明 ANNOTATION_TYPE:注释类型声明 PACKAGE:包声明 TYPE_PARAMETER:类型参数声明 TYPE_USE:使用类型 @Retention :指该注解的生命周期,存活在哪个阶段 SOURCE:批注将被编译器丢弃 CLASS:注释将由编译器记录在类文件中,但不必在运行时由VM保留。这是默认的行为。 RUNTIME:注释将由编译器记录在类文件中,并在运行时由VM保存*,因此可以通过反射方式读取它们 @Documented :指是默认情况下,带有类型的注释将由javadoc *和类似工具来记录 @Inherited :可以继承父类注解 里面的值只能用基本类型boolean、int、double、float、long、byte、short、char和String、Enum、Class以及一些其他注解
“我们一般写注解的时候。就是用图中上面那几个加粗颜色的属性和值
实战演练
“
其实使用这个自定义注解,千言万语就一句话
先声明一个自定义的注解 通过反射等方式取出这个注解,再根据这个注解中自己设定的值去做一些定制化的操作
本文将演示三种类型的自定义注解怎么用,平常开发也就这三种了(我接触的)
一、自定义类注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Component
public @interface DIYClassAnnotation {
// 自定义枚举类型
DIYEnum diyEnum();
// 年龄默认24 岁
int age() default 24;
}
看一下这个枚举类型
public enum DIYEnum {
xiaoJie("小杰","打代码"),
TEACHER("老师","教书"),
CHEF("厨师","做饭");
private String name;
private String worker;
DIYEnum(String name,String worker) {
this.name = name;
this.worker = worker;
}
public String getWorker() {
return worker;
}
public void setWorker(String worker) {
this.worker = worker;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
二、自定义字段注解
// 注解到什么地方 属性 上
@Target({ElementType.FIELD})
// 该注解的生命周期
@Retention(RetentionPolicy.RUNTIME)
// 指示默认情况下,带有类型的注释将由javadoc *和类似工具来记录
@Documented
// 可以继承父类注解
@Inherited
// bean
@Component
public @interface DIYFieldAnnotation {
// 性别
String sex();
}
三、自定义方法注解
// 注解到什么地方 方法 上
@Target({ElementType.METHOD})
// 该注解的生命周期
@Retention(RetentionPolicy.RUNTIME)
// 指示默认情况下,带有类型的注释将由javadoc *和类似工具来记录
@Documented
// 可以继承父类注解
@Inherited
// bean
@Component
public @interface DIYMethodAnnotation {
// 是否校验
int verification();
// 接口名称
String interfaceName();
}
其实我们注意到,感觉大家都大差不差啊,是的没错,也就是target作用域不一样罢了
我们自定义注解定义完了,下面要开始真正使用啦
定义个抽象父类Person
// 抽象父类
public abstract class Person {
public abstract void hobby();
}
定义学生Student子类
@DIYClassAnnotation(diyEnum = DIYEnum.xiaoJie,age=23 )
public class Student extends Person {
@DIYFieldAnnotation(sex = "男")
private String sex;
@Override
public void hobby() {
System.out.println(DIYEnum.xiaoJie.getWorker());
}
}
定义老师Teacher子类
@DIYClassAnnotation(diyEnum = DIYEnum.TEACHER,age=46 )
public class Teacher extends Person {
@DIYFieldAnnotation(sex = "女")
private String sex;
@Override
public void hobby() {
System.out.println(DIYEnum.TEACHER.getWorker());
}
}
定义厨师Chef子类
@DIYClassAnnotation(diyEnum = DIYEnum.CHEF,age=50 )
public class Chef extends Person {
@DIYFieldAnnotation(sex = "男")
private String sex;
@Override
public void hobby() {
System.out.println(DIYEnum.CHEF.getWorker());
}
}
再来一个注解工具类
public class DIYAnnotationUtils {
public static Person getPerson(Person ...persons){
for (Person person:persons) {
// 判断这个类是否有这个注解
if (person.getClass().isAnnotationPresent(DIYClassAnnotation.class)){
// 得到这个自定义的注解
DIYClassAnnotation workerAnnotation = person.getClass().getAnnotation(DIYClassAnnotation.class);
// 判断这个自定义注解注解的值是否是我们想要的
if (DIYEnum.xiaoJie.getName().equals(workerAnnotation.diyEnum().getName())){
// 反射得到这个对象的属性
Field[] fields = person.getClass().getDeclaredFields();
for (Field field:fields) {
// 如果这个字段有这个注解
if (field.isAnnotationPresent(DIYFieldAnnotation.class)){
// 打印出这个属性上有这个注解的值
DIYFieldAnnotation annotation = field.getAnnotation(DIYFieldAnnotation.class);
System.out.println(annotation.sex());
}
}
return person;
}
}
}
return null;
}
}
最主要的就是这个工具类(用到反射),其中根据传进来的对象判断符合不符合我们的要求 (注解时的名字是不是小杰),如果符合的话,把注解在属性上的注解拿出来
我们通过测视类来调用一下
public class Test {
public static void main(String[] args) {
Student student =new Student();
Chef chef = new Chef() ;
Teacher teacher = new Teacher();
Person person = DIYAnnotationUtils.getPerson(student, chef, teacher);
if (person != null){
person.hobby();
}
}
}
输出结果是
男
打代码
下面我们来演示下怎么在方法上使用这注解,最常见的组合就是自定义注解+AOP
下面来看下controller
@RestController
public class Controller {
// 此方法需要校验
@DIYMethodAnnotation(verification = 1,interfaceName = "学生爱好接口")
@RequestMapping("/verification")
public String verificationMethod(String id){
new Student().hobby();
return "校验";
}
// 此方法不需要校验
@DIYMethodAnnotation(verification = 0,interfaceName = "老师爱好接口")
@RequestMapping("/noVerification")
public String noVerificationMethod(String id){
new Teacher().hobby();
return "不校验";
}
// 此方法没有注解
@RequestMapping("/noAnnotation")
public String noAnnotationMethod(String id){
new Chef().hobby();
return "无注解";
}
}
再看下切面类 本文注重讲解注解,这个切面类还有很多完善的地方不过不在本文范围内
@Component
@Aspect
public class LogAspect {
// 注解的位置
@Pointcut("@annotation(com.example.demo.annotation.DIYMethodAnnotation)")
public void diyPointCut(){};
@Around("diyPointCut()")
public Object diyAround(ProceedingJoinPoint joinPoint){
//获得被增强的方法相关信息
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
// 获得这个方法
Method method = signature.getMethod();
// 获得这个方法上面的注解
DIYMethodAnnotation diyMethodAnnotation = method.getAnnotation(DIYMethodAnnotation.class);
// 根据注解自定义的一些属性去做自定义的操作
if (diyMethodAnnotation.verification() == 1){
System.out.println("当前校验的是:"+diyMethodAnnotation.interfaceName());
System.out.println("方法名称是:"+method.getName());
System.out.println("传递参数是:"+JSON.toJSONString(joinPoint.getArgs()));
}
System.out.println("aop 拦截器里 verification:"+diyMethodAnnotation.verification() );
try {
return joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
return null;
}
}
}
我们将项目跑起来,分别访问两个打了注解的接口
需要校验的接口
http://localhost:8081/verification?id=1
当前校验的是:学生爱好接口
方法名称是:verificationMethod
传递参数是:["1"]
aop 拦截器里 verification:1
打代码
不需要校验的接口
http://localhost:8081/noVerification?id=1
aop 拦截器里 verification:0
做饭
没有注解的接口
http://localhost:8081/noAnnotation?id=1
做饭
由输出结果可以得出一个结论,
没有注解的接口,走不到AOP,因为我们AOP配置的是只有注解的接口才进行AOP校验, 如果接口上有注解的话,又有两种情况(这是我们自己设置的) 输出 ”当前校验的是,方法名称是,传递参数是 verification 0 的时候 这个注解也不进行特别的操作 verification 1 的时候 这个注解进行特别的操作
“综上所述,我们在日常开发中,如果对某个类/字段/方法有什么特殊的要求的话,可以使用自定义注解,再通过反射获取到此注解,再根据这个注解中自定义的值在进行我们自定义的操作
好文推荐
最后
再贴一张最近火爆全网同时也对我触动很大的话
自助者,天助之
“我是【java小杰要加油】,欢迎大家关注,有什么想说的想看的评论区里留言呀,我们下期见。
评论
一个朋友
一个朋友,在深圳奋斗7年,和女友在去年合力在龙华买了一套房,总价600万,首付3成。但就在昨天,他们崩溃了。深圳推出可售型人才住房,就在他们新房附近,同样面积,总价不到400万,售价近乎腰斩。他们想不明白,同样是深圳人,买房人为什么都要被当成炒房客对待?二手房冰封,卖不出,新房不断打着,像极了上世纪
嵌入式Linux
0
真高!比亚迪员工爆料比亚迪在越南的薪资水平:基本工资480万,全勤奖35万,交通补助20万,餐补110万,每周6天,每天10小时
上一篇:某大公司为逼迫员工离职,竟然把他的工位安排到厕所旁,没想到他直接开始记录领导的如厕时间,还发到公司大群...对此,你怎么看?--完--PS:欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,欢迎转发分享给更多人。全文完,感谢你的耐心阅读。如果你还想看到我的文章,请一定给本
开发者全社区
0
太敢穿了!透视纱裙!性感火辣的身材
绝了呀今天的厂花:吴宣仪1995年1月26日,吴宣仪出生于海南省海口市,中国内地流行乐女歌手、影视演员。2016年2月,吴宣仪随宇宙少女发行首张迷你专辑正式出道。2018年4月,她参加《创造101》综艺选秀,获得第二名,成功加入火箭少女101组合。吴宣仪的颜值一直备受称赞,她的五官立体精致,皮肤白皙
逆锋起笔
0
某大公司为逼迫员工离职,竟然把他的工位安排到厕所旁,没想到他直接开始记录领导的如厕时间,还发到公司大群...
上一篇:字节的跳动职级与薪资(2024年)我们与公司间的合作,宛如两艘船只在茫茫大海上相互依靠,共同抵御风浪,携手驶向成功的彼岸。然而,当航向开始产生分歧,或是波涛汹涌的风浪改变了我们的初衷,我们或许应当冷静地选择和平分手,而非在风雨中硬撑。最近,一位网友的遭遇引起了广大职场人的关注和热议。这位网友
开发者全社区
0
金融研究 | 使用Python测量关键审计事项的「信息含量」
Tips: 公众号推送后内容只能更改一次,且只能改20字符。如果内容出问题,或者想更新内容, 只能重复推送。为了更好的阅读体验,建议阅读本文博客版, 链接地址https://textdata.cn/blog/2023-01-13-information-content-of-critical-aud
大邓和他的Python
0
我看阿里的年终奖总算发了!
到4月底了,这两天看朋友圈,发现阿里的年终奖终于发了,问了问老同学,也从网上检索了不少信息,基本搞清楚了阿里今年的年终奖情况。近来来阿里一些集团对绩效等级做了较大的调整,以前的旧绩效系统中,绩效分为3.25、3.5、3.75、4和5五个等级,其中4和5是较高绩效等级,较少见。而且之前3.5绩效内部划
公子龙
0
CVPR 2024|大视觉模型的开山之作!无需任何语言数据即可打造大视觉模型
↑ 点击蓝字 关注极市平台作者丨科技猛兽编辑丨极市平台极市导读 本文提出一种序列建模 (sequential modeling) 的方法,不使用任何语言数据,训练大视觉模型。>>加入极市CV技术交流群,走在计算机视觉的最前沿本文目录1 序列建模打造大视觉模型(来自 U
极市平台
1
金融研究(更新) | 使用Python构建关键审计事项的「信息含量」
Tips: 公众号推送后内容只能更改一次,且只能改20字符。如果内容出问题,或者想更新内容, 只能重复推送。为了更好的阅读体验,建议阅读本文博客版, 链接地址https://textdata.cn/blog/2023-01-13-information-content-of-critical-aud
大邓和他的Python
0