java里spring自定义注解如何组合原有注解,如自定义@AjaxRequestMapping=@ResponseBody+@RequestMapping

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java里spring自定义注解如何组合原有注解,如自定义@AjaxRequestMapping=@ResponseBody+@RequestMapping相关的知识,希望对你有一定的参考价值。

看到@RestController=@Controller+@ResponseBody的效果,于是我写了一个自定义注解来组合,如下:
@Target( ElementType.METHOD, ElementType.TYPE )
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping
@ResponseBody
public @interface AjaxRequestMapping
String name() default "";
String[] value() default ;
RequestMethod[] method() default RequestMethod.POST ;
String[] params() default ;
String[] headers() default ;
String[] consumes() default ;
String[] produces() default "application/json;charset=utf-8" ;

希望效果是用:
@AjaxRequestMapping("upload/file")
来替代原本的
@ResponseBody
@RequestMapping(value = "upload/file", method = RequestMethod.POST, produces = "application/json;charset=utf-8")

但是结果导致所有的请求都响应400异常,显然@AjaxRequestMapping的属性没有被@RequestMapping所获取。
请问大家,怎样才能起到@AjaxRequestMapping=@ResponseBody+@RequestMapping的效果?

参考技术A @AliasFor(
annotation = RequestMapping.class
)
String[] value() default ;
用这种格式书写才能把值传递给@RequestMapping中去
参考技术B

请使用 @RestController + @GetMapping/@PostMappi

@RestControlle("/api/test")
class Api

    @GetMapping("/list")
    Object list(@RequestParam("page")Integer page)
        //TODO 
    

参考技术C 人家定义的注解时,是那样写的,,,,,,你可以自己修改注解,来实现。。。。。。。。。。。

深入理解java注解及应用

注解的本质

Java注解(Annotation)又称 Java 标注,Java标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 ,也支持自定义 Java 标注。

  • 元注解:用于修饰注解的注解,通常用在注解的定义上。
  • java.lang.annotation包提供了四种元注解:
    在这里插入图片描述

元注解 底层是什么?
元注解的处理逻辑由apt tool提供,对注解的行为做出一些限制,例如生命周期,作用范围等。

  • 元注解中的参数
    注解中的参数,通过源码中的注释都有明确的说明,这里举例一下@Retention接口的参数,其他几个都是类似的步骤可以查看
    @Retention注解
    进入RetentionPolicy类中可以查看到,参数的值有哪些以及每个参数的含义
    值的查看

Java内置注解

@Override

作用:检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误
override
@Target(ElementType.METHOD)]:该注解用于描述方法
@Retention(RetentionPolicy.SOURCE):该注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃

@Deprecated

作用:标记过时方法。如果使用该方法,会报编译警告
deprecated
@Documented:注解是否将包含在JavaDoc中
@Retention(RetentionPolicy.RUNTIME):注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
  - CONSTRUCTOR:可用于描述构造器
  - FIELD:可用于描述域
  - LOCAL_VARIABLE:可用于描述局部变量
  - METHOD:可用于描述方法
  - PACKAGE:可用于描述包
  - PARAMETER:可用于描述参数
  - TYPE:可用于描述类、接口或enum声明

@SuppressWarnings

作用:指示编译器去忽略注解中声明的警告
SuppressWarnings
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}):
  - FIELD:可用于描述域
  - METHOD:可用于描述方法
  - PARAMETER:可用于描述参数
  - CONSTRUCTOR:可用于描述构造器
  - LOCAL_VARIABLE:可用于描述局部变量

@Retention(RetentionPolicy.SOURCE):注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃

自定义注解

如何自定义一个注解?

