惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
博客园_首页
H
Hackread – Cybersecurity News, Data Breaches, AI and More
T
ThreatConnect
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 聂微东
H
Help Net Security
T
Threat Research - Cisco Blogs
Blog — PlanetScale
Blog — PlanetScale
A
Arctic Wolf
G
Google Developers Blog
量子位
U
Unit 42
I
InfoQ
V
V2EX
F
Fox-IT International blog
P
Privacy & Cybersecurity Law Blog
V
Visual Studio Blog
J
Java Code Geeks
大猫的无限游戏
大猫的无限游戏
C
CERT Recently Published Vulnerability Notes
博客园 - 三生石上(FineUI控件)
T
The Exploit Database - CXSecurity.com
T
Tailwind CSS Blog
SecWiki News
SecWiki News
Know Your Adversary
Know Your Adversary
MyScale Blog
MyScale Blog
宝玉的分享
宝玉的分享
The Hacker News
The Hacker News
Project Zero
Project Zero
Application and Cybersecurity Blog
Application and Cybersecurity Blog
月光博客
月光博客
Recent Commits to openclaw:main
Recent Commits to openclaw:main
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
G
GRAHAM CLULEY
C
Cisco Blogs
I
Intezer
Simon Willison's Weblog
Simon Willison's Weblog
O
OpenAI News
Recorded Future
Recorded Future
T
Tenable Blog
W
WeLiveSecurity
腾讯CDC
Stack Overflow Blog
Stack Overflow Blog
T
The Blog of Author Tim Ferriss
www.infosecurity-magazine.com
www.infosecurity-magazine.com
D
Docker
C
Cybersecurity and Infrastructure Security Agency CISA
PCI Perspectives
PCI Perspectives

技术改变视野

为程序员、设计师打造的摸鱼社区:摸鱼派! - 技术改变视野 我在 GitHub 上的开源项目 - 技术改变视野 为IDEA/Git配置GPG密钥,点亮GitHub Verified Commit标识 - 技术改变视野 从 SpringMVC 转为使用 SpringBoot —— 手把手带你使用 Intellij IDEA 最快速地搭建 SpringBoot+MyBatis(无 XML)+Thymeleaf - 技术改变视野 无题 - 技术改变视野 年轻人的第一辆京牌电动车 - 技术改变视野 我们忙碌且漫长的一生,有多久是为自己而活? 说说《后浪》 - 技术改变视野 离线使用 Google Fonts:让你的网站更精致 | goofoffline 神器,一键下载生成离线字体库! - 技术改变视野 🎨 适用于 Solo / Bolo 的清新高级主题 —— Sakura | 移植自 WordPress 主题 - 技术改变视野 大白话之Java级联调用:一个类,一条语句,同时调用好几个方法,串成一串 - 技术改变视野 大白话 | Java初学指♂男:“说说初学的误区与死结”( 壹 | 反射与Field ) - 技术改变视野 一个实例理解Java的接口(interface)用处与用法 一个实例带你理解JavaBean WebFilter-SpringBoot过滤器注解实例讲解 实例带你搞懂Java多线程&&线程池之(壹):线程池与多线程的关系和区别 实例带你搞懂Java多线程&&线程池之(贰):简单的线程池应用 - 技术改变视野 实例带你获取多线程Thread的返回值之 (壹) - Callable的运行 实例带你学会简单的Java Thread多线程 实例带你获取多线程Thread的返回值之 (贰) - Callable配合线程池返回数据 一个实例理解Java Runnable多线程用处与用法 一个最简单的实例理解Semaphore在Java中的作用 从零开始OpenSSL之 (壹) - 使用genrsa、rsa、rsautl生成公私钥 从零开始 OpenSSL 之 (贰) - 使用 rsautl 解密文件 大白话之Docker(壹):快速入门&&简单官方实例 大白话之耦合性:什么是耦合性和内聚性?用编程语言实例讲解! 大白话之Docker(贰):简单部署一个Tomcat服务并发布内容 - 技术改变视野 大白话之从零讲解DVWA(壹)-SQL注入(SQL Injection) Low Level - 技术改变视野 大白话之从零讲解DVWA(贰)-SQL注入(SQL Injection) Medium/High Level Java日志插件-Slog4J下载 大白话之必会Java Atomic | 线程一点也不安全(一):比自增和synchronized更快速、靠谱的原子操作(调用C语言) Log-MySQL root用户登录后无法查看数据库全部表/正常访问数据库 Access denied for user 'root'@'localhost' to database 大白话之Docker(叁):制作一个运行Tomcat服务端的Docker镜像 Github仅保留指定文件/文件夹当前Commit,删除所有历史记录,清除「敏感信息」 将Tomcat、MySQL从Linux迁移到Windows的心路历程(干货):令人恐惧的字符编码 - 技术改变视野 Spring: java.lang.NoSuchMethodError: clearCache | ClassNotFoundException | Error during artifact deployment 思路及解决办法 - 技术改变视野 大白话之Java反射-初学最迷的概念:能干啥?咋用? 大白话之Java面向接口编程:最“正经”的中文实例讲解,看不懂来打我! 大白话 | 课堂实践:使用Iterator对数组进行遍历 大白话之fail-fast | fail-safe:为什么会有这个机制?它有什么作用? 大白话之必会Java Atomic | 线程一点也不安全(二):Atomic的ABA问题会导致什么情况?如何解决? 随笔 | 奇淫技巧 | Java:记return和短路运算符的妙用 随笔 | Tomcat:续-从Linux迁移到Windows编码问题彻底解决 - 技术改变视野 大白话之AutoClosable接口 | try-with-resources:JDK1.7的新特性,提高重复回收效率 - 技术改变视野 大白话之Java多线程join方法:开局一张图,试学一分钟,你就费和我一样,理解介个方法 大白话之Java Stream流:将类数组流化,便捷批量修改,通俗讲解! Java 困扰三周の问题:使用byte[]或skip()方法读取字节流Stream文件尾部多/少/缺字节解决方法 - 技术改变视野
刨根问底 | 大白话:在使用注解后,框架是怎么知道你哪个方法使用了注解的?用@RequestMapping注解举例详解! - 技术改变视野
adlered · 2019-12-09 · via 技术改变视野

