java自定义注解

前言

Java注解又称Java标注,是Java语言5.0版本开始支持加入源代码的特殊语法元数据。为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便的使用这些数据。
Java语言中的类、方法、变量、参数和包等都可以被标注。和Javadoc不同,Java标注可以通过反射获取注解内容。在编译器生成类文件时,注解可以被嵌入到字节码中。Java虚拟机可以保留注解内容,在运行时可以获取到注解内容

内置注解

java本身提供了7个内置注解,3个在java.lang包,还有4个在java.lang.annotation 中

作用在代码的注解是

@Override

检查方法是不是重写方法,如果父类或实现接口中没有定义就编译报错 |

@Deprecated

不推荐使用这个方法有更好的替代品,就像一起jdk写的方法过时了就使用这个标记了一下

@SuppressWarnings

指示编译器去忽略注解中声明的警告

元注解

就是只有我们写注解类才能使用的注解

@Retention

指定存储的方式
RetentionPolicy.SOURCE - 标记的注释仅保留在源级别中(源文件),并由编译器忽略。
RetentionPolicy.CLASS - 标记的注释在编译时由编译器保留,但Java虚拟机(JVM)不保存
RetentionPolicy.RUNTIME - 标记的注释由JVM保留,因此运行时环境可以通过反射动态获取

@Documented

无论何时使用指定的注释,都应使用Javadoc工具记录这些元素。(默认情况下,注释不包含在Javadoc中。)有关更多信息,请参阅 Javadoc工具页面。

@Target

就像限制使用注解的类型,给的这个注解比如是否可以在类上面使用,方法说明使用等等。有如下阐述
ElementType.TYPE 可以应用于类的任何元素
ElementType.FIELD 可以应用于字段或属性
ElementType.METHOD 可以应用于方法级注释
ElementType.PARAMETER 可以应用于方法的参数
ElementType.CONSTRUCTOR 可以应用于构造函数
ElementType.LOCAL_VARIABLE 可以应用于局部变量
ElementType.ANNOTATION_TYPE 可以应用于注释类型
ElementType.PACKAGE 可以应用于包声明、

@Inherited

@Inherited 注释表明注释类型可以从超类继承。当用户查询注释类型并且该类没有此类型的注释时,将查询类的超类以获取注释类型(默认情况下不是这样)。此注释仅适用于类声明。

请参考:https://www.jianshu.com/p/7f54e7250be3

@Repeatable

java8才有的,有@Repatable标记的注解 可以重复在同一个类、方法、属性等上使用

自定义注解示列(小试牛刀)

如何自定义注解?

使用@interface关键字, 其定义过程与定义接口非常类似, 需要注意的是:

Annotation的成员变量在Annotation定义中是以无参的方法形式来声明的, 其方法名和返回值类型定义了该成员变量的名字和类型,

而且我们还可以使用default关键字为这个成员变量设定默认值;

/**
 * 这是自定义注解的定义和接口i很像
 * @author 20190313
 *
 */
@Documented
//标记的注释由JVM保留,因此运行时环境可以使用它。
@Retention(RetentionPolicy.RUNTIME)
//可以应用于类的任何元素
@Target({ElementType.TYPE})
public @interface SPI {
	//value将成为注解的阐述,如果不传入该阐述默认值为default指定的就是“”啦
	String value() default "我是默认值";
}

注意:只有名字为“value”属性,赋值时可以省略属性名

Student使用注解

public class Student {
	//添加注解 并传入value值
	@FieldName(value = "姓名")//下方省略了get/set方法
	private String name;
	//这里并没有传入value参数,所以使用的是默认的
	@FieldName()
	private String pwd;

测试一下

	    for (Field m : Student.class.getDeclaredFields()) {
	        //获取注解对象
	    	FieldName fieldName = m.getAnnotation(FieldName.class);
	    	//如果fieldName不为空就说明属性加了这个注解
	    	if(fieldName != null) {
	    		System.out.println("value值为:"+fieldName.value());
	    	}
	    }

结果:

value值为:姓名
value值为:我是默认值

案例 : 获取类与方法上的注解值:

package com.cpc.annotation.p1;

/**
 * @Description:
 * @Author: cpc
 * @Date: 2019-11-06 15:20
 * @Version: V1.0
 */
public enum  TranscationModel {
    Read, Write, ReadWrite
}
package com.cpc.annotation.p1;

import java.lang.annotation.*;

/**
 * @Description:
 * @Author: cpc
 * @Date: 2019-11-06 15:21
 * @Version: V1.0
 */
//这是说明这个注解可以使用在啥子地方(类、属性、方法)
@Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD})
//注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Retention(RetentionPolicy.RUNTIME)
//指定被修饰的该Annotation可以被javadoc工具提取成文档.
@Documented
public @interface  MyAnnotation1 {
    String name();
}
package com.cpc.annotation.p1;

