学会SpringMVC之自定义注解各种场景应用,提高开发效率及代码质量

目录

一、简介

( 1 )  是什么

( 2 )  分类 

( 3 )  作用

二、自定义注解

( 1 ) 如何自定义注解

( 2 ) 场景演示

场景一(获取类与方法上的注解值)  

场景二( 获取类属性上的注解属性值 )  

场景三( 获取参数修饰注解对应的属性值 )

三、Aop自定义注解的应用

带给我们的收获


一、简介

( 1 )  是什么

在Spring MVC中,自定义注解是一种通过Java语言提供的元注解机制,用于在控制器方法、参数、类等地方添加注解,从而实现特定的功能或行为。 

在Spring MVC中,自定义注解是一种用于标记和定义特定功能的注解。通过自定义注解,可以在控制器方法、参数、类等地方添加注解,从而实现特定的功能或行为。

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

通过自定义注解,可以提高代码的可读性和可维护性,同时也可以减少重复的代码编写。在Spring MVC中,可以使用Java的元注解来定义自定义注解,例如@Target@Retention@Documented等。

通过自定义注解,可以提高代码的可读性和可维护性,同时也可以减少重复的代码编写。在Spring MVC中,自定义注解可以应用于控制器方法的映射、参数校验、数据绑定、AOP切面等方面,从而实现特定的功能。 

( 2 )  分类 

Java注解可以分为三类:

1. 元注解(Meta-Annotation):元注解是用来注解其他注解的注解,用于对注解进行说明和定义。常用的元注解有四种:

  • - @Retention:用于指定注解的保留策略,即注解在什么地方有效。
  • 有三个取值:RetentionPolicy.SOURCE(注解仅在源代码中有效)、RetentionPolicy.CLASS(注解在源代码和class文件中有效,默认值)、RetentionPolicy.RUNTIME(注解在运行时有效)。
  • - @Target:用于指定注解的作用目标,即注解可以应用在哪些元素上。
  • 常用的取值有:ElementType.TYPE(类、接口、枚举)、ElementType.FIELD(字段)、ElementType.METHOD(方法)、ElementType.PARAMETER(方法参数)、ElementType.CONSTRUCTOR(构造函数)、ElementType.LOCAL_VARIABLE(局部变量)、ElementType.ANNOTATION_TYPE(注解)、ElementType.PACKAGE(包)等。
  • - @Documented:用于指定注解是否包含在JavaDoc中。
  • - @Inherited:用于指定注解是否可以被继承。

2. 基本注解(Built-in Annotation):基本注解是Java内置的一些注解,用于标记和修饰代码。常用的基本注解有三个:

  • - @Override:用于标记方法覆盖父类的方法。
  • - @Deprecated:用于标记已过时的方法、类或字段。
  • - @SuppressWarnings:用于抑制编译器警告。

3. 自定义注解(Custom Annotation):自定义注解是开发者根据业务需求自行定义的注解,用于标记和修饰代码。自定义注解可以通过元注解的方式进行配置,以达到特定的目的。自定义注解的作用可以是:

  • - 标记和识别特定的代码逻辑或功能。
  • - 提供额外的元数据,用于生成文档、配置文件等。
  • - 在运行时通过反射获取注解信息,实现一些特定的逻辑。
  • - 与其他框架或工具进行集成,实现特定的功能。

总结:元注解用于对其他注解进行说明和定义,基本注解是Java内置的用于标记和修饰代码的注解,而自定义注解是根据业务需求自行定义的注解,用于标记和修饰代码,并提供额外的元数据和功能。

( 3 )  作用

在Spring MVC中,自定义注解可以用于实现以下功能:

  • 1. 请求映射:可以使用自定义注解来标记Controller中的方法,用于指定请求的URL路径和请求方法。例如,可以定义一个自定义注解`@GetMapping`,用于标记处理GET请求的方法,简化了在`@RequestMapping`中指定请求方法的操作。
  • 2. 参数绑定:可以使用自定义注解来标记Controller中方法的参数,用于指定参数的来源和绑定规则。例如,可以定义一个自定义注解`@PathVariable`,用于标记方法参数,表示该参数从URL路径中获取。
  • 3. 参数校验:可以使用自定义注解来标记方法的参数,用于指定参数的校验规则。例如,可以定义一个自定义注解`@Valid`,用于标记方法参数,表示该参数需要进行校验。
  • 4. AOP切面:可以使用自定义注解来标记需要进行AOP切面处理的方法或类。例如,可以定义一个自定义注解`@Log`,用于标记需要记录日志的方法,然后通过AOP切面对标记了`@Log`注解的方法进行日志记录。
  • 5. 权限控制:可以使用自定义注解来标记需要进行权限控制的方法或类。例如,可以定义一个自定义注解`@RequiresPermission`,用于标记需要进行权限验证的方法,然后通过AOP切面对标记了`@RequiresPermission`注解的方法进行权限验证。