/******************自定义注解-MyClass-修饰类******************/
@Target(ElementType.TYPE) //用于描述类、接口(包括注解类型) 或enum声明
@Retention(RetentionPolicy.RUNTIME) //jvm加载class文件之后,仍然存在
@Inherited //具有继承性
@interface MyClass
{
    String value();
}
/******************自定义注解-MyMethod-修饰方法******************/
@Documented //包含在JavaDoc中
@Target({ElementType.METHOD}) //用于描述方法
@Retention(RetentionPolicy.RUNTIME) //jvm加载class文件之后,仍然存在
@interface MyMethod
{
}
/******************自定义注解-MyVar-修饰变量******************/
@Target(ElementType.FIELD) //用于描述变量
@Retention(RetentionPolicy.RUNTIME) //jvm加载class文件之后,仍然存在
@interface MyVar
{
    int min(); //最小长度
}

如何使用自定义注解?

@MyClass("Test")
class Test{
    @MyVar(min = 5) //指定name的最小长度为5
    private String name;

	public Test(String name) {
        this.name = name;
    }

    @MyMethod
    public void printName() {
        System.out.println("name is " + name);
    }
}

自定义注解如何生效?

只是定义一个注解,并把注解使用在合适的位置,但是注解本身并没有生效。一个注解,如果没有解析它的代码,它就只是一个没有意义的标记。

public class AnnotationTest {
    public static void main(String[] args) {
        Test test = new Test("cloverning");
        try {
            Class clazz = test.getClass();
            //根据反射判断对象是否包含MyClass注解
            if (clazz.isAnnotationPresent(MyClass.class)) {
                MyClass myClazz = (MyClass) clazz.getAnnotation(MyClass.class);
                System.out.println("MyClass:" + myClazz.value());
                //获取Test类下的属性
                Field field = clazz.getDeclaredField("name");
                if (field.isAnnotationPresent(MyVar.class)) { //该属性是否包含MyVar注解
                    MyVar myVar = field.getDeclaredAnnotation(MyVar.class);
                    field.setAccessible(true);
                    //效验该类中被MyVar修饰的变量是否符合规则
                    //String.valueOf(field.get(test)):获取test中name的值
                    //myVar.min():获取注解中设置的变量的最小长度min
                    if (String.valueOf(field.get(test)).length() >= myVar.min()) {
                        //符合规则,则执行被MyMethod注解修饰的方法
                        Method[] myMethods = clazz.getDeclaredMethods();
                        for (Method method : myMethods) {
                            if (method.isAnnotationPresent(MyMethod.class)) {
                                method.invoke(test);
                            }
                        }
                    } else {
                        System.out.println("name长度不符合规则,值为:" + field.get(test));
                    }
                } else {
                    System.out.println("name属性没有配置MyVar注解!");
                }
            } else {
                System.out.println("没有配置MyClass注解!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

注解其实就是一个实现了Annotation的接口,而我们通过反射获取到的实际上是通过JDK动态代理生成的代理类,这个类实现了我们的注解接口。在实际项目中,使注解生效的代码一般通过拦截器或者切面来实现

Spring中@Bean注解

@Bean的定义

bean

@Bean的使用

beanuse

@Bean的生效方式

通过在源码中打断点的方式,在org.springframework.context.annotation.ConfigurationClassParser类的doProcessConfigurationClass中,检索@Bean修饰的方法,把方法的metadata和类configClass封装成BeanMethod加入到ConfigurationClass中的beanMethods集合中,也就是收集@Bean修饰的方法。
在这里插入图片描述
进入retrieveBeanMethodMetadata中,可以看到也是通过反射的方式获取到被@Bean注解修饰的数据。
在这里插入图片描述
然后,具体的逻辑就不做过多解释啦,大家打个断点自己跟着走一走看一看是最好的,本篇文章实际上就是想解释注解到底是个怎么回事,虽然标题是深入理解,感觉其实写的也没有那么深入啦!

以上是关于java里spring自定义注解如何组合原有注解,如自定义@AjaxRequestMapping=@ResponseBody+@RequestMapping的主要内容,如果未能解决你的问题,请参考以下文章

@Resource注解到底该怎么用?

spring 自定义注解(annotation)与 aop获取注解

自定义SpringBoot Starter 通过注解启动装配

使用自定义注解做参数必填的校验

SpringBoot Starter自定义注解 - 接口加解密

深入理解java注解及应用