java注解:如何实现和使用一个自定义注解?

java中注解在java中的应用非常广泛,如override、supperwarning等等注解,框架中的注解应用更为广泛,主流框架基本都有自己的注解体系,今天想总结和学习一下注解的相关知识,第一篇将介绍如何实现一个注解,第二篇将介绍如何应用一个注解。

1,注解有什么用? 注解的作用基本有三个:
.生成文档。这是最常见的,也是java 最早提供的注解。常用的有 @see @param @return 等
.跟踪代码依赖性,实现替代配置文件功能。比较常见的是spring 2.5 开始的基于注解配置。作用就是减少配置。现在的框架基本都使用了这种配置来减少配置文件的数量。也是
.在编译时进行格式检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。

2,实现一个最简单的注解:

@Retention(RetentionPolicy.RUNTIME)
public @interface MyTarget {
}

上面是一个最简单的注解实现,没有定义任何的属性,其中需要注意的是@Retention(RetentionPolicy.RUNTIME)是定义注解所必须的。
@Retention是注解的注解,称为注解的元注解。括号里有一个枚举类型的值,即为注解内部定义的值。打开Retention的实现:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    RetentionPolicy value();
}

可以看到这里定义了一个变量value并且没有缺省值,所以不写这个value就会报错。 继续打开RetentionPolicy:

public enum RetentionPolicy {
    SOURCE,
    CLASS,
    RUNTIME
}

可以发现这个枚举类定义了三个值,这三个值分别代表的是我们定义的MyTarget如何保持。
用@Retention(RetentionPolicy.CLASS)修饰的注解,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,但不会被虚拟机读取在运行的时候;
用@Retention(RetentionPolicy.SOURCE )修饰的注解,表示注解的信息会被编译器抛弃,不会留在class文件中,注解的信息只会留在源文件中;
用@Retention(RetentionPolicy.RUNTIME )修饰的注解,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,会被虚拟机保留在运行时,

还需要注意的是java的元注解一共有四个:
@Document
@Target
@Retention
@Inherited

各个的作用,读者自己查一下吧。无论如何我们实现了一个最简单的注解MyTarget,下面进行简单的测试:

    @MyTarget
    public void doSomething() { }

    @Resource
    public static void main(String[] args) throws Exception
    {
        Method method = MyTargetTest.class.getMethod("doSomething",null);
       if(method.isAnnotationPresent(MyTarget.class))
        {                              System.out.println(method.getAnnotation(MyTarget.class));
        }
    }

运行上面的测试会打出一句话:

@annotations.MyTarget()

其中

if(method.isAnnotationPresent(MyTarget.class))

可以判断出方法是是不是存在MyTarget的注解,能打印出这句话证明我们写的确实是一个注解。

二:注解中的属性定义

上面的内容我们实现了一个最简单的注解,但是这个注解基本是没有什么功能的,java注解的功能实现基本是通过定义属性实现的(真正实现功能有相关的处理类,处置这些属性,我们先来定义属性)。注解处理器类库(java.lang.reflect.AnnotatedElement):

AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通过反射获取了某个类的AnnotatedElement对象之后,程序就可以调用该对象的如下四个个方法来访问Annotation信息:

  
注解处理的一个基础:

方法1:<T extends Annotation> T getAnnotation(Class<T> annotationClass): 返回改程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null。
  方法2:Annotation[] getAnnotations():返回该程序元素上存在的所有注解。
  方法3:boolean is AnnotationPresent(Class<?extends Annotation> annotationClass):判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false.
  方法4:Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。

j

注解定义属性不同于java,看一下上面的Retention的定义属性方式:

 RetentionPolicy value();

这基本就是注解定义属性的方式,类似于java中定义方法,可以设置缺省值,即用注解的时候缺省值是可以不写的。

我们来看一下注解的功能之一: 为属性赋值,我们定义三个注解:

@Retention(RetentionPolicy.RUNTIME)
public @interface CarSalerTarget {
    public String salerName();
    public int age() default  1;
}
@Retention(RetentionPolicy.RUNTIME)
public @interface CarNameTarget {
    String name() default  "";
}
@Retention(RetentionPolicy.RUNTIME)
public @interface CarSalerTarget {
    public String salerName();
    public int age() default  1;
}