通过自定义注解,可以使代码更加简洁、易读,并且可以实现一些特定的功能,提高开发效率和代码的可维护性。在Spring MVC中,自定义注解的应用非常广泛,可以根据具体的业务需求进行自定义注解的定义和使用。

二、自定义注解

( 1 ) 如何自定义注解

要自定义注解,需要使用Java提供的元注解来对注解进行配置,然后使用@interface关键字定义注解的名称和属性。以下是自定义注解的步骤:

1 . 使用元注解配置注解的行为和作用范围。常用的元注解有:

  • @Retention:用于指定注解的生命周期。常用的取值有RetentionPolicy.SOURCE(注解在编译期丢弃)、RetentionPolicy.CLASS(注解在编译期保留,但在运行时丢弃,默认值)、RetentionPolicy.RUNTIME(注解在运行时保留)。
  • @Target:用于指定注解的作用目标。常用的取值有ElementType.TYPE(类、接口、枚举)、ElementType.FIELD(字段)、ElementType.METHOD(方法)、ElementType.PARAMETER(方法参数)、ElementType.CONSTRUCTOR(构造函数)、ElementType.LOCAL_VARIABLE(局部变量)、ElementType.ANNOTATION_TYPE(注解)、ElementType.PACKAGE(包)等。
  • @Documented:用于指定注解是否包含在JavaDoc中。
  • @Inherited:用于指定注解是否可以被继承。
  • @Deprecated:用于标记已过时的注解。当一个注解被标记为@Deprecated时,表示该注解已不推荐使用,可以使用其他替代的注解。

  • @Native:用于指定注解是否为本地注解。本地注解是指由JDK或第三方库提供的注解,而不是自定义的注解。

  • @SuppressWarnings:用于抑制编译器警告。可以使用@SuppressWarnings注解来忽略特定的警告信息,例如未使用的变量、未检查的类型转换等。

2 . 使用@interface关键字定义注解的名称和属性。注解的名称可以是任意合法的Java标识符,通常以大写字母开头。注解的属性使用方法类似于接口的方法,可以指定默认值。

3 . 在需要使用注解的地方使用注解。可以在类、方法、字段等地方使用自定义注解,并根据注解的属性进行配置。

4 . 在运行时通过反射获取注解信息。可以使用Java的反射机制,在运行时获取类、方法、字段等上的注解信息,并根据注解的属性进行特定的逻辑处理。

以下是一个示例,演示了如何自定义一个简单的注解:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
    String value() default "";
    int count() default 0;
}

在上面的示例中,定义了一个名为MyAnnotation的注解,使用了@Retention(RetentionPolicy.RUNTIME)元注解指定了注解在运行时保留,使用了@Target(ElementType.METHOD)元注解指定了注解可以应用在方法上。注解中定义了两个属性,一个是value,一个是count,并指定了默认值。

然后可以在需要使用注解的地方使用@MyAnnotation来标记方法,

并根据需要配置注解的属性值:

@MyAnnotation(value = "Hello", count = 10)
public void myMethod() {
    // do something
}

在运行时,可以使用反射来获取注解的信息:

Method method = MyClass.class.getMethod("myMethod");
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
String value = annotation.value(); // 获取注解的属性值
int count = annotation.count();

通过以上步骤,就可以自定义注解并在代码中使用了。根据具体的业务需求,可以定义不同的注解,并使用注解来实现特定的功能。

( 2 ) 场景演示

