前言
阅读本篇文章,你需要理解以下的知识:
- 重要:反射 (参考)
- Java enum
- 接口的使用
- 了解注解是什么、该什么时候使用
- 最好接触过 Spring(因为用 @RequestMapping 举例)
先说说注解
如果你熟悉 Spring 框架,你一定使用过这个注解:
@RequestMapping(value = "/admin/index.html", method = RequestMethod.GET)
这条注释的意思是:
- 用户访问"/admin/index.html"页面,则执行下方方法
- 限制用户只能使用"GET"方式访问
那么 Spring 在启动后是如何知道你用了这个注解,并且调用这个注解指定的方法的呢?
让我们先大体猜测一下:
- 我们可以配置 Spring 扫描的
@Controller
所在目录 - Spring 扫描目录,并逐个扫描
@Controller
类中的注解 - 解析所有扫描到的注解,并通过反射,执行指定注释下的方法
实例
打开你的 IDE,新建一个类 Main.java
,并复制下方语句:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
/**
* 模拟Spring的@RequestMapping注解实现原理
* @implNote 注意:本示例仅用于展示@RequestMapping注释的原理,并非真正实现了@RequestMapping注解!
* @author GitHub: AdlerED
*/
/**
* 使用@interface定义一个注解,注解名为RequestMapping
* 枚举 RequestMethod 包含两个String对象:GET | POST
* value() 指定URL,必填
* method() 指定方式,选填,默认值RequestMethod.POST
*
* @Target 元注解,指定注解用于什么地方,ElementType.METHOD 表示用于描述方法
* @Retention 元注解,指定什么时候使用该注解,RetentionPolicy.RUNTIME 表示运行期也保留注解,因此可以使用反射机制读取该注解的信息。
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface RequestMapping {
public enum RequestMethod {GET, POST}
String value();
RequestMethod method() default RequestMethod.POST;
}
/**
* Controller类,用两种方法使用自定义的@RequestMapping注解
*/
class Controller {
//由于method()方法有默认值,在注解只需要一个必填时,可以不指定方法名
@RequestMapping("/index.html")
public void mainPage() {
boolean status = true;
}
//手动指定value()方法值和method()方法值
@RequestMapping(value = "/admin/index.html", method = RequestMapping.RequestMethod.GET)
public void adminPage() {
boolean status = false;
}
}
public class Main {
/**
* 主方法,用于将Controller类中使用注解的内容进行反射
*/
public static void main(String[] args) {
try {
//获取Controller类的反射
Class clazz = Controller.class;
//反射获取Controller类中的所有方法,并遍历
for(Method method : clazz.getMethods()) {
//获取方法中的@RequestMapping注解信息
RequestMapping methodAnnotation = method.getAnnotation(RequestMapping.class);
//如果该方法使用了@RequestMapping注解,则
if(methodAnnotation != null) {
//打印方法名
System.out.println(" Method Name : " + method.getName());
//打印注解value()的值
System.out.println(" Value : " + methodAnnotation.value());
//打印注解method()的值
System.out.println(" Method : " + methodAnnotation.method());
System.out.println(" --------------------------- ");
}
}
} catch (Exception E) {
E.printStackTrace();
}
}
}
反复理解并运行语句。
运行结果:
Method Name : mainPage
Value : /index.html
Method : POST
---------------------------
Method Name : adminPage
Value : /admin/index.html
Method : GET
---------------------------
整理实例语句,有以下几点:
@interface RequestMapping {}
定义一个自定义注解,此处的interface
不是接口,因为在interface
前边还有一个@
Controller {}
类调用了@RequestMapping()
接口,并演示了数据传递的定义Main {}
类用来模拟Spring
,通过反射的方式扫描Controller
类,并将使用了@RequestMapping()
注解的方法也通过反射的方式,使其能够被修改调用。
后语
反射是 Java 的灵魂。 通过反射,我们才拥有了简单并优美的自定义注释,而不需要进行复杂的实例化,更具灵活性。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于