java自定义注解以及自定义注解结合AOP使用

目录

前言

一、自定义注解和元注解

1.元注解

1.1@Target

1.2@Retention

1.3@Document

1.4@Inherited

2.自定义注解

2.1注解属性类型

2.2注解属性赋值

2.3为 MyAnnotation 注解添加 id 和 describe 属性:

二、自定义注解简单使用

1.1使用1

1.2使用2

三、自定义注解结合aop使用


前言

       注解是一种能被添加到java源代码中的元数据,方法、类、参数和包都可以用注解来修饰。注解可以看作是一种特殊的标记,可以用在方法、类、参数和包上,程序在编译或者运行时可以检测到这些标记而进行一些特殊的处理。

    要深入学习注解,我们就必须能定义自己的注解并使用注解,在定义自己的注解之前,我们需要了解java为我们提供的元注解和相关定义注解的语法。

一、自定义注解和元注解

1.元注解

元注解是专门用来注解其他注解的注解,听起来有些绕口,实际上就是专门为自定义注解提供的注解。java.lang.annotation提供了五种元注解:
@Documented – 注解是否将包含在JavaDoc中
@Retention – 什么时候使用该注解
@Target – 注解用于什么地方
@Inherited – 是否允许子类继承该注解
@Repeatable - 是否可重复注解,jdk1.8引入

下面我们看一下每个元注解的作用和相应分参数的使用说明。

1.1@Target

Target类型描述
ElementType.TYPE应用于类、接口(包括注解类型)、枚举
ElementType.FIELD应用于属性(包括枚举中的常量)
ElementType.METHOD应用于方法
ElementType.PARAMETER应用于方法的形参
ElementType.CONSTRUCTOR应用于构造函数
ElementType.LOCAL_VARIABLE应用于局部变量
ElementType.ANNOTATION_TYPE应用于注解类型
ElementType.PACKAGE应用于包
ElementType.TYPE_PARAMETER应用于类型变量
ElementType.TYPE_USE应用于任何使用类型的语句中(例如声明语句、泛型和强制转换语句中的类型)

1.2@Retention

表明该注解的生命周期

生命周期类型描述
RetentionPolicy.SOURCE编译时被丢弃,不包含在类文件中
RetentionPolicy.CLASSJVM加载时被丢弃,包含在类文件中,默认值
RetentionPolicy.RUNTIME由JVM 加载,包含在类文件中,在运行时可以被获取到

1.3@Document

表明该注解标记的元素可以被Javadoc 或类似的工具文档化

1.4@Inherited

表明使用了@Inherited注解的注解,所标记的类的子类也会拥有这个注解。

2.自定义注解

我们定义一个类的时候是使用的 class 关键字定义的,现在我们想定义一个自己的注解 需要使用 @interface 关键字来定义。除了上面的元注解其他的注解其实都是自定义注解。比如:

@Documented
@Inherited
@Target({ ElementType.FIELD, ElementType.METHOD ,ElementType.TYPE})  //可以在字段、枚举的常量、方法
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
     String value() default "";//注解属性
}

2.1注解属性类型

注解属性 ( 接口方法 ) 返回值类型要求 :

  1. 基本数据类型 : byte , short , int , long , float , double , char , boolean ;
  2. 字符串类型 : String ;
  3. 枚举类型 : enum ;
  4. 注解类型 ;
  5. 以上类型的数组形式 ;

注解属性返回值必须是以上的类型 , 不能设置其它类型返回值 , 否则会报错 ;

2.2注解属性赋值

注解中定义了属性 , 在使用注解时 , 需要给注解属性赋值;定义注解属性时 , 可以使用default关键字指定属性默认值 , 下面代码中 , 制定注解属性 intValue 值类型为 int 整型 , 默认值 88;

int intValue() default 88

如果 注解属性 指定了默认值 , 在使用注解时 , 可以选择 不为该属性赋值 ( 此时使用默认属性值 ) , 也可以进行赋值 ( 指定一个新的属性值 ) ;

如果 注解属性 没有指定默认值 , 则使用注解时 , 必须为其指定一个默认值 , 否则编译时报错 ;

数组类型的注解属性赋值时 , 使用大括号进行赋值 , 大括号内是数组元素 , 如果只有一个属性 , 可以省略大括号 

