一文详解Java自定义注解

news/2024/10/18 2:24:33/

目录

简介

JDK注解

@Target

@Retention

@Documented

@Inherited

第三方注解

自定义注解

举例

默认字符串注解

实现指定包名称扫描注解


简介

注解(Annotation)是Java SE 5.0 版本开始引入的概念,它是对 Java 源代码的说明,是一种元数据(描述数据的数据)。

Java中的注解主要分为以下三类:

  • JDK的注解
  • 第三方的注解
  • 自定义注解

JDK注解

  • Java内置注解
    • @Override (标记重写方法)
    • @Deprecated (标记过时)
    • @SuppressWarnings (忽略警告)
  • 元注解 (注解的注解)
    • @Target (注解的作用目标)
    • @Retention (注解的生命周期)
    • @Document (注解是否被包含在JavaDoc中)
    • @Inherited (是否允许子类集成该注解)

@Target

用于描述注解的使用范围,有一个枚举ElementType来指定,具体如下:

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应用于任何使用类型的语句中(例如声明语句、泛型和强制转换语句中的类型)

@Retention

表示需要在什么级别保存该注释信息,用于描述注解的生命周期,也是一个枚举RetentionPoicy来决定的

取值含义
RetentionPolicy.SOURCE源码中保留,编译期可以处理
RetentionPolicy.CLASSClass文件中保留,Class加载时可以处理
RetentionPolicy.RUNTIME运行时保留,运行中可以处理

一般填RetentionPoicy.RUNTIME即可

@Documented

如果用javadoc生成文档时,想把注解也生成文档,就带这个。

@Inherited

@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。注意,@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

第三方注解

常见的有Spring,SpringBoot,Dubbo等等框架的注解

自定义注解

使用JDK中一些元注解,@Target,@Retention,@Document,@Inherited来修饰注解。具体格式如下:

/*** 修饰符 @interface 注解名 {* 注解元素的声明1* 注解元素的声明2* }* 修饰符:访问修饰符必须为public,不写默认为pubic;* 关键字:必须为@interface;* 注解名: 注解名称为自定义注解的名称,使用时还会用到;* 注解类型元素:注解类型元素是注解中内容,可以理解成自定义接口的实现部分;*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyTestAnnotation {/***    注解的元素声明的两种形式*    type elementName();*    type elementName() default value;  */String value() default "test";
}
  • 修饰符: 访问修饰符必须为public,不写默认为pubic
  • 关键字: 关键字为@interface
  • 注解名称: 注解名称为自定义注解的名称,使用时还会用到
  • 注解内容: 注解中内容,对注解的描述

举例

默认字符串注解

  • 定义注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyTestAnnotation {String value() default "test";
}
  • 配置注解
@Data
@Builder
@MyTestAnnotation
public class MyBean {private String name;private int age;
}
  • 利用反射解析注解
public class MyTest {//isAnnotationPresent:判断当前元素是否被指定注解修饰//getAnnotation:返回指定的注解//getAnnotations:返回所有的注解public static void main(String[] args) {try {//获取MyBean的Class对象MyBean myBean = MyBean.builder().build();Class clazz = myBean.getClass();//判断myBean对象上是否有MyTestAnnotation注解if (clazz.isAnnotationPresent(MyTestAnnotation.class)) {System.out.println("MyBean类上配置了MyTestAnnotation注解!");//获取该对象上MyTestAnnotation类型的注解MyTestAnnotation myTestAnnotation = (MyTestAnnotation) clazz.getAnnotation(MyTestAnnotation.class);System.out.println(myTestAnnotation.value());} else {System.out.println("MyBean类上没有配置MyTestAnnotation注解!");}} catch (Exception e) {e.printStackTrace();}}
}
//结果
//Connected to the target VM, address: '127.0.0.1:62125', transport: 'socket'
//MyBean类上配置了MyTestAnnotation注解!
//test
//Disconnected from the target VM, address: '127.0.0.1:62125', transport: 'socket'

实现指定包名称扫描注解

结果示例:

@RpcComponentScan(basePackages = {"com.xlfc.consumer"})

可以扫描com.xlfc.consumer包下的所有类

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Import(CustomScannerRegistrar.class)//Spring框架下的注解
@Documented
public @interface RpcComponentScan {String[] basePackages();
}@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {Class<?>[] value();
}
  • 自定义扫描类的方法
