注解的本质与工作原理

news/2024/9/25 13:12:15/文章来源:https://www.cnblogs.com/clswhde/p/18431138

一、注解的本质是什么?

1.1 注解的定义

注解(Annotation)是Java 5引入的一种元数据(Metadata)机制,用于在代码中添加额外的信息。注解本质上是一种特殊的接口,后续会由工具和框架在编译时、类加载时、或运行时进行处理,以实现特定的功能。

1.2 注解的分类

注解可以分为三类:

  1. 标准注解:Java标准库提供的注解,如@Override、@Deprecated、@SuppressWarnings等。
  2. 元注解:用于注解其他注解的注解,如@Retention、@Target、@Inherited、@Documented等。
  3. 自定义注解:用户自定义的注解,用于特定的应用场景。

1.3 注解的本质

注解本质上是Java中的一种接口。每个注解都会自动继承java.lang.annotation.Annotation接口。当我们在代码中使用注解时,编译器会在编译后的字节码中生成相应的注解信息,这些信息可以在运行时通过反射机制获取并处理。

例如,定义一个简单的注解:

import java.lang.annotation.*;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {String value();
}

编译后的字节码中会包含MyAnnotation注解的信息,我们可以通过反射机制获取并处理这些信息。

1.4 注解的处理

注解的处理方式主要有三种:

  1. 编译时处理:通过注解处理器(Annotation Processor)在编译时处理注解,生成额外的代码或资源文件。

  2. 类加载时处理:通过字节码增强技术(如ASM、Javassist)在类加载时处理注解,修改字节码。

  3. 运行时处理:通过反射机制在运行时处理注解,实现特定的功能。

二、为何注解能够完成特定功能?

2.1 注解的运行机制

当我们在代码中使用注解时,编译器会将注解信息存储在字节码中。在运行时,框架(如Spring)通过反射机制获取注解信息,并根据注解的定义执行相应的逻辑。

例如,Spring中的@Autowired注解用于依赖注入。当Spring容器初始化时,会扫描所有的Bean,通过反射机制查找标注了@Autowired的字段或方法,并注入相应的依赖对象。

2.2 Spring注解的工作原理

Spring框架通过多种机制处理注解,包括类路径扫描、反射和动态代理等。以下是几个常用Spring注解的工作原理:

  1. @Component:用于标注一个类为Spring Bean。Spring在初始化时会扫描指定的包,将标注了@Component的类注册为Bean。

  2. @Autowired:用于自动注入依赖对象。Spring容器在创建Bean时,通过反射查找标注了@Autowired的字段或方法,并注入相应的依赖对象。

  3. @Transactional:用于声明事务。Spring AOP(面向切面编程)在运行时通过动态代理或字节码增强技术,为标注了@Transactional的方法生成代理类,实现事务管理。

2.3 Spring注解处理的核心类

Spring框架中有几个核心类负责处理注解:

  1. AnnotationConfigApplicationContext:一个基于注解配置的Spring应用上下文,实现了注解的扫描和处理。

  2. ClassPathBeanDefinitionScanner:用于扫描指定包路径下的类,并根据注解信息生成Bean定义。

  3. AutowiredAnnotationBeanPostProcessor:一个Bean后置处理器,用于处理@Autowired注解,实现依赖注入。

  4. TransactionAspectSupport:用于处理@Transactional注解,实现事务管理。

2.4 示例:@Component和@Autowired的处理流程

以下是@Component和@Autowired注解在Spring中的处理流程:

1、@Component的处理流程:

  • Spring容器启动时,AnnotationConfigApplicationContext会初始化ClassPathBeanDefinitionScanner。

  • ClassPathBeanDefinitionScanner扫描指定包路径下的类,查找标注了@Component的类。

  • 对于每个标注了@Component的类,生成相应的Bean定义,并注册到Spring容器中。

2、@Autowired的处理流程:

  • Spring容器在创建Bean时,会初始化AutowiredAnnotationBeanPostProcessor。
  • AutowiredAnnotationBeanPostProcessor通过反射查找所有Bean中标注了@Autowired的字段和方法。
  • 对于每个标注了@Autowired的字段和方法,从Spring容器中查找相应的依赖对象,并注入到目标Bean中。

2.5 实例代码