2.3为 MyAnnotation 注解添加 id 和 describe 属性:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface MyAnnotation { 
    int id();
    String describe();
}

也可以为 id 和 describe 属性添加默认值,当 id 或 describe 属性不指定具体的值的时候就会使用默认值:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface MyAnnotation { 
    int id() default 0;
    String describe() default "";
}

二、自定义注解简单使用

1.1使用1

1.定义自定义注解

import java.lang.annotation.*;

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface MyAnnotation {
    int id() default 0;
    String describe() default "";
}

2.定义pojo类

import com.alibaba.fastjson.annotation.JSONField;
import com.itheima.Annotation.MyAnnotation;

public class Student {

    @JSONField(ordinal = 0)
    @MyAnnotation
    public String name;

    @MyAnnotation(id = 1, describe = "分数")
    public Integer score;

    @MyAnnotation(describe = "getName方法")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getScore() {
        return score;
    }

    public void setScore(Integer score) {
        this.score = score;
    }
}

3.使用反射获取类成员变量上的所有注解

import com.itheima.Annotation.MyAnnotation;
import com.itheima.Pojo.Student;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

public class TestAnnotation {
    public static void main(String[] args) {
        Class<?> studentClass = Student.class;
        Field[] fields = studentClass.getDeclaredFields();//获取所有的类成员变量字段
        for (Field field : fields) {
            String fieldName = field.getName(); //获取该类成员变量的名字
            System.out.println("成员变量名是:" + fieldName);
            Annotation[] annotations = field.getAnnotations(); //获取该类成员变量上所有声明周期是运行时的注解
            for (Annotation annotation : annotations) {
                Class<? extends Annotation> annotationType = annotation.annotationType();
                String annotationName = annotationType.getSimpleName();//注解的简短名称
                System.out.println(" 使用的注解是:" + annotationName);
                //判断该注解是不是 MyAnnotation 注解,是的话打印其 id 和 describe 属性
                if (annotationType.equals(MyAnnotation.class)) {
                    MyAnnotation myAnnotation = field.getAnnotation(MyAnnotation.class);
                    int id = myAnnotation.id();
                    String describe = myAnnotation.describe();
                    System.out.println("    MyAnnotation注解中的id是:" + id);
                    System.out.println("    MyAnnotation注解中的describe是:" + describe);
                }
            }
            System.out.println("--------------------");
        }
    }
}

4.输出结果

成员变量名是:name
 使用的注解是:JSONField
 使用的注解是:MyAnnotation
    MyAnnotation注解中的id是:0
    MyAnnotation注解中的describe是:
--------------------
成员变量名是:score
 使用的注解是:MyAnnotation
    MyAnnotation注解中的id是:1
    MyAnnotation注解中的describe是:分数
--------------------

 5.反射获取成员变量上的指定注解

import com.itheima.Annotation.MyAnnotation;
import com.itheima.Pojo.Student;
import java.lang.reflect.Field;

public class TestAnnotation {
    public static void main(String[] args) {
        Class<?> studentClass = Student.class;
        //反射遍历所有成员变量
        Field[] fields = studentClass.getDeclaredFields();
        for (Field field : fields) {
            //如果其成员变量上有 MyAnnotation 注解,就打印成员变量名和注解里的内容
            if (field.isAnnotationPresent(MyAnnotation.class)) {
                String fieldName = field.getName();
                //获取变量字段上的 MyAnnotation 注解
                MyAnnotation annotation = field.getAnnotation(MyAnnotation.class);
                int id = annotation.id();
                String describe = annotation.describe();
                System.out.println("成员变量是:" + fieldName);
                System.out.println("MyAnnotation注解中的id是:" + id);
                System.out.println("MyAnnotation注解中的describe是:" + describe);
            }
            System.out.println();
        }
     
    }
}

输出:
    成员变量是:name
    MyAnnotation注解中的id是:0
    MyAnnotation注解中的describe是:

    成员变量是:score
    MyAnnotation注解中的id是:1
    MyAnnotation注解中的describe是:分数

6.获取方法上的指定注解

import com.itheima.Annotation.MyAnnotation;
import com.itheima.Pojo.Student;
import java.lang.reflect.Method;