创建完项目之后,找到 pom.xml 配置文件 ,进行项目引用导入。




  4.0.0

  org.example
  CloudJunzySSM
  1.0-SNAPSHOT
  war

  CloudJunzySSM Maven Webapp
  
  http://www.example.com

  
    UTF-8
    1.8
    1.8
    3.7.0

    
    
    5.0.2.RELEASE
    
    3.4.5
    
    5.1.44
    
    5.1.2
    
    1.3.1
    
    2.1.1
    2.4.3
    
    2.9.1
    3.2.0
    1.7.13
    
    4.12
    4.0.0
    1.18.2

    1.1.0
    2.10.0

    2.9.0
    1.7.1.RELEASE
    2.9.3
    1.2
    1.1.2
    8.0.47
    1.3.3
    5.0.2.Final

    1.3.2
  

  

    
    
      org.springframework
      spring-core
      ${spring.version}
    
    
      org.springframework
      spring-beans
      ${spring.version}
    
    
      org.springframework
      spring-context
      ${spring.version}
    
    
      org.springframework
      spring-orm
      ${spring.version}
    
    
      org.springframework
      spring-tx
      ${spring.version}
    
    
      org.springframework
      spring-aspects
      ${spring.version}
    
    
      org.springframework
      spring-web
      ${spring.version}
    

    
      org.springframework
      spring-test
      ${spring.version}
    


    
    
      org.mybatis
      mybatis
      ${mybatis.version}
    
    
    
      mysql
      mysql-connector-java
      ${mysql.version}
    
    
    
      com.github.pagehelper
      pagehelper
      ${pagehelper.version}
    
    
    
      org.mybatis
      mybatis-spring
      ${mybatis.spring.version}
    

    
      org.springframework
      spring-context-support
      ${spring.version}
    

    
    
      org.mybatis.caches
      mybatis-ehcache
      ${mybatis.ehcache.version}
    
    
    
      net.sf.ehcache
      ehcache
      ${ehcache.version}
    

    
      redis.clients
      jedis
      ${redis.version}
    
    
      org.springframework.data
      spring-data-redis
      ${redis.spring.version}
    
    
      com.fasterxml.jackson.core
      jackson-databind
      ${jackson.version}
    
    
      com.fasterxml.jackson.core
      jackson-core
      ${jackson.version}
    
    
      com.fasterxml.jackson.core
      jackson-annotations
      ${jackson.version}
    

    
    
      org.apache.commons
      commons-dbcp2
      ${commons.dbcp2.version}
      
        
          commons-pool2
          org.apache.commons
        
      
    
    
      org.apache.commons
      commons-pool2
      ${commons.pool2.version}
    

    
    
      org.springframework
      spring-webmvc
      ${spring.version}
    

    

    
    
    
    
      org.slf4j
      slf4j-api
      ${slf4j.version}
    
    
      org.slf4j
      jcl-over-slf4j
      ${slf4j.version}
      runtime
    

    
    
      org.apache.logging.log4j
      log4j-api
      ${log4j2.version}
    
    
      org.apache.logging.log4j
      log4j-core
      ${log4j2.version}
    
    
    
      org.apache.logging.log4j
      log4j-slf4j-impl
      ${log4j2.version}
    
    
    
      org.apache.logging.log4j
      log4j-web
      ${log4j2.version}
      runtime
    

    
    
      com.lmax
      disruptor
      ${log4j2.disruptor.version}
    

    
    
      junit
      junit
      ${junit.version}

    
    
      javax.servlet
      javax.servlet-api
      ${servlet.version}
      provided
    
    
      org.projectlombok
      lombok
      ${lombok.version}
      provided
    
    
      jstl
      jstl
      ${jstl.version}
    
    
      taglibs
      standard
      ${standard.version}
    
    
      org.apache.tomcat
      tomcat-jsp-api
      ${tomcat-jsp-api.version}
    
    
      commons-fileupload
      commons-fileupload
      ${commons-fileupload.version}
    

    
      org.hibernate
      hibernate-validator
      ${hibernate-validator.version}
    

    
    
      org.apache.shiro
      shiro-core
      ${shiro.version}
    
    
      org.apache.shiro
      shiro-web
      ${shiro.version}
    
    
      org.apache.shiro
      shiro-spring
      ${shiro.version}
    
  

  
    CloudJunzySSM

    
      
      
        src/main/java
        
          **/*.xml
        
      
      
      
        src/main/resources
        
          *.properties
          *.xml
        
      
    

      

        
          org.apache.maven.plugins
          maven-compiler-plugin
          ${maven.compiler.plugin.version}
          
            ${maven.compiler.source}
            ${maven.compiler.target}
            ${project.build.sourceEncoding}
          
        
        
          org.mybatis.generator
          mybatis-generator-maven-plugin
          1.3.2
          
            
            
              mysql
              mysql-connector-java
              ${mysql.version}
            
          
          
            true
          
        

        
          maven-clean-plugin
          3.1.0
        
        
        
          maven-resources-plugin
          3.0.2
        
        
          maven-compiler-plugin
          3.8.0
        
        
          maven-surefire-plugin
          2.22.1
        
        
          maven-war-plugin
          3.2.2
        
        
          maven-install-plugin
          2.5.2
        
        
          maven-deploy-plugin
          2.8.2
        
      
  

创建配置文件 spring-context.xml







创建配置文件  spring-mybatis.xml 



    
    
    
    
    

    

    
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    

    
    
    
        
        
        
        
        
        
        
        
            
                
                    
                        
                            helperDialect=mysql
                        
                    
                
            
        
    

    
    
    
        
        
        
        
    

    
        
    
    
    

创建配置文件  spring-mvc.xml         



    
    

    
    

    
    
        
        
        
        
    

    
    
    
    

    
    
        
        
        
        
        
        
    



























    
        
            
                
            
        
    
    
        
        
            
                text/html;charset=UTF-8
                text/json;charset=UTF-8
                application/json;charset=UTF-8
            
        
    

    
    
        
        
        
        
        
        
            
                error
            
            
        
    


    
    

也可以不进行以上配置及导入,一下是基于我博客中代码进行知识点扩展 

 SpringMVC之JSON数据返回及异常处理机制

重写创建的项目才需要导入以上引用及配置

场景一(获取类与方法上的注解值)  

创建 TranscationModel 直接C到包里接口

package com.CloudJun.annotation;

public enum  TranscationModel {
    Read, Write, ReadWrite
}

创建 MyAnnotation1 直接C到包里接口

package com.CloudJun.annotation;

import java.lang.annotation.*;

/**
 * @author CloudJun
 * MyAnnotation1注解可以用在类、接口、属性、方法上
 * 注解运行期也保留
 * 不可继承
 */
@Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
//@Inherited //继承使用需要该注解,否则读取不到已继承的注解及属性
@Documented
public @interface MyAnnotation1 {
    String name();
}

创建 MyAnnotation2 直接C到包里接口

package com.CloudJun.annotation;

import java.lang.annotation.*;

/**
 * @author CloudJun
 *  MyAnnotation2注解可以用在方法上
 *  注解运行期也保留
 *  不可继承
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation2 {
    TranscationModel model() default TranscationModel.ReadWrite;
}

创建 MyAnnotation3 直接C到包里接口

package com.CloudJun.annotation;

import java.lang.annotation.*;

/**
 * @author CloudJun
 * MyAnnotation3注解可以用在方法上
 * 注解运行期也保留
 * 可继承
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation3 {
    TranscationModel[] models() default TranscationModel.ReadWrite;
}

创建测试类进行自定义注解测试 Demo1 

package com.CloudJun.annotation.Demo1;

import com.CloudJun.annotation.MyAnnotation1;
import com.CloudJun.annotation.MyAnnotation2;
import com.CloudJun.annotation.MyAnnotation3;
import com.CloudJun.annotation.TranscationModel;

/**
 * @author CloudJun
 * 获取类与方法上的注解值
 */
@MyAnnotation1(name = "Cloud")
public class Demo1 {

    @MyAnnotation1(name = "Jun")
    private Integer age;

    @MyAnnotation2(model = TranscationModel.Read)
    public void list() {
        System.out.println("list");
    }

    @MyAnnotation3(models = {TranscationModel.Read, TranscationModel.Write})
    public void edit() {
        System.out.println("edit");
    }
}

创建测试类进行自定义注解测试 Demo1Test

package com.CloudJun.annotation.Demo1;

import com.CloudJun.annotation.MyAnnotation1;
import com.CloudJun.annotation.MyAnnotation2;
import com.CloudJun.annotation.MyAnnotation3;
import com.CloudJun.annotation.TranscationModel;
import org.junit.Test;

