Java注解的入门学习

一、概念

Java注解是一种元数据形式,可以被添加到Java代码中的各种元素(类、方法、字段等)上,以提供关于这些元素的额外信息。注解是在Java 5中引入的一项特性,它们不直接影响代码的执行,而是提供了一种机制来对代码进行标记和解释。

通常以@符号开头,放到注解目标的前面。Java提供了一些内置的注解。

@Override:该注解代表重写父类的方法

@Deprecated:使用@Deprecate的方法会出现一条删除线,表示该方法过时了,但是不影响使用

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

@Retention:标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问

@Documented:标记这些注解是否包含在用户文档中

@Target:标记这个注解应该是哪种 Java 成员。

@Inherited:标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)

从 Java 7 开始,额外添加了 3 个注解:

@SafeVarargs:忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告

@FunctionalInterface:Java 8 开始支持,标识一个匿名函数或函数式接口。

@Repeatable:Java 8 开始支持,标识某注解可以在同一个声明上使用多次。

二、注解的作用

1. 提供元数据信息

注解为代码元素提供了额外的元数据信息。这些信息可以用于在编译时或运行时进行处理,以实现各种功能。例如,@Override注解用于标记方法覆盖父类的行为,这在编译时会进行检查。

2.编译时检查

使用注解可以在编译时进行静态检查,从而帮助捕获一些常见的错误。例如,使用@Deprecated注解标记已过时的方法或类可以在编译时产生警告,提醒开发人员使用更合适的替代方案。

3.自动生成代码

注解可以用于生成一些重复性的代码,从而减少开发人员的工作量。通过编写自定义的注解处理器,可以在编译时根据注解信息生成额外的代码。这在一些框架和库中被广泛使用,以提供更便捷的开发方式。

4. 运行时处理

通过使用反射机制,可以在运行时处理注解信息。这样可以实现一些动态的行为,例如根据注解信息加载特定的配置文件或执行特定的逻辑。

三、自定义注解

创建自定义的注解,我们需要使用到下面几个注解,这些作用于注解上的注解我们称为元注解。

1.Target注解

标记这个注解应该是哪种 Java 成员使用。

TYPE:类、接口(包括注释类型)或枚举声明
FIELD:字段声明(包括枚举常量)
METHOD: 方法声明
PARAMETER: 参数声明
CONSTRUCTOR: 构造方法声明
LOCAL_VARIABLE: 局部变量声明
ANNOTATION_TYPE:释类型声明
PACKAGE:包声明

2.Retention注解

标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。

source:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;被编译器忽略。
class:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期。
runtime:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在。

3.@Document注解

@Document注解用于指定被修饰的注解可以被javadoc工具提取成文档。定义注解类时使用@Document注解进行修饰,则所有使用该注解修饰的程序元素的API文档中将会包含该注解说明

4.@Inherited注解

@Inherited注解指定注解具有继承性,如果某个注解使用@Inherited进行修饰,则该类使用该注解时,其子类将自动被修饰

5.@Repeatable注解

@Repeatable注解是Java8新增的注解,用于开发重复注解。

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

/**
 * @author qinxun
 * @date 2023-06-08
 * @Descripion: 自定义注解
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    // 定义一个名为“name”的注解元素,默认为空字符串
    String name() default "";

    // 定义一个名为"value"的注解元素,默认值为0
    int value() default 0;

}

我们创建一个注解测试类,获取使用自定义注解的信息。

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * @author qinxun
 * @date 2023-06-08
 * @Descripion: 自定义注解测试
 */
@MyAnnotation(name = "class", value = 10)
public class AnnotationTest {
    public static void main(String[] args) {
        // 获取类上的自定义注解数据
        MyAnnotation myAnnotation = AnnotationTest.class.getAnnotation(MyAnnotation.class);
        System.out.println("name:" + myAnnotation.name() + ",value=" + myAnnotation.value());

        // 获取方法上的自定义注解数据
        Class<AnnotationTest> aClass = AnnotationTest.class;
        Method[] methods = aClass.getDeclaredMethods();
        for (Method method : methods) {
            Annotation[] annotations = method.getDeclaredAnnotations();
            for (Annotation annotation : annotations) {
                MyAnnotation testAnnotation = (MyAnnotation) annotation;
                System.out.println("name:" + testAnnotation.name() + ",value=" + testAnnotation.value());
            }
        }
    }

    @MyAnnotation(name = "method", value = 5)
    private static void show() {
        System.out.println("方法");
    }
}

执行程序结果:

name:class,value=10
name:method,value=5

四、自定义注解在web里的使用

在web开发中,权限控制非常重要,所以有些接口会限制必须登录之后才能访问,但是个别接口并没有这种限制。

1.我们自定义一个注解,用于标记需要登录后才能访问。

import java.lang.annotation.*;

/**
 * @author qinxun
 * @date 2023-06-08
 * @Descripion: 自定义注解标记访问方法需要登录
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NeedLoginAnnotation {
}

2.创建一个拦截器,用于处理我们的自定义登录注解

import com.example.quartzdemo.annotation.NeedLoginAnnotation;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author qinxun
 * @date 2023-06-08
 * @Descripion: 自定义登录拦截器
 */
public class LoginFilter implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) {
        if (obj instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) obj;
            // 判断方法是否使用了自定义登录注解  
            NeedLoginAnnotation needLoginAnnotation = handlerMethod.getMethod().getDeclaredAnnotation(NeedLoginAnnotation.class);
            if (needLoginAnnotation != null) {
                System.out.println("该接口需要登录后才能访问");
                // 判断是否登录的逻辑 如果是登录状态就放行..
                return false;
            }
        } else if (obj instanceof ResourceHttpRequestHandler) {
            return true;
        }
        // 放行
        return true;
    }
}

3.把我们创建的拦截器添加到web配置中

import com.example.quartzdemo.filter.LoginFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author qinxun
 * @date 2023-06-08
 * @Descripion: web配置
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 添加自定义拦截器
        registry.addInterceptor(new LoginFilter())
                .addPathPatterns()
                .excludePathPatterns("/","/login");
    }
}

4.创建控制层进行测试

import com.example.quartzdemo.annotation.NeedLoginAnnotation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author qinxun
 * @date 2023-06-08
 * @Descripion: 自定义注解测试
 */
@RestController
public class AnnotationController {

    /**
     * 新增 加上了需要登录才能访问的注解
     */
    @RequestMapping("/save")
    @NeedLoginAnnotation
    public String toSave() {
        System.out.println("新增操作");
        return "新增";
    }

    /**
     * 查询
     */
    @GetMapping("/find")
    public String toFind() {
        System.out.println("查询操作");
        return "查询";
    }
}

在新增操作的时候我们标记了需要登录才能访问的注解,在查询的接口我们没有添加这个注解。

 控制台返回 

该接口需要登录后才能访问

这样我们就实现了标记自定义登录注解的方法,如果没有登录的情况下是不能访问的。

我们在访问查询的接口,因为查询的接口没有添加自定义的登录注解,所以拦截器是放行的,是可以访问这个方法。

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

qinxun2008081

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

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

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

打赏作者

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

抵扣说明:

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

余额充值