public class TestAnnotation {
    public static void main(String[] args) {
        Class<?> studentClass = Student.class;
        /* 反射遍历所有方法 */
        Method[] methods = studentClass.getDeclaredMethods();
        for (Method method : methods) {
            //如果其方法上有 MyAnnotation 注解,就打印方法名和注解里的内容
            if (method.isAnnotationPresent(MyAnnotation.class)) {
                String methodName = method.getName();
                //获取方法上的 MyAnnotation 注解
                MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
                int id = annotation.id();
                String describe = annotation.describe();
                System.out.println("方法名是:" + methodName);
                System.out.println("MyAnnotation注解中的id是:" + id);
                System.out.println("MyAnnotation注解中的describe是:" + describe);
            }
        }
    }
}

输出:方法名是:getName
      MyAnnotation注解中的id是:0
      MyAnnotation注解中的describe是:getName方法

1.2使用2

 1.自定义注解initsex

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
@Inherited
public @interface InitSex {
    enum SEX_TYPE {MAN, WOMAN}
    SEX_TYPE sex() default SEX_TYPE.MAN;
}

2.自定义注解ValidateAge

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
@Inherited
public @interface ValidateAge {
    /**
     * 最小值
     */
    int min() default 18;
    /**
     * 最大值
     */
    int max() default 99;
    /**
     * 默认值
     */
    int value() default 20;
}

3.定义pojo

import com.itheima.Annotation.InitSex;
import com.itheima.Annotation.ValidateAge;

public class User {
    private String username;
    @ValidateAge(min = 20, max = 35, value = 22)
    private int age;
    @InitSex(sex = InitSex.SEX_TYPE.MAN)
    private String sex;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

4.测试

import com.itheima.Annotation.InitSex;
import com.itheima.Annotation.ValidateAge;
import com.itheima.Pojo.User;

import java.lang.reflect.Field;

public class TestInitParam {
    public static void main(String[] args) throws IllegalAccessException {
        User user = new User();
        initUser(user);
        // 年龄为0,校验为通过情况
        boolean checkResult = checkUser(user);
        printResult(checkResult);
        // 重新设置年龄,校验通过情况
        user.setAge(22);
        checkResult = checkUser(user);
        printResult(checkResult);
    }
    static void initUser(User user) throws IllegalAccessException {
        // 获取User类中所有的属性(getFields无法获得private属性)
        Field[] fields = User.class.getDeclaredFields();
        // 遍历所有属性
        for (Field field : fields) {
            // 如果属性上有此注解,则进行赋值操作
            if (field.isAnnotationPresent(InitSex.class)) {
                InitSex init = field.getAnnotation(InitSex.class);
                field.setAccessible(true);
                // 设置属性的性别值
                field.set(user, init.sex().toString());
                System.out.println("完成属性值的修改,修改值为:" + init.sex().toString());
            }
        }
    }
    static boolean checkUser(User user) throws IllegalAccessException {
        // 获取User类中所有的属性(getFields无法获得private属性)
        Field[] fields = User.class.getDeclaredFields();
        boolean result = true;
        // 遍历所有属性
        for (Field field : fields) {
            // 如果属性上有此注解,则进行赋值操作
            if (field.isAnnotationPresent(ValidateAge.class)) {
                ValidateAge validateAge = field.getAnnotation(ValidateAge.class);
                field.setAccessible(true);
                int age = (Integer)field.get(user);
                if (age < validateAge.min() || age > validateAge.max()) {
                    result = false;
                    System.out.println("年龄值不符合条件");
                }
            }
        }
        return result;
    }
    static void printResult(boolean checkResult) {
        if (checkResult) {
            System.out.println("校验通过···");
        } else {
            System.out.println("校验未通过···");
        }
    }
}

5.输出

完成属性值的修改,修改值为:MAN
年龄值不符合条件
校验未通过···
校验通过···

三、自定义注解结合aop使用

1.pojo

import com.itheima.Annotation.InitSex;
import com.itheima.Annotation.ValidateAge;

public class User {
    private String username;
    @ValidateAge(min = 20, max = 35, value = 22)
    private int age;
    @InitSex(sex = InitSex.SEX_TYPE.MAN)
    private String sex;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

2.自定义注解

2.1  自定义注解InitSex

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
@Inherited
public @interface InitSex {
    enum SEX_TYPE {MAN, WOMAN}
    SEX_TYPE sex() default SEX_TYPE.MAN;
}

2.2  自定义注解ValidateAge

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
@Inherited
public @interface ValidateAge {
    /**
     * 最小值
     */
    int min() default 18;
    /**
     * 最大值
     */
    int max() default 99;
    /**
     * 默认值
     */
    int value() default 20;
}

2.3  自定义注解Log

import java.lang.annotation.*;


@Target({ElementType.METHOD})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
}

3. 切面

import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Date;

@Aspect
@Component
public class LogAspect {