/**
 * @author CloudJun
 */
public class Demo1Test {
    @Test
    public void list() throws Exception {
//        获取类上的注解
        MyAnnotation1 annotation1 = Demo2.class.getAnnotation(MyAnnotation1.class);
        System.out.println(annotation1.name());//Cloud

//        获取方法上的注解
        MyAnnotation2 myAnnotation2 = Demo1.class.getMethod("list").getAnnotation(MyAnnotation2.class);
        System.out.println(myAnnotation2.model());//Read

//        获取属性上的注解
        MyAnnotation1 myAnnotation1 = Demo1.class.getDeclaredField("age").getAnnotation(MyAnnotation1.class);
        System.out.println(myAnnotation1.name());// Jun
    }

    @Test
    public void edit() throws Exception {
        MyAnnotation3 myAnnotation3 = Demo1.class.getMethod("edit").getAnnotation(MyAnnotation3.class);
        for (TranscationModel model : myAnnotation3.models()) {
            System.out.println(model);//Read,Write
        }
    }
}

执行其中的方法( list )进行测试,输出结果如下 : 

学会SpringMVC之自定义注解各种场景应用,提高开发效率及代码质量_第1张图片

执行其中的方法( edit)进行测试,输出结果如下 : 

学会SpringMVC之自定义注解各种场景应用,提高开发效率及代码质量_第2张图片

场景二( 获取类属性上的注解属性值  

场景自定义注解 TestAnnotation

package com.CloudJun.annotation.Demo2;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author CloudJun
 */
//@Retention(RetentionPolicy.SOURCE)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TestAnnotation {
    String value() default "默认value值";

    String what() default "这里是默认的what属性对应的值";
}

创建测试类进行自定义注解的测试 Demo2

package com.CloudJun.annotation.Demo2;

/**
 * @author CloudJun
 * 获取类属性上的注解属性值
 */
public class Demo2 {
    @TestAnnotation(value = "这里是value对应的值--msg1", what = "这里是what对应的值--msg1")
    private static String msg1;

    @TestAnnotation("这就是value对应的值==pa")
    private static String msg2;

    @TestAnnotation(value = "这就是value对应的值==as")
    private static String msg3;

    @TestAnnotation(what = "这就是what对应的值")
    private static String msg4;
}

创建测试类进行自定义注解的测试 Demo2Test

package com.CloudJun.annotation.Demo2;

import org.junit.Test;

/**
 * @author CloudJun
 * 1.value--默认值
 * 2.default--默认值的赋予
 */
public class Demo2Test {
    @Test
    public void test1() throws Exception {
        TestAnnotation msg1 = Demo2.class.getDeclaredField("msg1").getAnnotation(TestAnnotation.class);
        System.out.println(msg1.value());
        System.out.println(msg1.what());
    }

    @Test
    public void test2() throws Exception{
        TestAnnotation msg2 = Demo2.class.getDeclaredField("msg2").getAnnotation(TestAnnotation.class);
        System.out.println(msg2.value());
        System.out.println(msg2.what());
    }

    @Test
    public void test3() throws Exception{
        TestAnnotation msg3 = Demo2.class.getDeclaredField("msg3").getAnnotation(TestAnnotation.class);
        System.out.println(msg3.value());
        System.out.println(msg3.what());
    }

    @Test
    public void test4() throws Exception{
        TestAnnotation msg4 = Demo2.class.getDeclaredField("msg4").getAnnotation(TestAnnotation.class);
        System.out.println(msg4.value());
        System.out.println(msg4.what());
    }
}

执行其中 test1 的方法进行测试,输出结果为 : 

学会SpringMVC之自定义注解各种场景应用,提高开发效率及代码质量_第3张图片

执行其中 test2 的方法进行测试,输出结果为 : 

 学会SpringMVC之自定义注解各种场景应用,提高开发效率及代码质量_第4张图片

执行其中 test3 的方法进行测试,输出结果为 : 

 学会SpringMVC之自定义注解各种场景应用,提高开发效率及代码质量_第5张图片

执行其中 test4 的方法进行测试,输出结果为 : 

学会SpringMVC之自定义注解各种场景应用,提高开发效率及代码质量_第6张图片 