前言

阅读本篇文章,你需要理解以下的知识:

  • 重要:反射 (参考
  • Java enum
  • 接口的使用
  • 了解注解是什么、该什么时候使用
  • 最好接触过Spring(因为用@RequestMapping举例)

先说说注解

如果你熟悉Spring框架,你一定使用过这个注解:

1@RequestMapping(value = "/admin/index.html", method = RequestMethod.GET)

这条注释的意思是:

  • 用户访问"/admin/index.html"页面,则执行下方方法
  • 限制用户只能使用"GET"方式访问

那么Spring在启动后是如何知道你用了这个注解,并且调用这个注解指定的方法的呢?

让我们先大体猜测一下:

  1. 我们可以配置Spring扫描的@Controller所在目录
  2. Spring扫描目录,并逐个扫描@Controller类中的注解
  3. 解析所有扫描到的注解,并通过反射,执行指定注释下的方法

实例

打开你的IDE,新建一个类Main.java,并复制下方语句:

 1import java.lang.annotation.ElementType;
 2import java.lang.annotation.Retention;
 3import java.lang.annotation.RetentionPolicy;
 4import java.lang.annotation.Target;
 5import java.lang.reflect.Method;
 6
 7/**
 8 * 模拟Spring的@RequestMapping注解实现原理
 9 * @implNote 注意:本示例仅用于展示@RequestMapping注释的原理,并非真正实现了@RequestMapping注解!
10 * @author GitHub: AdlerED
11 */
12
13/**
14 * 使用@interface定义一个注解,注解名为RequestMapping
15 * 枚举 RequestMethod 包含两个String对象:GET | POST
16 * value() 指定URL,必填
17 * method() 指定方式,选填,默认值RequestMethod.POST
18 *
19 * @Target 元注解,指定注解用于什么地方,ElementType.METHOD 表示用于描述方法
20 * @Retention 元注解,指定什么时候使用该注解,RetentionPolicy.RUNTIME 表示运行期也保留注解,因此可以使用反射机制读取该注解的信息。
21 */
22@Target(ElementType.METHOD)
23@Retention(RetentionPolicy.RUNTIME)
24@interface RequestMapping {
25    public enum RequestMethod {GET, POST}
26    String value();
27    RequestMethod method() default RequestMethod.POST;
28}
29
30/**
31 * Controller类,用两种方法使用自定义的@RequestMapping注解
32 */
33class Controller {
34    //由于method()方法有默认值,在注解只需要一个必填时,可以不指定方法名
35    @RequestMapping("/index.html")
36    public void mainPage() {
37        boolean status = true;
38    }
39
40    //手动指定value()方法值和method()方法值
41    @RequestMapping(value = "/admin/index.html", method = RequestMapping.RequestMethod.GET)
42    public void adminPage() {
43        boolean status = false;
44    }
45}
46
47public class Main {
48    /**
49     * 主方法,用于将Controller类中使用注解的内容进行反射
50     */
51    public static void main(String[] args) {
52        try {
53            //获取Controller类的反射
54            Class clazz = Controller.class;
55            //反射获取Controller类中的所有方法,并遍历
56            for(Method method : clazz.getMethods()) {
57                //获取方法中的@RequestMapping注解信息
58                RequestMapping methodAnnotation = method.getAnnotation(RequestMapping.class);
59                //如果该方法使用了@RequestMapping注解,则
60                if(methodAnnotation != null) {
61                    //打印方法名
62                    System.out.println(" Method Name : " + method.getName());
63                    //打印注解value()的值
64                    System.out.println(" Value : " + methodAnnotation.value());
65                    //打印注解method()的值
66                    System.out.println(" Method : " + methodAnnotation.method());
67                    System.out.println(" --------------------------- ");
68                }
69            }
70        } catch (Exception E) {
71            E.printStackTrace();
72        }
73    }
74}

反复理解并运行语句。

运行结果:

1 Method Name : mainPage
2 Value : /index.html
3 Method : POST
4 --------------------------- 
5 Method Name : adminPage
6 Value : /admin/index.html
7 Method : GET
8 --------------------------- 

整理实例语句,有以下几点:

  • @interface RequestMapping {} 定义一个自定义注解,此处的interface不是接口,因为在interface前边还有一个@
  • Controller {}类调用了@RequestMapping()接口,并演示了数据传递的定义
  • Main {}类用来模拟Spring,通过反射的方式扫描Controller类,并将使用了@RequestMapping()注解的方法也通过反射的方式,使其能够被修改调用。

后语

反射是Java的灵魂。 通过反射,我们才拥有了简单并优美的自定义注释,而不需要进行复杂的实例化,更具灵活性。