当前位置: 首页 > article >正文

java的Annotation使用

Java注解是一种元数据,可以为代码中的类、方法、字段、参数等元素提供附加信息,且不会直接影响代码的执行。Java在1.5版本中引入了注解(Annotation),用于提供代码在编译、运行时的额外信息。注解通过反射机制可以读取,从而完成相应的逻辑操作。

一、Java注解的原理

注解的本质是实现了java.lang.annotation.Annotation接口的特殊接口类型。当编译器或运行时遇到注解时,可以通过反射机制获取注解的数据,并做相应的处理。Java注解可以分为三类:

  1. 编译时注解:例如@Override@Deprecated,用于编译器检查。
  2. 运行时注解:例如@Retention(RetentionPolicy.RUNTIME)注解,用于在运行时通过反射读取。
  3. 源码注解:例如@SuppressWarnings,只在源码中存在,编译后即消失。

二、自定义注解

自定义注解在Java中非常常见。它们通常结合反射机制与代理模式实现,具体步骤如下:

  1. 定义注解:使用@interface关键字定义注解。可以指定默认值和使用范围。
  2. 配置元注解:元注解如@Target@Retention@Inherited@Documented等可以控制注解的作用范围和生命周期。
  3. 使用注解:在代码中标注自定义注解。
  4. 解析注解:通过反射获取并处理注解信息。

三、示例代码

假设我们要定义一个@MyAnnotation注解,并应用于方法上:

1. 定义自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME) // 指定在运行时可见
@Target(ElementType.METHOD) // 指定注解作用于方法
public @interface MyAnnotation {
    String value() default "default value";
    int number() default 0;
}
2. 应用自定义注解

在某个类中使用@MyAnnotation

public class TestClass {

    @MyAnnotation(value = "Hello, Annotation!", number = 10)
    public void annotatedMethod() {
        System.out.println("This method has been annotated.");
    }
}
3. 解析自定义注解

通过反射获取注解的值:

import java.lang.reflect.Method;