场景三( 获取参数修饰注解对应的属性值

创建自定义注解 IsNotNull 

package com.CloudJun.annotation.Demo3;

import java.lang.annotation.*;

/**
 * @author CloudJun
 * 非空注解:
 * 使用在方法的参数上,false表示此参数可以为空,true不能为空
 */
@Documented
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface IsNotNull {
    boolean value() default false;
}

创建测试类  Demo3

package com.CloudJun.annotation.Demo3;

/**
 * @author CloudJun
 * 获取参数修饰注解对应的属性值
 */
public class Demo3 {

    public void hello1(@IsNotNull(true) String name) {
        System.out.println("hello:" + name);
    }

    public void hello2(@IsNotNull String name) {
        System.out.println("hello:" + name);
    }
}

创建测试类  Demo3Test进行方法测试

package com.CloudJun.annotation.Demo3;

import org.junit.Test;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;


/**
 * @author CloudJun
 */
public class Demo3Test {

    @Test
    public void hello1() throws Exception {
        Demo3 demo3 = new Demo3();
        for (Parameter parameter : demo3.getClass().getMethod("hello1", String.class).getParameters()) {
            IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);
            if(annotation != null){
                //如果值没有设置,将会是默认值为:false
                System.out.println(annotation.value());//true
            }
        }
    }

    @Test
    public void hello2() throws Exception {
        Demo3 demo3 = new Demo3();
        for (Parameter parameter : demo3.getClass().getMethod("hello2", String.class).getParameters()) {
            IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);
            if(annotation != null){
                //如果值有设置,将会是默认值为:true
                System.out.println(annotation.value());//false
            }
        }
    }

    @Test
    public void hello3() throws Exception {
//        模拟浏览器传递到后台的参数 解读@requestParam
        String name = "独孤九剑";
        Demo3 demo3 = new Demo3();
        Method method = demo3.getClass().getMethod("hello1", String.class);
        for (Parameter parameter : method.getParameters()) {
            IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);
            if(annotation != null){
                System.out.println(annotation.value());//true
                if (annotation.value() && !"".equals(name)){
                    method.invoke(demo3,name);
                }
            }
        }
    }
}

执行其中的方法( hello1 )进行测试,输出结果为 : 

学会SpringMVC之自定义注解各种场景应用,提高开发效率及代码质量_第7张图片 

执行其中的方法( hello2 )进行测试,输出结果为 : 

学会SpringMVC之自定义注解各种场景应用,提高开发效率及代码质量_第8张图片 

执行其中的方法( hello3 )进行测试,输出结果为 : 

学会SpringMVC之自定义注解各种场景应用,提高开发效率及代码质量_第9张图片

三、Aop自定义注解的应用

AOP(面向切面编程)是一种编程范式,它通过在程序运行时动态地将额外的逻辑织入到方法或类中,从而实现对方法或类的增强。自定义注解可以与AOP结合使用,用于标记需要进行增强的方法或类。

以下是一个示例,演示了如何使用自定义注解与AOP结合,实现日志记录的功能:

   1 .定义自定义注解@MyLog,用于标记需要记录日志的方法:

package com.CloudJun.annotation.aop;

        import java.lang.annotation.ElementType;
        import java.lang.annotation.Retention;
        import java.lang.annotation.RetentionPolicy;
        import java.lang.annotation.Target;

/**
 * @author CloudJun
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
    String desc();
}

  2 . 定义切面类MyLogAspect,在该类中定义增强逻辑,例如记录日志:

package com.CloudJun.aspect;

import com.CloudJun.annotation.aop.MyLog;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * @author CloudJun
 */
@Component
@Aspect
public class MyLogAspect {
    private static final Logger logger = LoggerFactory.getLogger(MyLogAspect.class);

    /**
     * 只要用到了com.CloudJun.annotation.aop.MyLog这个注解的,就是目标类
     * 是目标类就会执行以下before方法里的代码
     */
    @Pointcut("@annotation(com.CloudJun.annotation.aop.MyLog)")
    private void MyValid() {
    }

