SpringMVC之自定义注解

简介: SpringMVC之自定义注解

前言

随着Web开发的发展,越来越多的企业开始使用SpringMVC框架来构建自己的Web应用程序。在开发过程中,为了提高代码的可读性和可维护性,我们经常需要自定义注解。本文将介绍如何编写一个自定义注解,并通过一个简单的例子来演示如何使用它。

一、自定义注解

Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。 注解相关类都包含在java.lang.annotation包中。

2. 注解的用处

  • 配置和元数据:注解可以用于配置和描述类、方法、字段等元素的特性和行为。例如,我们可以使用注解来指定数据库表的名称、字段的长度、方法的访问权限等。
  • 编译时检查:注解可以用于在编译时对代码进行静态检查,以确保代码的正确性和合规性。例如,我们可以使用注解来标记过时的方法或类,编译器会在编译时给出警告。
  • 运行时处理:注解可以在运行时通过反射机制获取到,并根据注解的定义来执行相应的逻辑。例如,我们可以使用注解来实现自定义的AOP(面向切面编程)逻辑,或者在某些条件下动态地修改方法的行为。
  • 文档生成:注解可以用于生成文档,以便开发者更好地理解代码的含义和使用方式。例如,我们可以使用注解来标记API的使用示例、参数的说明等。

3. 为什么要用注解

  • 减少样板代码:通过使用注解,我们可以将一些重复性的代码抽象为注解,从而减少冗余的代码量。
  • 提高代码可读性:注解可以用于描述代码的特性和行为,使代码更加易于理解和阅读。
  • 增强代码的可维护性:通过使用注解,我们可以将一些与业务逻辑无关的代码与业务逻辑分离,使代码更加模块化和可维护。
  • 提高开发效率:使用注解可以简化一些繁琐的操作,提高开发效率。

4.自定义注解的应用场景

应用场景十分广泛,举例说明几个:

  • 在SpringMVC中,我们可以使用自定义注解来标记Controller中的方法,以实现请求的映射和处理。
  • 在MyBatis中,我们可以使用自定义注解来标记Mapper接口中的方法,以实现SQL语句的映射和执行。
  • 在JUnit中,我们可以使用自定义注解来标记测试方法,以实现自动化测试的执行。

5. 注解的分类

  • JDK元注解:元注解是用于注解其他注解的注解,它可以用于指定注解的作用范围、生命周期等。常见的元注解有@Target@Retention@Documented等。
  • JDK基本注解:标准注解是Java提供的一些常用注解,例如@Override@Deprecated@SuppressWarnings等。
  • 自定义注解:自定义注解是开发者根据自己的需求定义的注解,用于实现特定的功能或逻辑。
  • 框架注解:框架注解是一些常用框架提供的注解,用于实现框架的特定功能。例如,Spring框架提供的@Autowired@RequestMapping等注解。

6.如何定义并使用自定义注解

自定义注解的定义非常简单,只需要使用@interface关键字即可。

1. package com.ctb.utils;
2. import java.lang.annotation.ElementType;
3. import java.lang.annotation.Retention;
4. import java.lang.annotation.RetentionPolicy;
5. import java.lang.annotation.Target;
6. 
7. @Target(ElementType.METHOD)
8. @Retention(RetentionPolicy.RUNTIME)
9. public @interface CustomAnnotation {
10.     String value() default "";
11. }

我们定义了一个名为CustomAnnotation的注解。该注解可以应用于方法上,并且在运行时保留。注解中还定义了一个名为value的属性,默认为空字符串。

使用自定义注解非常简单,只需要在需要标记的地方使用注解即可。

1. @CustomAnnotation("这是一个自定义注解示例")
2. public void doSomething() {
3. // 执行一些操作
4. 
5. }

7.自定义注解三种使用案例

案例一:

1. 定义一个枚举类:用来表示一组固定的值。

1. package com.ctb.model;
2. 
3. public enum  TranscationModel {
4.     Read, Write, ReadWrite
5. }

2. 定义三个不同注解方式的类:

MyAnnotation1 :  

1. package com.ctb.annotation;
2. 
3. import java.lang.annotation.*;
4. 
5. /**
6.  * MyAnnotation1注解可以用在类、接口、属性、方法上
7.  * 注解运行期也保留
8.  * 不可继承
9.  */
10. @Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD})
11. @Retention(RetentionPolicy.RUNTIME)
12. @Documented
13. public @interface MyAnnotation1 {
14.     String name();
15. }

