@RestController 源码解读:解决 Web 开发中 REST 服务的疑难杂症

目录

一、@RestContrller注解

1.1 查看底层源码

1.2 @AliasFor注解说明

1.2.1 注解别名

1.2.2 元数据别名

1.3 value() 方法的作用


一、@RestContrller注解

1.1 查看底层源码

首先编写如下内容:

@RestController
public class TestController {

    
}

按住 Ctrl , 鼠标点击 @RestController 进入源码:

  1. @Target注解说明:查看底层源码发现
     

  2. @Documented:标明这个注解会包含在JavaDoc文档中

  3. @Retention:表示这个注解在运行时仍然有效,可以通过反射机制读取。


1.2 @AliasFor注解说明

@AliasFor是Spring框架的一个注解,用于声明注解属性的别名。它有两种不同的应用场景。

  • 注解内的别名

  • 元数据的别名

1.2.1 注解别名

查看@AliasFor注解源码:


 

通过该注解可以知道@AliasFor(value="xxx")和@AliasFor(attribute="xxx")的作用是相同的,接下来我们举例说明:

  1. 首先我需要自定义一个注解

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

    当我们使用到该注解如 @MyInterface1(value1="number1"),表示 value1 的属性传入了 number1的值。现在如果自定义的注解改变为如下方式,但我希望通过 @MyInterface1(value2="number1") 达到上述相同的效果:

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

    就可以添加@Alias()注解为注解内方法(因为@Alias作用域是方法注解)起别名:

    @Retention(value = RetentionPolicy.RUNTIME)
    @Documented
    @Target(ElementType.TYPE)
    public @interface MyInterface1 {
    
        @AliasFor(value = "value2")
        String value1() default "";
    
        @AliasFor(value = "value1")
        String value2() default "";
    }

    达到 @MyInterface1(value2="number1") 和 @MyInterface1(value1="number1") 的效果相同。

注意事项:

  1. 组成别名对的每个属性都必须加上注释 @AliasFor,attribute()或value() 属性必须引用该对中另一个属性
  2. 别名属性必须声明相同的返回类型
  3. 别名属性必须声明一个默认值
  4. 别名属性必须声明相同的默认值

1.2.2 元数据别名

  1. 自定义第一个注解:

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

  2. 自定义第二个注解:

    @Retention(value = RetentionPolicy.RUNTIME)
    @Documented
    @Target(ElementType.TYPE)
    @MyInterface1
    public @interface MyInterface2 {
    
        @AliasFor(annotation = MyInterface1.class,value = "value")
        String value() default "";
    }

    此时@MyInterface1 (“number”)就和@MyInterface2(“number”)等价。这里可以理解成,注解MyInterface2的value属性重写了注解MyInterface1的value属性,但重新的属性的返回类型必须相同。

    此时再来查看@RestController 的@Alias:

        @RestController(value="xxxx")和@Controller(value="xxx")等价。

类似的使用包括:

可以看出对于value这个属性来说,@Configuration注解中的值会重写@Component的value属性值,这有点像类之间的继承,子类可以重父类的方法。我们也可以将@Configuration注解看成@Component的子注解


1.3 value() 方法的作用

@RestController的定义中,value()方法使用@AliasFor注解将其与@Controllervalue属性关联起来。这意味着当在@RestController上使用value属性时,它实际上等同于在@Controller上使用value属性,用于指定控制器的基本路径等相关信息,例如@RestController("myControllerPath")这种用法

也就是说value属性用于指定控制器的基本路径,那么我们进行接下来的测试:

  1. 首先编写Controller类代码:运行项目

    @RestController(value = "user")
    public class TestController {
        
        @RequestMapping("/test")
        public String test(){
            return "测试成功!";
        }
        
    }

    结果程序并没有识别到,发生404错误:

  2. 接下来测试/test路径:发现可以访问成功

  3. 所以如果是要填写路径的话,还是需要使用 @RequestMapping("/user/test")才是正确的,代码修改后测试:
    @RestController(value = "user")
    @RequestMapping("/user")
    public class TestController {
    
        @RequestMapping("/test")
        public String test(){
            return "测试成功!";
        }
    
    }

    此时就可以访问成功了:

  4. 一般情况下,我们修改为如下的规范:

    @RestController
    @RequestMapping("/user")
    public class TestController {
    
        @RequestMapping("/test")
        public String test(){
            return "测试成功!";
        }
    
    }

        所以value()方法的解释仅仅是 “建议”。

JDK 17 引入 records 新特性

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

敖云岚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值