public class CustomScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {private static final String SPRING_BEAN_BASE_PACKAGE="com.xlfc";private static final String BASE_PACKAGE_ATTRIBUTE_NAME="basePackages";private static final Class<?> annotationClass = RpcComponentScan.class;private ResourceLoader resourceLoader;@Overridepublic void setResourceLoader(ResourceLoader resourceLoader) {this.resourceLoader=resourceLoader;}@Overridepublic void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {CustomScanner rpcServiceScanner=new CustomScanner(beanDefinitionRegistry, Service.class);CustomScanner springBeanScanner=new CustomScanner(beanDefinitionRegistry, Component.class);if (resourceLoader!=null){rpcServiceScanner.setResourceLoader(resourceLoader);springBeanScanner.setResourceLoader(resourceLoader);}String[] packageToScan=getPackageToScan(annotationMetadata);//其实就是扫描包下面有这些注解的类,将其加入到容器中后才可以使用。springBeanScanner.scan(SPRING_BEAN_BASE_PACKAGE);rpcServiceScanner.scan(packageToScan);}/*** 获取到需要扫描的内容* */private String[] getPackageToScan(AnnotationMetadata annotationMetadata) {String[] packageToScan=new String[0];AnnotationAttributes attributes = AnnotationAttributes.fromMap(annotationMetadata.getAnnotationAttributes(annotationClass.getName()));//可见DubboComponentScanRegistrar的getPackagesToScan0方法if (attributes!=null){packageToScan=attributes.getStringArray(BASE_PACKAGE_ATTRIBUTE_NAME);}//说明是没有扫描的if (packageToScan.length==0){packageToScan=new String[]{((StandardAnnotationMetadata)annotationMetadata).getIntrospectedClass().getPackage().getName()};}return packageToScan;}}


http://www.ppmy.cn/news/79784.html

相关文章

传奇手游三职业1.80合击服务端三端互通版搭建教程

传奇手游三职业1.80合击服务端三端互通版搭建教程 大家好&#xff0c;我是驰网艾西。随着时代的发展&#xff0c;以前我们热爱的传奇游戏也越来越没有时间玩了&#xff0c;到了一定的年纪大家都有自己的事业以及生活压力。以前我们总是玩PC端所谓的端游&#xff0c;现在大家都…

(C语言版)力扣(LeetCode)题库1-5题解析

力扣&#xff08;LeetCode&#xff09;题库1-5题解析 1.两数之和题目解析 2.两数相加题目解法 3.无重复字符的最长字串题目解法 4. 寻找两个正序数组的中位数题目解法 5. 最长回文子串题目解法 结语 1.两数之和 题目 给定一个整数数组 nums 和一个整数目标值 target&#xff…

加密与解密 基础篇/win API/小端序大端序

目录 1.1加密和解密的概念 软件逆向工程 逆向分析技术是什么 1.通过软件的执行 来分析程序 2.静态分析技术 3.动态分析技术 那我们如何有效的进行动态调试呢 1.2文本字符 ASCII码 Unicode 字节存储顺序 1.3Windows操作系统 win32API函数 WOW64 Windows消息机制 深…

探秘 | 简说IP地址以及路由器的功能究竟是什么?

我们都知道我们在上网的时候都有一个IP地址&#xff0c;用来和其他人进行通信和数据交换。 其中IP地址又分为内网地址和外网地址&#xff0c;也叫作私有地址和公有地址。 为什么要区分私有地址和公有地址呢&#xff1f;原因很简单&#xff0c;因为公有的IP地址不够使用了&…

Python基础教程:第九章_Python异常模块与包

从现在开始&#xff0c;让我们来进入到新的章节&#xff0c; Python 异常模块与包的内容学习。本章节我们主要分为 6 部分进行讲解&#xff0c;包含了 Python 异常的相关操作以及 Python 的模块操作&#xff0c; Python 的包操作和安装第三方 Python 包的相关操作。 了解异常 …

周六晚周日全天Hcip BGP

ISIS 默认是窄带 需要开启宽带 ISIS&#xff0c;前提我是level 1&#xff0c;收到ATT位置为1 的路由是默认路由 为什么要使用BGP协议&#xff1f; 我们要在不同的AS之间进行通信&#xff0c;需要使用BGP协议。 BGP优势&#xff1a; 1.非常稳定 2.可以传输大量的路由&#xff…

Python——第7章 pandas数据分析实战

7.1pandas常用数据类型 7.1.1一维数组与常用操作 import pandas as pd import matplotlib.pyplot as plt#设置输出结果对齐方式 pd.set_option(display.unicode.ambiguous_as_wide,True) pd.set_option(display.unicode.east_asian_width,True)#自动创建从0开始的非负整数索引…

装饰者模式-java实现

的简介 装饰模式又称为“包装(Wrapper)模式”&#xff0c;以对客户端透明的方式扩展对象的功能&#xff0c;是继承关系的一个替代方案。动态地给对象添加一些额外地职责&#xff0c;就增加功能而言&#xff0c;装饰模式比生成子类更加灵活。 一般来说&#xff0c;一些特殊场景…