MyAnnotation2 :  

1. package com.ctb.annotation;
2. 
3. import com.ctb.model.TranscationModel;
4. 
5. import java.lang.annotation.*;
6. 
7. /**
8.  *  MyAnnotation2注解可以用在方法上
9.  *  注解运行期也保留
10.  *  不可继承
11.  */
12. @Target(ElementType.METHOD)
13. @Retention(RetentionPolicy.RUNTIME)
14. @Documented
15. public @interface MyAnnotation2 {
16.     TranscationModel model() default TranscationModel.ReadWrite;
17. }

MyAnnotation3 :  

1. package com.ctb.annotation;
2. 
3. import com.ctb.model.TranscationModel;
4. 
5. import java.lang.annotation.*;
6. 
7. 
8. /**
9.  * MyAnnotation3注解可以用在方法上
10.  * 注解运行期也保留
11.  * 可继承
12.  */
13. @Target(ElementType.METHOD)
14. @Retention(RetentionPolicy.RUNTIME)
15. @Inherited
16. @Documented
17. public @interface MyAnnotation3 {
18.     TranscationModel[] models() default TranscationModel.ReadWrite;
19. }

Demo1测试类 : 获取类与方法上的注解值

1. package com.ctb.annotation.demo;
2. 
3. import com.ctb.annotation.MyAnnotation1;
4. import com.ctb.annotation.MyAnnotation2;
5. import com.ctb.annotation.MyAnnotation3;
6. import com.ctb.model.TranscationModel;
7. 
8. /**
9.  * 获取类与方法上的注解值
10.  */
11. @MyAnnotation1(name = "abc")
12. public class Demo1 {
13. 
14. @MyAnnotation1(name = "xyz")
15. private Integer age;
16. 
17. @MyAnnotation2(model = TranscationModel.Read)
18. public void list() {
19.         System.out.println("list");
20.     }
21. 
22. @MyAnnotation3(models = {TranscationModel.Read, TranscationModel.Write})
23. public void edit() {
24.         System.out.println("edit");
25.     }
26. }

Demo1Test测试类:

1. package com.ctb.annotation.demo;
2. 
3. import com.ctb.annotation.MyAnnotation1;
4. import com.ctb.annotation.MyAnnotation2;
5. import com.ctb.annotation.MyAnnotation3;
6. import com.ctb.model.TranscationModel;
7. import org.junit.Test;
8. 
9. public class Demo1Test {
10.     @Test
11.     public void list() throws Exception {
12. //        获取类上的注解
13.         MyAnnotation1 annotation1 = Demo1.class.getAnnotation(MyAnnotation1.class);
14.         System.out.println(annotation1.name());//abc
15. 
16. //        获取方法上的注解
17.         MyAnnotation2 myAnnotation2 = Demo1.class.getMethod("list").getAnnotation(MyAnnotation2.class);
18.         System.out.println(myAnnotation2.model());//Read
19. 
20. //        获取属性上的注解
21.         MyAnnotation1 myAnnotation1 = Demo1.class.getDeclaredField("age").getAnnotation(MyAnnotation1.class);
22.         System.out.println(myAnnotation1.name());// xyz
23.     }
24. 
25.     @Test
26.     public void edit() throws Exception {
27.         MyAnnotation3 myAnnotation3 = Demo1.class.getMethod("edit").getAnnotation(MyAnnotation3.class);
28. for (TranscationModel model : myAnnotation3.models()) {
29.             System.out.println(model);//Read,Write
30.         }
31.     }
32. }

@Ingerited的使用

@Inherited注解是Java中的元注解之一,用于控制注解的继承性。当一个类或接口被@Inherited注解修饰时,它的子类将自动获得该注解。但需要注意的是,@Inherited只对类和接口有效,对方法、字段等无效。

普通的类继承是指子类可以继承父类的所有非private的成员变量和方法,包括构造器。子类可以使用父类中的方法和属性,也可以重写父类的方法,在其基础上进行扩展或修改。

执行list方法测试结果

执行edit方法测试结果

案例二:

1. 自定义注解类:

1. package com.ctb.annotation;
2. 
3. import java.lang.annotation.ElementType;
4. import java.lang.annotation.Retention;
5. import java.lang.annotation.RetentionPolicy;
6. import java.lang.annotation.Target;
7. 
8. //@Retention(RetentionPolicy.SOURCE)
9. @Retention(RetentionPolicy.RUNTIME)
10. @Target(ElementType.FIELD)
11. public @interface TestAnnotation {
12.     String value() default "默认value值";
13. 
14.     String what() default "这里是默认的what属性对应的值";
15. }