public class AnnotationProcessor {
    public static void main(String[] args) {
        try {
            // 获取TestClass类的注解方法
            Method method = TestClass.class.getMethod("annotatedMethod");

            // 检查方法上是否存在MyAnnotation注解
            if (method.isAnnotationPresent(MyAnnotation.class)) {
                MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);

                // 输出注解信息
                System.out.println("Value: " + annotation.value());
                System.out.println("Number: " + annotation.number());
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

四、元注解解释

  • @Target:定义注解的使用范围,取值如ElementType.METHOD(方法)、ElementType.TYPE(类/接口)等。
  • @Retention:定义注解的生命周期,包括RetentionPolicy.RUNTIME(运行时)、RetentionPolicy.CLASS(编译期)、RetentionPolicy.SOURCE(源码级别)。
  • @Inherited:允许子类继承父类的注解。
  • @Documented:标记注解是否包含在javadoc中。

五、自定义注解的应用场景

自定义注解广泛应用于框架开发和功能增强,如:

  • Spring中的依赖注入@Autowired@Service等注解用于对象管理和注入。
  • AOP(面向切面编程):使用注解来标识切点,实现事务管理、日志记录等功能。
  • 数据校验:例如@NotNull@Min等注解,用于输入参数的验证。下面是几个典型的自定义注解应用场景示例,包括依赖注入、AOP、数据校验等,每个示例都会演示如何定义注解、应用注解,以及如何在运行时解析注解。

1. 依赖注入(Dependency Injection)

在Spring等框架中,注解用于简化对象的依赖管理。例如,自定义一个@Inject注解实现简单的依赖注入机制。

自定义注解@Inject
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD) // 注解应用于字段上
public @interface Inject {}
使用注解实现依赖注入
public class Service {
    public void serve() {
        System.out.println("Service is serving...");
    }
}

public class Client {
    @Inject // 将Service注入到Client
    private Service service;

    public void doSomething() {
        service.serve();
    }
}
注解解析和依赖注入实现
import java.lang.reflect.Field;

public class DependencyInjector {
    public static void injectDependencies(Object obj) throws IllegalAccessException {
        Field[] fields = obj.getClass().getDeclaredFields();

        for (Field field : fields) {
            if (field.isAnnotationPresent(Inject.class)) {
                field.setAccessible(true);
                // 实例化被注入的类
                Object dependency = field.getType().getDeclaredConstructor().newInstance();
                field.set(obj, dependency); // 将依赖对象注入字段
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Client client = new Client();
        injectDependencies(client);
        client.doSomething();
    }
}

2. AOP(面向切面编程)

使用注解实现AOP功能,模拟在方法执行前后加入日志记录。

自定义注解@Log
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) // 注解应用于方法上
public @interface Log {}
应用注解
public class UserService {
    @Log
    public void performAction() {
        System.out.println("Action performed.");
    }
}
注解解析实现AOP
import java.lang.reflect.Method;

public class LogAspect {
    public static void logMethod(Object obj) throws Exception {
        for (Method method : obj.getClass().getDeclaredMethods()) {
            if (method.isAnnotationPresent(Log.class)) {
                System.out.println("Logging before method: " + method.getName());
                method.invoke(obj);
                System.out.println("Logging after method: " + method.getName());
            }
        }
    }

    public static void main(String[] args) throws Exception {
        UserService userService = new UserService();
        logMethod(userService);
    }
}

3. 数据校验

自定义注解实现数据校验,例如检查字符串是否为空。

自定义注解@NotEmpty
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD) // 注解应用于字段
public @interface NotEmpty {
    String message() default "Field cannot be empty";
}
使用注解
public class User {
    @NotEmpty(message = "Name cannot be empty")
    private String name;

    public User(String name) {
        this.name = name;
    }
}
校验逻辑
import java.lang.reflect.Field;

public class Validator {
    public static void validate(Object obj) throws Exception {
        for (Field field : obj.getClass().getDeclaredFields()) {
            if (field.isAnnotationPresent(NotEmpty.class)) {
                field.setAccessible(true);
                String value = (String) field.get(obj);
                if (value == null || value.isEmpty()) {
                    NotEmpty notEmpty = field.getAnnotation(NotEmpty.class);
                    throw new Exception(notEmpty.message());
                }
            }
        }
    }

    public static void main(String[] args) {
        try {
            User user = new User(""); // Name is empty
            validate(user);
        } catch (Exception e) {
            System.out.println("Validation error: " + e.getMessage());
        }
    }
}

总结

  • 依赖注入@Inject实现依赖对象的注入。
  • AOP@Log在方法前后加入日志逻辑。
  • 数据校验@NotEmpty用于字段的非空校验。

这些示例展示了如何通过注解简化开发流程,提升代码可读性与可维护性。


http://www.kler.cn/a/371960.html

相关文章:

  • Java AQS 目录
  • AXI接口的实现逻辑和底层原理,在FPGA中如何实现AXI接口,一篇文章足以搞明白!!!
  • ES6 变量的解构赋值
  • 【JavaEE】【多线程】定时器
  • 【算法】Kruskal最小生成树算法
  • 【动手学强化学习】part2-动态规划算法
  • MYSQL全局锁、标级锁、行级锁
  • 房屋租赁系统
  • Linux 如何精准排除特定文件并批量替换字符串
  • rabbitmq自学总结
  • net start mysql 启动mysql服务,发生系统错误,拒绝访问
  • 浅谈站点可靠性工程之SRE
  • 【10天速通Navigation2】(三) :Cartographer建图算法配置:从仿真到实车,从原理到实现
  • 研二了,该想想做啥呢?
  • 【算法系列-二叉树】层序遍历
  • 【2024|滑坡数据集论文解读1】CAS滑坡数据集:用于深度学习滑坡检测的大规模多传感器数据集
  • Scala 特质(Traits)与类继承 #scala #Scala #Scala继承
  • Mac程序坞窗口预览的方法来了
  • lego-loam featureAssociation 源码注释(七)
  • 使用 Kafka 和 MinIO 实现人工智能数据工作流
  • Windows 上更新OpenSSL 到 1.1.1
  • 现代化可观测性平台(1)
  • C语言常用的数据类型有哪些?
  • uniapp封装movable-area+movable-view组件,实现悬浮按钮可拖动,自动吸附边缘效果,自动向两边靠拢
  • element ui中el-image组件查看图片的坑
  • QT相机连接与拍照