以下是一个简单的实例代码,展示@Component@Autowired注解的使用及其处理流程:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;// 定义一个Service类,标注为Spring Bean
@Component
public class MyService {public void serve() {System.out.println("Service is serving...");}
}// 定义一个Controller类,依赖于Service类
@Component
public class MyController {private final MyService myService;@Autowiredpublic MyController(MyService myService) {this.myService = myService;}public void process() {myService.serve();}
}// 配置类,启用组件扫描
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}// 测试类
public class Main {public static void main(String[] args) {// 初始化Spring容器AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);// 获取Controller Bean并调用其方法MyController controller = context.getBean(MyController.class);controller.process();// 关闭Spring容器context.close();}
}

上述代码中,Spring容器启动时会扫描com.example包路径下的所有类,找到标注了@Component的MyService和MyController类,并将它们注册为Bean。随后,通过@Autowired注解,Spring容器会自动注入MyService实例到MyController中,完成依赖注入

三、元注解是什么?

3.1 元注解的定义

元注解是用于注解其他注解的注解。元注解为注解提供了配置元数据,使得注解本身可以携带更多的信息,控制其作用范围和生命周期。

3.2 常见的元注解

Java标准库提供了几个常见的元注解,包括:

  1. @Retention:指定注解的保留策略,即注解在什么阶段可见。取值范围包括:

    • RetentionPolicy.SOURCE:注解仅在源码中保留,编译时会被丢弃。

    • RetentionPolicy.CLASS:注解在编译时保留,但不会被加载到JVM中(默认值)。

    • RetentionPolicy.RUNTIME:注解在运行时保留,可以通过反射机制读取。

  2. @Target:指定注解可以应用的程序元素。取值范围包括:

    • ElementType.TYPE:类、接口或枚举。

    • ElementType.FIELD:字段。

    • ElementType.METHOD:方法。

    • ElementType.PARAMETER:方法参数。

    • ElementType.CONSTRUCTOR:构造函数。

    • ElementType.LOCAL_VARIABLE:局部变量。

    • ElementType.ANNOTATION_TYPE:注解类型。

    • ElementType.PACKAGE:包。

  3. @Inherited:指定注解可以被子类继承。

