俯拾皆是的Java注解,你真的get了吗?

共 6226字,需浏览 13分钟

 ·

2023-10-17 06:42


欢迎关注微信公众号:互联网全栈架构
一、什么是注解
注解是一种元数据,可以应用到代码的多种元素上,比如类、字段、方法等,它提供了关于这些元素的额外信息,但不会影响程序的运行逻辑。它主要有以下这些作用:
为编译器提供额外信息:编译器可以用注解来检测错误、抑制警告等。比如注解@Override,如果被修饰的方法没有正确重写父类的方法,那么编译器就会报错。又比如@Deprecated,它用来标识一个方法已经过时,建议不要继续使用,编译器也会给出相应的警告提示。
编译时自动生成代码:注解可以用于在编译时自动生成代码,从而减少开发人员的工作量以及一些不必要的错误,在一些框架中也经常可以见到这种用法,比如Lombok。
运行时处理:在运行时读取并处理注解,从而改变程序的行为。这种情况在Spring框架中可以说是比比皆是了。

生成文档:另外,@Documented修饰的元素将会包含在生成的Java文档中。

二、内置注解及元注解
JDK本身自带了一些常用的注解,主要有以下这些:

而应用于其他注解的注解,我们称之为元注解,一共有五种元注解:

三、自定义注解
我们通过两个简单的案例来实际说明一下注解的用法。
 1. 通过反射读取注解信息
首先我们定义一个简单的注解,它具有name和desc两个属性,然后在定义类的时候使用这个注解,并指定属性的值,最后在测试类中获取注解信息并打印:
package com.sample.core.annotation;

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

// 自定义一个注解,有value有desc两个属性
// 运行时生效,可应用于类、接口或者枚举
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
    String value();
    String desc();
}
package com.sample.core.annotation;

@MyAnnotation(value = "full-stack", desc = "欢迎来到编程世界")
public class MyClass {
}
package com.sample.core.annotation;

// 通过反射获取注解的信息
public class AnnotationTest {
    public static void main(String[] args) {
        Class<MyClass> myClass = MyClass.class;
        MyAnnotation myAnnotation = myClass.getAnnotation(MyAnnotation.class);
        System.out.println(myAnnotation.value());
        System.out.println(myAnnotation.desc());
    }
}
2. Spring AOP自定义注解打印日志
我们知道,Spring框架的两大核心是IoC和AOP,而AOP表示面向切面编程,在无需修改代码的前提下,对业务逻辑添加统一功能,比如事务、安全、日志等。现在我们通过自定义注解的方式来实现日志打印功能,只要在方法上加上这个注解,就可以打印出日志,而无需在每个方法里面都加上日志打印的功能,大大提升了代码的可维护性和简洁性。
这个例子基于Spring框架来完成,如果对于Spring Cloud Alibaba的项目搭建还不太熟练,请参考之前写的一篇文章:手把手:Spring Cloud Alibaba项目搭建
先定义一个注解,它只包含level属性,也就是日志级别的含义:
package com.fullstack.commerce.user.util;

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 MyLog {
    // 日志级别
    String level();
}
然后再定义一个注解处理器:
package com.fullstack.commerce.user.util;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;

// 这是一个切面类,同时交由Spring统一管理
@Aspect
@Component
public class MyLogAspect {
    // 配置织入点
    @Pointcut("@annotation(MyLog)")
    private void logPointCut(){}

    // 环绕织入,在调用方法的前后执行
    @Around("logPointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {

        // 获取方法名称
        MethodSignature signature =(MethodSignature) joinPoint.getSignature();
        String methodName=signature.getName();

        // 获取注解MyLog的参数值
        Method method = signature.getMethod();
        MyLog myLog=method.getAnnotation(MyLog.class);
        String level=myLog.level();

        // 打印日志
        System.out.println("方法名为:"+methodName+",日志级别为:"+level);
        long start = System.currentTimeMillis();
        // 注解方法继续执行
        Object result=joinPoint.proceed();
        System.out.println("方法的执行时间为:" + (System.currentTimeMillis()-start)+"毫秒。");

        return result;
    }
}

这样,统一打印日志的自定义注解就定义好了,接下来就是使用了。只需要在方法上加上@MyLog的注解,并指定它的level属性值,方法在被调用时,就会自动打印日志,并在方法执行完成后,打印出方法的执行时间。我们在Controller的方法上加上这个注解,并且访问这个方法,看看结果会是如何:
package com.fullstack.commerce.user.controller;

import com.fullstack.commerce.user.util.MyLog;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("hello")
public class HelloController {

    @GetMapping("test")
    @MyLog(level = "info")
    public String test(){
        return "Hello World";
    }
}

在浏览器里面输入:http://localhost:8080/hello/test,然后可以看到控制台输出如下:

以上基于JDK8实现。另外,文章主要是讲解自定义注解的使用,省去很多无关的细节,在实际代码编写中,还需要根据业务场景的实际特点做相应的丰富和改进。

都看到这里了,请帮忙一键三连啊,也就是点击文末的在看、点赞、分享,这样会让我的文章让更多人看到,也会大大地激励我进行更多的输出,谢谢!

鸣谢:

https://docs.oracle.com/javase/tutorial/java/annotations/index.html


推荐阅读:

“八面玲珑”的ZooKeeper入门介绍

一呼百应:监听变化的观察者模式

手把手:Spring Cloud Alibaba项目搭建

春天的故事:Spring框架的入门级知识

责无旁贷:超酷的责任链模式

聚沙成塔:聊聊建造者模式

公司裁员,码农竟然成了“帮凶”?(剧情杜撰)

浏览 84
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报