import java.lang.annotation.*;

/**
 * @Description:
 * @Author: cpc
 * @Date: 2019-11-06 15:22
 * @Version: V1.0
 *
 *  MyAnnotation2注解可以用在方法上
 *  注解运行期也保留
 *  不可继承
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation2 {
    TranscationModel model() default TranscationModel.ReadWrite;
}
package com.cpc.annotation.p1;

import java.lang.annotation.*;

/**
 * @Description:
 * @Author: cpc
 * @Date: 2019-11-06 15:24
 * @Version: V1.0
 *
 * MyAnnotation3注解可以用在方法上
 * 注解运行期也保留
 * 可继承
 */
@Target(ElementType.METHOD)
//这是保存到运行期
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation3 {
    TranscationModel[] models() default TranscationModel.ReadWrite;
}
package com.cpc.annotation.p1;

/**
 * @Description:
 * @Author: cpc
 * @Date: 2019-11-06 15:24
 * @Version: V1.0
 *
 * 获取类与方法上的注解值
 */
@MyAnnotation1(name = "abc")
public class Demo1 {
    @MyAnnotation1(name = "xyz")
    private Integer age;
    @MyAnnotation2(model = TranscationModel.Read)
    public void list() {
        System.out.println("list");
    }
    @MyAnnotation3(models = {TranscationModel.Read, TranscationModel.Write})
    public void edit() {
        System.out.println("edit");
    }
}
package com.cpc.annotation.p1;

import org.junit.jupiter.api.Test;

/**
 * @Description:
 * @Author: cpc
 * @Date: 2019-11-06 15:26
 * @Version: V1.0
 */
public class Demo1Test {
    @Test
    public void list() throws Exception {
//        获取类上的注解
        MyAnnotation1 annotation1 = Demo1.class.getAnnotation(MyAnnotation1.class);
        System.out.println(annotation1.name());//abc

//        获取方法上的注解
        MyAnnotation2 myAnnotation2 = Demo1.class.getMethod("list").getAnnotation(MyAnnotation2.class);
        System.out.println(myAnnotation2.model());//Read

    }

    @Test
    public void edit() throws Exception {
        //这是获取方法上的注解
        MyAnnotation3 myAnnotation3 = Demo1.class.getMethod("edit").getAnnotation(MyAnnotation3.class);
        //这是拿到注解的属性并且输出
        for (TranscationModel model : myAnnotation3.models()) {
            System.out.println(model);//Read,Write
        }
    }
}

案例二:获取类属性上的注解属性值

package com.cpc.annotation.p2;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Description:
 * @Author: cpc
 * @Date: 2019-11-06 15:29
 * @Version: V1.0
 */
//@Retention(RetentionPolicy.SOURCE)
//保存到运行事件
@Retention(RetentionPolicy.RUNTIME)
//这是可以应用到属性上
@Target(ElementType.FIELD)
public  @interface TestAnnotation {
    String value() default "默认value值";

    String what() default "这里是默认的what属性对应的值";

}
package com.cpc.annotation.p2;

/**
 * @Description:
 * @Author: cpc
 * @Date: 2019-11-06 15:30
 * @Version: V1.0
 *
 * 获取类属性上的注解属性值
 *
 */
public class Demo2 {

    @TestAnnotation(value = "这就是value对应的值_msg1", what = "这就是what对应的值_msg1")
    private static String msg1;

    @TestAnnotation("这就是value对应的值1")
    private static String msg2;

    @TestAnnotation(value = "这就是value对应的值2")
    private static String msg3;

    @TestAnnotation(what = "这就是what对应的值")
    private static String msg4;

}
package com.cpc.annotation.p2;

import org.junit.jupiter.api.Test;

/**
 * @Description: 这是获取到类属性上的注解值
 * @Author: cpc
 * @Date: 2019-11-06 15:30
 * @Version: V1.0
 */
public class Demo2Test {

    @Test
    public void test1() throws Exception {
        //这是获取 Demo2 这个类上的 msg1 字典的 TestAnnotation 注解对象 
        TestAnnotation msg1 = Demo2.class.getDeclaredField("msg1").getAnnotation(TestAnnotation.class);
        System.out.println(msg1.value());
        System.out.println(msg1.what());
    }

    @Test
    public void test2() throws Exception{
        TestAnnotation msg2 = Demo2.class.getDeclaredField("msg2").getAnnotation(TestAnnotation.class);
        System.out.println(msg2.value());
        System.out.println(msg2.what());
    }

    @Test
    public void test3() throws Exception{
        TestAnnotation msg3 = Demo2.class.getDeclaredField("msg3").getAnnotation(TestAnnotation.class);
        System.out.println(msg3.value());
        System.out.println(msg3.what());
    }