  4. @Documented:指定注解将包含在Javadoc中。

3.3 示例:自定义注解及元注解的使用

以下是一个示例代码,展示如何自定义注解

并使用元注解:

import java.lang.annotation.*;// 定义一个自定义注解,使用元注解进行配置
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface MyCustomAnnotation {String value() default "default";
}// 使用自定义注解
public class Example {@MyCustomAnnotation(value = "example")public void myMethod() {// 方法实现}
}// 解析自定义注解
import java.lang.reflect.Method;public class AnnotationProcessor {public static void main(String[] args) throws Exception {Method method = Example.class.getMethod("myMethod");if (method.isAnnotationPresent(MyCustomAnnotation.class)) {MyCustomAnnotation annotation = method.getAnnotation(MyCustomAnnotation.class);System.out.println("Annotation value: " + annotation.value());}}
}

在上述代码中,定义了一个自定义注解MyCustomAnnotation,并使用元注解@Retention、@Target和@Documented对其进行配置。通过反射机制,可以在运行时解析该注解并获取注解信息。

四、Spring注解源码解析

4.1 @Component注解源码解析

@Component注解是Spring框架中最基本的注解,用于将一个类标识为Spring Bean。以下是@Component注解的源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Component {String value() default "";
}

@Component注解本身使用了三个元注解:@Target、@Retention和@Documented。其中,@Target(ElementType.TYPE)表示@Component注解可以应用于类、接口或枚举;@Retention(RetentionPolicy.RUNTIME)表示@Component注解在运行时可见;@Documented表示@Component注解将包含在Javadoc中。

4.2 @Autowired注解源码解析

@Autowired注解用于自动注入依赖对象。以下是@Autowired注解的源码:

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {boolean required() default true;
}

@Autowired注解使用了@Target、@Retention和@Documented元注解。其中,@Target元注解指定@Autowired可以应用于构造函数、字段、方法和注解类型;@Retention(RetentionPolicy.RUNTIME)表示@Autowired注解在运行时可见;@Documented表示@Autowired注解将包含在Javadoc中。

4.3 @Transactional注解源码解析

@Transactional注解用于声明事务。以下是@Transactional注解的源码:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {String value() default "";// 其他属性省略
}

@Transactional注解使用了@Target、@Retention、@Inherited和@Documented元注解。其中,@Target元注解指定@Transactional可以应用于方法和类;@Retention(RetentionPolicy.RUNTIME)表示@Transactional注解在运行时可见;@Inherited表示@Transactional注解可以被子类继承;@Documented表示@Transactional注解将包含在Javadoc中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/803455.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

记.Net Framework中wwwroot文件限制用户访问

背景 项目.Net Framework做的,已经线上跑了很多年了,突然发现用户上传的文件都被放到了wwwroot//Content/Upload目录,这些文件都是比较重要的,程序用来读取解析数据的,但是被直接可以公开访问了。 其实要改也很简单,代码改一下,文件挪一下位置就可以了,但是如果这样改就…

项目可能问问题

项目和简历 hr面试问题 自我介绍 面试官你好,我叫王首都,重庆邮电大学 计算机科学与技术专业研二在读,主要从事java后端开发,项目达人探店,它主要,实现了登录验证,缓存查询,优惠券秒杀,接口限流,以及签到打卡等功能。在上学期间获得了人民奖学金,新生奖学金,学业讲…

MongoDB 双活集群在运营商的实践

本文将着重分享某头部运营商订单中心在实现双活架构过程中的最佳实践,提供详细的技术细节和实际案例。通过介绍项目实施过程中的技术细节,提供类似场景需求的方案参考。在现代电信行业中,订单中心作为核心业务系统之一,承担着处理客户订单、管理订单状态、与各个业务系统进…

信创里程碑:TapData 与海量数据达成产品兼容互认证,共同助力基础设施国产化建设

测试结果显示,TapData LDP V3 与 Vastbase G100 V2.2 完全兼容,整体运行稳定高效,性能表现优秀,可为企业级客户提供可靠的中间件与数据库支撑。近日,深圳钛铂数据有限公司(以下简称钛铂数据)自主研发的钛铂实时数据平台(TapData Live Data Platform,TapData LDP)与北…

【日记】感觉自己已经魔怔了(817 字)

正文下午装档案的时候,无意间朝外看了一眼,发现自己视力衰退了好多。感觉两只眼睛都有散光了,看东西有重影。有些担心。兄长血检报告出来了,血红蛋白高,肌酐低。尿酸倒是正常了,但总体还是偏高。我觉得好奇怪,他降尿酸怎么这么难…… 更奇怪的是他说心电图时不紧张,但窦…

DNS正向解析和反向解析的区别

在网络世界中,域名系统(DNS)起着至关重要的作用,它就如同网络世界的导航地图,帮助我们在浩瀚的数字海洋中准确找到目标。而在DNS中,正向解析和反向解析是两个重要的概念,它们有着明显的区别。 首先,正向解析是将域名转换为IP地址的过程。当我们在浏览器中输入一个网址,…

DNS云解析和普通解析一样吗

在当今数字化时代,网络的稳定与高效运行至关重要。域名系统(DNS)作为互联网的基础设施之一,其解析服务的质量直接影响着用户的网络体验。近年来,DNS云解析逐渐兴起,与传统的普通解析相比,它们之间存在着显著的区别。 首先,在可靠性方面,DNS云解析具有明显优势。普通解…

【学习笔记】数学证明方法

持续更新中持续更新中最值定理前提条件: 函数 \(f(x)\) 在区间内是连续的在满足前提的情况下,设区间上界为 \(a\),下界为 \(b\) 那么函数 \(f(x)\) 一定能取到区间 \((a,b)\) 内的所有值介值定理前提条件: 函数 \(f(x)\) 在区间内是连续的当区间 \([a,b]\) 上界为 \(A\),下…

【YashanDB知识库】多表更新报错 YAS-04344 multi-table update is not supported

本文内容来自YashanDB官网,具体内容请见https://www.yashandb.com/newsinfo/7369204.html?templateId=1718516 【问题分类】功能使用 【关键字】YAS-04344,UPDATE,multi-table update,MERGE INTO 【问题描述】 在崖山环境执行类似以下语法进行多表更新报 YAS-04344 multi-…

解决方案 | ObjectARX开发版本对照表CAD1997-CAD2025,ObjectARX SDK版本、ObjectARX-Wizards版本、CAD版本、VS版本匹配表

众所周知,在一般情况下,需要ObjectARX SDK版本、ObjectARX-Wizards版本、CAD版本、VS版本版本匹配才能进行CAD二次开发。根据网络数据整理如下。 参考资料:https://blog.csdn.net/zhoufei95/article/details/121553501

【YashanDB知识库】查询YashanDB表空间使用率

本文转自YashanDB官网,具体内容请见https://www.yashandb.com/newsinfo/7369203.html?templateId=1718516 【问题分类】功能使用 【关键字】表空间,使用率 【问题描述】YashanDB使用过程中,如何查询表空间的使用率 【问题原因分析】需要查询相应的YashanDB系统表,计算表空…

QT C++ 自学积累 『非技术文』

QT C++ 自学积累 『非技术文』最近一段时间参与了一个 QT 项目的开发,使用的是 C++ 语法,很遗憾的是我之前从来没有接触过 C++ ,大学没有开过这堂课,也没用自己学习过,所有说上手贼慢,到现在为止其实也不是很清楚具体的开发技巧,毕竟是参与,东一复制西一粘贴的,就拉倒…