都是汽车相关的信息,中文名,英文名,销售员信息; 下面我们定义一个奔驰汽车的类,试着用注解进行赋值:

public class BnechCar {
    @CarNameTarget(name="奔驰")
    private String name;

    @CarTypeTarget(carType= CarTypeTarget.Type.benchi)
    private String type;

    @CarSalerTarget(salerName="wpz",age=22)
    private String salerInfo;
}

这样其实就定义和赋值完成了,我们搞一个中间类来打印一下信息:

/**
 * Created by wangpengzhi1 on 2017/9/29.
 */
public class CarInfoUtil {
    public static void getFruitInfo(Class<?> clazz){
        Field[] fields = clazz.getDeclaredFields();
        for(Field field :fields){
            if(field.isAnnotationPresent(CarNameTarget.class)){
                CarNameTarget name = (CarNameTarget) field.getAnnotation(CarNameTarget.class);
                String carColour ="汽车的中文名:"+name.name();
                System.out.println(carColour);
            }
            else if(field.isAnnotationPresent(CarTypeTarget.class)){
                CarTypeTarget type= (CarTypeTarget) field.getAnnotation(CarTypeTarget.class);
                String carType="汽车的类型:"+type.carType().toString();
                System.out.println(carType);
            }
            else if(field.isAnnotationPresent(CarSalerTarget.class)){
                CarSalerTarget saler= (CarSalerTarget) field.getAnnotation(CarSalerTarget.class);
                String salerInfo=" 销售员姓名:"+saler.salerName()+" 销售员年龄:"+ saler.age();
                System.out.println(salerInfo);
            }
        }
    }
}

这个类其实就是根据注解获取属性的值。

测试类:

 @Test
    public void testTarget(){
          CarInfoUtil.getFruitInfo(BnechCar.class);
    }

打印信息:

汽车的中文名:奔驰
汽车的类型:benchi
销售员姓名:wpz 销售员年龄:22

看的出注解为属性赋值是成功的。利用上面的处理方式基本就可以理解了框架中使用注解如何进行DI的操作了。

java 注解的知识网络:
这里写图片描述

java技术交流群:255453635 备注:CSDN

  • 27
    点赞
  • 151
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 31
    评论
实现一个SpringBoot自定义注解,可以按照以下步骤进行: 1. 定义注解Java代码中定义一个注解,可以使用@Target、@Retention等元注解来指定注解的作用目标和生命周期,例如: ``` @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String value() default ""; } ``` 上述代码定义了一个@MyAnnotation注解,作用目标为方法,生命周期为运行时,注解中有一个value属性默认为空字符串。 2. 使用注解 在需要使用注解的地方,例如类、方法、字段等上面使用注解,例如: ``` @RestController public class MyController { @MyAnnotation("hello") @RequestMapping("/hello") public String hello() { return "Hello World!"; } } ``` 上述代码中,在MyController类上使用了@RestController注解,而在hello方法上使用了@MyAnnotation注解,并指定value属性为"hello"。 3. 解析注解 在需要解析注解的地方,例如在拦截器、切面、过滤器等中,可以使用反射机制来获取注解信息,例如: ``` @Aspect @Component public class MyAspect { @Around("@annotation(MyAnnotation)") public Object around(ProceedingJoinPoint pjp) throws Throwable { MethodSignature signature = (MethodSignature) pjp.getSignature(); Method method = signature.getMethod(); MyAnnotation annotation = method.getAnnotation(MyAnnotation.class); if (annotation != null) { String value = annotation.value(); // do something with value } return pjp.proceed(); } } ``` 上述代码中,使用@Around注解定义了一个环绕通知,拦截被@MyAnnotation注解标记的方法,并使用反射获取注解信息。 综上所述,实现一个SpringBoot自定义注解需要定义注解使用注解和解析注解三个步骤。
评论 31
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

专注网赚的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值