    @Test
    public void test4() throws Exception{
        TestAnnotation msg4 = Demo2.class.getDeclaredField("msg4").getAnnotation(TestAnnotation.class);
        System.out.println(msg4.value());
        System.out.println(msg4.what());
    }
}

案例三:获取参数修饰注解对应的属性值

package com.cpc.annotation.p3;

import java.lang.annotation.*;

/**
 * @Description: 非空注解:使用在方法的参数上,false表示此参数可以为空,true不能为空
 * @Author: cpc
 * @Date: 2019-11-06 15:32
 * @Version: V1.0
 *
 */
@Documented
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface IsNotNull {
    boolean value() default false;
}
package com.cpc.annotation.p3;

/**
 * @Description:
 * @Author: cpc
 * @Date: 2019-11-06 15:33
 * @Version: V1.0
 *
 * 获取参数修饰注解对应的属性值
 *
 */
public class Demo3 {

    public void hello1(@IsNotNull(true) String name) {
        System.out.println("hello:" + name);
    }

    public void hello2(@IsNotNull String name) {
        System.out.println("hello:" + name);
    }
}
package com.cpc.annotation.p3;

import org.junit.jupiter.api.Test;

/**
 * @Description: 这是测试获取方法参数上的注解 
 * @Author: cpc
 * @Date: 2019-11-06 15:33
 * @Version: V1.0
 */
@SuppressWarnings(value = "unchecked")
public class Demo3Test {
    @Test
    @SuppressWarnings(value = "unchecked")
    public void hello1() throws Exception {
        Demo3 demo3 = new Demo3();
        //这是获取 demo3 上面的 hello1 方法获取所有类型类string的参数
        for (Parameter parameter : demo3.getClass().getMethod("hello1", String.class).getParameters()) {
            //这是搞到参数中的 IsNotNull  这个注解
            IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);
            //判断是否有这个注解
            if(annotation != null){
                //获取对应的value值
                System.out.println(annotation.value());//true
            }
        }
    }

    @Test
    @SuppressWarnings(value = "unchecked")
    public void hello2() throws Exception {
        Demo3 demo3 = new Demo3();
        //一样的 这是搞到 hello2 上面的 string 参数注解 ,拿到说有参数
        for (Parameter parameter : demo3.getClass().getMethod("hello2", String.class).getParameters()) {
            //搞到IsNotNull 这个玩意
            IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);
            if(annotation != null){
                //如果不为空就直接输出吧
                System.out.println(annotation.value());//false
            }
        }
    }
}

高级:Aop自定义注解的应用

上代码,直接搞

package com.cpc.annotation.springAop;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Description: aop 日志字典类 
 * @Author: cpc
 * @Date: 2019-11-06 15:38
 * @Version: V1.0
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface  MyLog {
    //这是日志的描述信息
    String desc();
}

package com.cpc.annotation.springAop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;


/**
 * @Description:
 * @Author: cpc
 * @Date: 2019-11-06 15:38
 * @Version: V1.0
 */
@Component
@Aspect
public class MyLogAspect {

    /**
     * 只要用到了com.cpc.annotation.springAop.MyLog这个注解的,就是目标类
     */
    @Pointcut("@annotation(com.cpc.annotation.springAop.MyLog)")
    private void MyValid() {
    }

    @Before("MyValid()")
    public void before(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        MyLog myLog = signature.getMethod().getAnnotation(MyLog.class);
        System.out.println("[" + signature.getName() + " : start.....]");
        System.out.println("【目标对象方法被调用时候产生的日志,记录到日志表中】:"+myLog.desc());
    }

}

package com.cpc.annotation.springAop;

import org.springframework.stereotype.Component;

/**
 * @Description:
 * @Author: cpc
 * @Date: 2019-11-06 15:53
 * @Version: V1.0
 */
@Component
public class LogController {

    @MyLog(desc = "这是结合spring aop知识,讲解自定义注解应用的一个案例")
    public void testLogAspect(){
        System.out.println("这里随便来点啥");
    }
}
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * @Description: 这个类主要是读取配置文件滴 
 * @Author: cpc
 * @Date: 2019-11-06 15:54
 * @Version: V1.0
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:applicationContext.xml"})
public class BaseTestCase {
}
import com.cpc.annotation.springAop.LogController;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * @Description: 测试aop日志
 * @Author: cpc
 * @Date: 2019-11-06 15:54
 * @Version: V1.0
 */
public class LogControllerTest extends BaseTestCase {
    @Autowired
    private LogController logController;

    @Test
    public void testLogAspect(){
        logController.testLogAspect();
    }
}

AOP + 自定义注解应用篇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值