2. 定义测试类:获取类属性上的注解属性值

1. package com.ctb.annotation.demo2;
2. 
3. import com.ctb.annotation.TestAnnotation;
4. 
5. /**
6.  * 获取类属性上的注解属性值
7.  */
8. public class Demo2 {
9. @TestAnnotation(value = "这就是value对应的值_msg1", what = "这就是what对应的值_msg1")
10. private static String msg1;
11. 
12. @TestAnnotation("这就是value对应的值1")
13. private static String msg2;
14. 
15. @TestAnnotation(value = "这就是value对应的值2")
16. private static String msg3;
17. 
18. @TestAnnotation(what = "这就是what对应的值")
19. private static String msg4;
20. }

3. 测试

1. package com.ctb.annotation.demo2;
2. 
3. import com.ctb.annotation.TestAnnotation;
4. import org.junit.Test;
5. 
6. public class Demo2Test {
7.     @Test
8.     public void test1() throws Exception {
9.         TestAnnotation msg1 = Demo2.class.getDeclaredField("msg1").getAnnotation(TestAnnotation.class);
10.         System.out.println(msg1.value());
11.         System.out.println(msg1.what());
12.     }
13. 
14.     @Test
15.     public void test2() throws Exception{
16.         TestAnnotation msg2 = Demo2.class.getDeclaredField("msg2").getAnnotation(TestAnnotation.class);
17.         System.out.println(msg2.value());
18.         System.out.println(msg2.what());
19.     }
20. 
21.     @Test
22.     public void test3() throws Exception{
23.         TestAnnotation msg3 = Demo2.class.getDeclaredField("msg3").getAnnotation(TestAnnotation.class);
24.         System.out.println(msg3.value());
25.         System.out.println(msg3.what());
26.     }
27. 
28.     @Test
29.     public void test4() throws Exception{
30.         TestAnnotation msg4 = Demo2.class.getDeclaredField("msg4").getAnnotation(TestAnnotation.class);
31.         System.out.println(msg4.value());
32.         System.out.println(msg4.what());
33.     }
34. }

案例三:

1.创建自定义注解:

1. package com.ctb.annotation;
2. 
3. import java.lang.annotation.*;
4. 
5. /**
6.  * 非空注解:使用在方法的参数上,false表示此参数可以为空,true不能为空
7.  */
8. @Documented
9. @Target({ElementType.PARAMETER})
10. @Retention(RetentionPolicy.RUNTIME)
11. public @interface IsNotNull {
12. boolean value() default false;
13. }

2. 创建测试类:

1. package com.ctb.annotation.demo3;
2. 
3. import com.ctb.annotation.IsNotNull;
4. 
5. /**
6.  * 获取参数修饰注解对应的属性值
7.  */
8. public class Demo3 {
9. 
10. public void hello1(@IsNotNull(true) String name) {
11. System.out.println("hello:" + name);
12.     }
13. 
14. public void hello2(@IsNotNull String name) {
15. System.out.println("hello:" + name);
16.     }
17. }

3. 测试

1. package com.ctb.annotation.demo3;
2. 
3. import com.ctb.annotation.IsNotNull;
4. import org.junit.Test;
5. 
6. import java.lang.reflect.Method;
7. import java.lang.reflect.Parameter;
8. 
9. public class Demo3Test {
10. 
11.     @Test
12.     public void hello1() throws Exception {
13.         Demo3 demo3 = new Demo3();
14. for (Parameter parameter : demo3.getClass().getMethod("hello1", String.class).getParameters()) {
15.             IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);
16. if(annotation != null){
17.                 System.out.println(annotation.value());//true
18.             }
19.         }
20.     }
21. 
22.     @Test
23.     public void hello2() throws Exception {
24.         Demo3 demo3 = new Demo3();
25. for (Parameter parameter : demo3.getClass().getMethod("hello2", String.class).getParameters()) {
26.             IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);
27. if(annotation != null){
28.                 System.out.println(annotation.value());//false
29.             }
30.         }
31.     }
32. 
33.     @Test
34.     public void hello3() throws Exception {
35. //        模拟浏览器传递到后台的参数 解读@requestParam
36. String name = "zs";
37.         Demo3 demo3 = new Demo3();
38. Method method = demo3.getClass().getMethod("hello1", String.class);
39. for (Parameter parameter : method.getParameters()) {
40.             IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);
41. if(annotation != null){
42.                 System.out.println(annotation.value());//true
43. if (annotation.value() && !"".equals(name)){
44. method.invoke(demo3,name);
45.                 }
46.             }
47.         }
48.     }
49. }