    @Before("MyValid()")
    public void before(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        logger.debug("[" + signature.getName() + " : start.....]");
        System.out.println("[" + signature.getName() + " : start.....]");

        MyLog myLog = signature.getMethod().getAnnotation(MyLog.class);
        logger.debug("【目标对象方法被调用时候产生的日志,记录到日志表中】:"+myLog.desc());
        System.out.println("【目标对象方法被调用时候产生的日志,记录到日志表中】:" + myLog.desc());
    }

//    @Around("MyValid()")
//    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
//        long startTime = System.currentTimeMillis();
//        System.out.println(pjp.getTarget());//获取目标方法
//        System.out.println(pjp.getThis());//
//        Object[] args = pjp.getArgs();//获取参数
//        System.out.println(Arrays.toString(args));//输出参数
//        Object ob = pjp.proceed();//获取方法返回值
//        System.out.println(ob);//输出返回值
//        logger.info("耗时 : " + (System.currentTimeMillis() - startTime));
//        return ob;
//    }


}

在上面的切面类中,使用@Aspect注解标记该类为切面类。@Pointcut("@annotation(com.CloudJun.annotation.aop.MyLog)")注解用于定义切点,表示匹配所有标记有@Log注解的方法。@Before注解表示在目标方法执行前执行增强逻辑。

3 . 创建一个控制器 LogController 

package com.CloudJun.web;

import com.CloudJun.annotation.aop.MyLog;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;

/**
 * @author CloudJun
 */
@Controller
public class LogController {

    @RequestMapping("/myLog")
    @MyLog(desc = "这是结合spring aop知识,讲解自定义注解应用的一个案例")
    public void testLogAspect(HttpServletRequest request){
        request.getRemoteAddr();//这里是获取请求IP,可以输出或者保存在某个地方及属性
        request.getRemotePort();//这里是获取请求端口,可以输出或者保存在某个地方及属性
        System.out.println("这里随便来点啥");
    }
}

自定义注解与AOP结合使用,可以实现各种不同的功能,如权限控制、性能监控、事务管理等。根据具体的业务需求,可以定义不同的注解,并在切面类中实现相应的增强逻辑。

测试

开启服务器,在浏览器中进行访问地址,进行测试( 以下访问地址是根据自己配置而修改的 )

访问该地址进行测试 :  localhost:8081/ssm/
myLog ( 结果如下 )

学会SpringMVC之自定义注解各种场景应用,提高开发效率及代码质量_第10张图片

将切面类中( MyLogAspect ) 的 before 方法进行注释,将其中的 doAround 方法注释打开

 同样访问该地址进行测试 :  localhost:8081/ssm/myLog ( 结果如下 )

 学会SpringMVC之自定义注解各种场景应用,提高开发效率及代码质量_第11张图片

小总结 

通过自定义注解与AOP结合使用,可以实现各种不同的功能,根据具体的业务需求进行定制化开发。这种方式可以将横切逻辑与业务逻辑分离,提高代码的可维护性和可扩展性,同时也减少了代码的重复编写。

带给我们的收获

学习SpringMVC中的自定义注解和AOP自定义注解的应用可以带来以下几个方面的收获:

1. 提高代码重用性:通过自定义注解,我们可以将一些常用的功能逻辑抽象为注解,然后在需要的地方进行标记和使用。这样可以减少代码的重复编写,提高代码的可维护性和可读性。

2. 简化开发流程:通过自定义注解,我们可以简化一些繁琐的配置和操作。比如,在SpringMVC中,我们可以使用自定义注解来标记控制器的映射路径,从而省去手动配置URL映射的步骤,简化了开发流程。

3. 实现横切关注点:AOP(面向切面编程)可以通过自定义注解来实现横切关注点的功能,例如日志记录、事务管理、权限控制等。通过在代码中标记自定义注解,可以将这些关注点与业务逻辑分离,提高代码的可维护性和可扩展性。

4. 代码解耦和模块化:通过自定义注解和AOP,我们可以将一些功能逻辑和横切关注点从业务代码中解耦出来,实现模块化的开发。这样可以降低代码的耦合度,提高代码的可测试性和可维护性。

总的来说,学习SpringMVC中的自定义注解和AOP自定义注解的应用,可以提高代码的重用性、简化开发流程,实现横切关注点,解耦业务代码,从而带来更加高效、可维护和可扩展的代码开发和管理。

学会SpringMVC之自定义注解各种场景应用,提高开发效率及代码质量_第12张图片

你可能感兴趣的:(java,开发语言,mybatis,sql,intellij,idea,tomcat,maven)