首页 > Python资料 博客日记
java注解(实现原理及自定义注解)
2024-08-14 01:00:08Python资料围观61次
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
本文不是讲某个注解什么含义,而是讲注解的实现原理,以及自定义注解的创建。
我们最开始会接触一些框架的注解,例如spring等,但是这些注解是怎么起作用的呢?我们怎样实现自己的注解呢?
一、注解的实现原理
一言以蔽之,原理就是打个标签(类或方法等上使用 @注解),然后在特定时机处理标签(检测到标签后,加相应的功能)。
我们使用注解时,只接触打标签,也就是编码加上各种 @注解,而标签的处理则隐藏在框架或工具类中,嫌少接触。
1.1 怎样定义注解(打标签)
如下,跟定义接口一样,不过类型是@interface。
@Target(ElementType.METHOD) // 注解用于方法上
@Retention(RetentionPolicy.RUNTIME) // 保留到运行时,可通过注解获取
public @interface MyAnnotation {
String description();
int length() default 0;
}
这个注解上面的注解,是 java定义的元注解,用于描述注解,常用的有:
- Target:描述了注解修饰的对象范围。(TYPE-描述类、接口或enum,METHOD-描述方法等)
- Retention: 表示注解保留时间长短。(SOURE-在源文件中有效,编译过程中忽略,RUNTIME-在运行时有效)
其中,这个注解可以有属性,也可以没有属性,属性可以有默认值,也可以没有默认值。这些不重要,只是标签的附属功能。
当在类等上面使用 @ 加上注解后,只是给它打了个标签,并没有任何功能,这个标签到底对应什么功能,取决于它的注解处理器。
1.2 注解处理器 (决定了这个标签到底能干嘛)
注解会被编译进class文件中,所以获取到class对象后,就能获取到其定义在类、方法、属性等上的标签了。
所以怎样获取注解?
class对象--反射获取到方法、属性等--获取方法或属性上的注解。
Class c = XX.class;
// 获取所有字段
for(Method m : c.getMethods()){
// 判断这个字段是否有MyAnnotion注解
if(f.isAnnotationPresent(MyAnnotation.class)){
MyAnnotion annotation = f.getAnnotation(MyAnnotation.class);
}
}
1.3 常用标签的处理过程
例如经典的@Bean标签(一般不再单独使用,仅用于理解),表示这是一个spring的Bean,会初始化到spring容器中。
那这个标签是怎样起作用的呢?
首先,spring定义好了Bean注解。
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@AliasFor("name")
String[] value() default {};
@AliasFor("value")
String[] name() default {};
// 其他属性忽略
}
你在某个类型上也使用了该注解,在spring容器初始化时(refresh入口的那一堆难以理解的源码),会检测这个类有没有Bean注解,有的话,就注册。
只看其中判断有没有注解的代码。
// 判断该类是否有某注解
protected Boolean hasAnnotation(String typeName) {
try {
// 获取class对象
Class<?> clazz = ClassUtils.forName(typeName, this.getClass().getClassLoader());
// 关键是clazz.getAnnotation,获取类上的注解
return (this.considerMetaAnnotations ? AnnotationUtils.getAnnotation(clazz, this.annotationType) : clazz.getAnnotation(this.annotationType)) != null;
} catch (Throwable var3) {
// ...
}
}
二、怎样创建自定义注解
某些场景使用自定义注解,能大大简化代码。例如调用某controller方法时,添加认证信息;两个对象之间属性拷贝,处理不同名属性等。
下面以对象拷贝为例,例如对象A,对象B之间的拷贝,期望自动处理不同名属性时。
// 原实体
@Data
public class Source {
// 按属性名称转
@PropertyTransform(name = "targetName",transformStrategy = TransformStrategy.DEFAULT)
String sourceName;
}
// 目标实体
@Data
public class Target {
String targetName;
}
// 定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Component
public @interface PropertyTransform {
/**
* 目标属性
* @return
*/
@AliasFor("name")
String value() default "";
/**
* 目标属性
* @return
*/
@AliasFor("value")
String name() default "";
}
// 注解处理器
public class PropertiesTransformUtils {
@SneakyThrows
public static Object copy(Object source,Class<?> target){
Class<?> sourceClass = source.getClass();
//获取原实体下的所有属性
Field[] fields = sourceClass.getDeclaredFields();
// 初始化目标实体
Object targetObj = target.newInstance();
//记录转换名称后的属性名以及属性值
Map<String,Object> objMap = new HashMap<>(fields.length);
for (Field field : fields) {
field.setAccessible(true);
//获取属性上的注解
PropertyTransform propertyTransform = field.getAnnotation(PropertyTransform.class);
if (propertyTransform != null){
objMap.put(propertyTransform.name(),field.get(source));
}
//将值拷贝到目标实体
Object targetObj = target.newInstance();
for (Field declaredField : target.getDeclaredFields()) {
Object value = objMap.getOrDefault(declaredField.getName(),null);
declaredField.setAccessible(true);
declaredField.set(targetObj,value);
}
return targetObj;
}
总结
注解的实现分为三步:定义注解;在代码中使用注解;注解处理器赋予相应的功能。不管是框架内的注解,还是自定义注解,都是按照这三步来的。不太好理解的可能就是注解处理器赋予的各种功能。
标签:
相关文章
最新发布
- 【Python】selenium安装+Microsoft Edge驱动器下载配置流程
- Python 中自动打开网页并点击[自动化脚本],Selenium
- Anaconda基础使用
- 【Python】成功解决 TypeError: ‘<‘ not supported between instances of ‘str’ and ‘int’
- manim边学边做--三维的点和线
- CPython是最常用的Python解释器之一,也是Python官方实现。它是用C语言编写的,旨在提供一个高效且易于使用的Python解释器。
- Anaconda安装配置Jupyter(2024最新版)
- Python中读取Excel最快的几种方法!
- Python某城市美食商家爬虫数据可视化分析和推荐查询系统毕业设计论文开题报告
- 如何使用 Python 批量检测和转换 JSONL 文件编码为 UTF-8
点击排行
- 版本匹配指南:Numpy版本和Python版本的对应关系
- 版本匹配指南:PyTorch版本、torchvision 版本和Python版本的对应关系
- Python 可视化 web 神器:streamlit、Gradio、dash、nicegui;低代码 Python Web 框架:PyWebIO
- 相关性分析——Pearson相关系数+热力图(附data和Python完整代码)
- Python与PyTorch的版本对应
- Anaconda版本和Python版本对应关系(持续更新...)
- Python pyinstaller打包exe最完整教程
- Could not build wheels for llama-cpp-python, which is required to install pyproject.toml-based proj