二、Aop自定义注解的应用  

1 .自定义注解类

1. package com.ctb.annotation;
2. 
3. import java.lang.annotation.ElementType;
4. import java.lang.annotation.Retention;
5. import java.lang.annotation.RetentionPolicy;
6. import java.lang.annotation.Target;
7. 
8. @Target(ElementType.METHOD)
9. @Retention(RetentionPolicy.RUNTIME)
10. public @interface MyLog {
11.     String desc();
12. }

2.切面类

1. package com.ctb.aspect;
2. 
3. import com.ctb.annotation.MyLog;
4. import org.aspectj.lang.JoinPoint;
5. import org.aspectj.lang.annotation.Aspect;
6. import org.aspectj.lang.annotation.Before;
7. import org.aspectj.lang.annotation.Pointcut;
8. import org.aspectj.lang.reflect.MethodSignature;
9. import org.slf4j.Logger;
10. import org.slf4j.LoggerFactory;
11. import org.springframework.stereotype.Component;
12. 
13. @Component
14. @Aspect
15. public class MyLogAspect {
16. private static final Logger logger = LoggerFactory.getLogger(MyLogAspect.class);
17. 
18. /**
19.      * 只要用到了com.javaxl.p2.annotation.springAop.MyLog这个注解的,就是目标类
20.      */
21. @Pointcut("@annotation(com.ctb.annotation.MyLog)")
22. private void MyValid() {
23.     }
24. 
25. @Before("MyValid()")
26. public void before(JoinPoint joinPoint) {
27.         MethodSignature signature = (MethodSignature) joinPoint.getSignature();
28.         logger.debug("[" + signature.getName() + " : start.....]");
29.         System.out.println("[" + signature.getName() + " : start.....]");
30. 
31.         MyLog myLog = signature.getMethod().getAnnotation(MyLog.class);
32.         logger.debug("【目标对象方法被调用时候产生的日志,记录到日志表中】:"+myLog.desc());
33.         System.out.println("【目标对象方法被调用时候产生的日志,记录到日志表中】:" + myLog.desc());
34.     }
35. }

3.Controller层

1. package com.ctb.web;
2. 
3. import com.ctb.annotation.MyLog;
4. import org.springframework.stereotype.Component;
5. 
6. @Component
7. public class LogController {
8. @MyLog(desc = "这是结合spring aop知识,讲解自定义注解应用的一个案例")
9. public void testLogAspect(){
10.         System.out.println("记录日志...");
11.     }
12. }


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
6月前
|
前端开发 Java 编译器
SpringMVC自定义注解---[详细介绍]
SpringMVC自定义注解---[详细介绍]
27 0
|
6月前
|
监控 Java 编译器
SpringMVC之自定义注解
SpringMVC之自定义注解
33 0
|
7月前
|
前端开发 Java
48SpringMVC - 参数绑定(自定义)
48SpringMVC - 参数绑定(自定义)
28 0
|
6月前
|
安全 Java 数据库连接
【springMvc】自定义注解的使用方式
【springMvc】自定义注解的使用方式
64 0
|
2天前
|
前端开发 安全 Java
解锁高级技巧:玩转 Spring MVC 自定义拦截器的神奇世界
解锁高级技巧:玩转 Spring MVC 自定义拦截器的神奇世界
79 0
|
2天前
|
缓存 安全 Java
SpringMVC自定义注解和使用
SpringMVC自定义注解和使用
95 0
|
5月前
|
Java
springmvc之自定义注解-->自定义注解简介,基本案例和aop自定义注解
springmvc之自定义注解-->自定义注解简介,基本案例和aop自定义注解
34 0
|
5月前
|
Java 开发者
SpringMVC----自定义注解
SpringMVC----自定义注解
30 0
|
5月前
|
Java
【SpringMVC】之自定义注解
【SpringMVC】之自定义注解
36 0
|
6月前
|
JSON 安全 Java
SpringMVC之自定义注解(这期博客带你领略自定义注解的魅力)
SpringMVC之自定义注解(这期博客带你领略自定义注解的魅力)
47 0
SpringMVC之自定义注解(这期博客带你领略自定义注解的魅力)