    @Around("@annotation(com.itheima.Annotation.Log)")
    public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {
        //操作时间
        Date operateTime = new Date();
        //操作类名
        String className = joinPoint.getTarget().getClass().getName();
        //操作方法名
        String methodName = joinPoint.getSignature().getName();
        //操作方法参数
        Object[] args = joinPoint.getArgs();
        String methodParams = Arrays.toString(args);
        long begin = System.currentTimeMillis();
        //调用原始目标方法运行
        Object result = joinPoint.proceed();
        long end = System.currentTimeMillis();
        //方法返回值
        String returnValue = JSONObject.toJSONString(result);
        //操作耗时
        Long costTime = end - begin;
        //记录操作日志
        System.out.println("操作时间:"+operateTime+" 操作类名:"+className+" 操作方法名:"+methodName+
                "  操作方法参数:"+methodParams+"  方法返回值:"+returnValue+"  操作耗时"+costTime);
        return result;
    }
}

4.测试切面和自定义注解的结合使用(切点是被自定义注解Log注解的方法)

import com.itheima.Annotation.InitSex;
import com.itheima.Annotation.Log;
import com.itheima.Annotation.ValidateAge;
import com.itheima.Pojo.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.lang.reflect.Field;


@RestController
@RequestMapping("/test")
public class AopDemo {
    @Log
    @RequestMapping("/show3")
    @ResponseBody
    public void testAop(String ss) throws IllegalAccessException{
        User user = new User();
        initUser(user);
        // 年龄为0,校验为通过情况
        boolean checkResult = checkUser(user);
        printResult(checkResult);
        // 重新设置年龄,校验通过情况
        user.setAge(22);
        checkResult = checkUser(user);
        printResult(checkResult);
    }



    public void initUser(User user) throws IllegalAccessException {
        // 获取User类中所有的属性(getFields无法获得private属性)
        Field[] fields = User.class.getDeclaredFields();
        // 遍历所有属性
        for (Field field : fields) {
            // 如果属性上有此注解,则进行赋值操作
            if (field.isAnnotationPresent(InitSex.class)) {
                InitSex init = field.getAnnotation(InitSex.class);
                field.setAccessible(true);
                // 设置属性的性别值
                field.set(user, init.sex().toString());
                System.out.println("完成属性值的修改,修改值为:" + init.sex().toString());
            }
        }
    }
    public boolean checkUser(User user) throws IllegalAccessException {
        // 获取User类中所有的属性(getFields无法获得private属性)
        Field[] fields = User.class.getDeclaredFields();
        boolean result = true;
        // 遍历所有属性
        for (Field field : fields) {
            // 如果属性上有此注解,则进行赋值操作
            if (field.isAnnotationPresent(ValidateAge.class)) {
                ValidateAge validateAge = field.getAnnotation(ValidateAge.class);
                field.setAccessible(true);
                int age = (Integer)field.get(user);
                if (age < validateAge.min() || age > validateAge.max()) {
                    result = false;
                    System.out.println("年龄值不符合条件");
                }
            }
        }
        return result;
    }
    public void printResult(boolean checkResult) {
        if (checkResult) {
            System.out.println("校验通过···");
        } else {
            System.out.println("校验未通过···");
        }
    }
}

5.输出

完成属性值的修改,修改值为:MAN
年龄值不符合条件
校验未通过···
校验通过···
操作时间:Thu Jul 18 16:26:39 CST 2024 操作类名:com.itheima.service.impl.AopDemo 操作方法名:testAop  操作方法参数:[test]  方法返回值:null  操作耗时58

  • 20
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值