Spring Boot 实现自定义注解 利用aop完成指定方法的处理

实现自定义注解 利用aop完成指定方法的处理

构建一个web项目,pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.8.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>spring.boot.aop</groupId>
    <artifactId>annotation</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>annotation</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

创建自定义注解

/**
 * @author 81509
 */
@Target({
     ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnnotation {
     
    String value() default "";
} 

@Target表示该注解可以应用的java元素类型

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
     
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

@Target其中参数类型是ElementType[]数组,其中ElementType是枚举类型

public enum ElementType {
     
    /** Class, interface (including annotation type), or enum declaration */
    /** 应用于类、接口(包括注解类型)、枚举 */
    TYPE,

    /** Field declaration (includes enum constants) */
    /** 应用于属性(包括枚举中的常量) */
    FIELD,

    /** Method declaration */
    /** 应用于方法 */
    METHOD,

    /** Formal parameter declaration */
    /**应用于方法的形参*/
    PARAMETER,

    /** Constructor declaration */
    /**应用于构造函数*/
    CONSTRUCTOR,

    /** Local variable declaration */
    /**应用于局部变量*/
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    /**应用于注解类型*/
    ANNOTATION_TYPE,

    /** Package declaration */
    /**应用于包*/
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
     /**1.8版本新增,应用于类型变量*/
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
     /**1.8版本新增,应用于任何使用类型的语句中(例如声明语句、泛型和强制转换语句中的类型)*/
    TYPE_USE
}

@Retention 表明该注解的生命周期

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
     
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

@Retention 表明该注解的生命周期,其中RetentionPolicy 是枚举类型

public enum RetentionPolicy {
     
    /**
     * Annotations are to be discarded by the compiler.
     */
     /**编译时被丢弃,不包含在类文件中*/
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
     /**JVM加载时被丢弃,包含在类文件中,默认值*/
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
     /**由JVM 加载,包含在类文件中,在运行时可以被获取到*/
    RUNTIME
}

@Document 表明该注解标记的元素可以被Javadoc 或类似的工具文档化
@Inherited 表明使用了@Inherited注解的注解,所标记的类的子类也会拥有这个注解

利用aop完成指定注解的处理

Controller:

/**
 * @author 81509
 */
@RestController
public class AopController {
     

    @RequestMapping("/logAop")
    @LogAnnotation("logAopController")
    public Object logAop() {
     
        System.out.println("logAop controller");
        return "logAop controller";
    }
    
}

Aspect

/**
 * @Aspect 作用是把当前类标识为一个切面供容器读取
 * @author 81509
 */
@Component
@Aspect
public class LogAopAspect {
     

    /**
     * 创建切点
     */
    @Pointcut(value = "@annotation(spring.boot.aop.annotation.annotation.LogAnnotation)")
    public void logAop() {
       
  
    }

    /**
     * 环绕增强,相当于MethodInterceptor
     * @param proceedingJoinPoint
     * @param logAnnotation
     * @return
     */
    @Around("@annotation(logAnnotation)")
    public Object around(ProceedingJoinPoint proceedingJoinPoint, LogAnnotation logAnnotation) {
     
        System.out.println("方法环绕start.....");
        //获取注解里参数logAnnotation.value()
        System.out.println("aop around:" + logAnnotation.value());
        try {
     
            return proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
     
            throwable.printStackTrace();
            return null;
        }
    }
    @Around("logAop()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) {
     
        System.out.println("方法环绕start.....");
        //获取注解里的值
        System.out.println("aop around");
        try {
     
            return proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
     
            throwable.printStackTrace();
            return null;
        }
    }

    /**
     * 标识一个前置增强方法,相当于BeforeAdvice的功能
     * @param joinPoint
     * @param logAnnotation
     */
    @Before("@annotation(logAnnotation)")
    public void deBefore(JoinPoint joinPoint, LogAnnotation logAnnotation){
     
        //获取注解参数logAnnotation.value()
        System.out.println("LogAop before:" + logAnnotation.value());
    }
    @Before("logAop()")
    public void deBefore(JoinPoint joinPoint){
     
        System.out.println("LogAop before:");
    }

    /**
     * 后置最终通知,final增强,不管是抛出异常或者正常退出都会执行
     */
    @After("@annotation(logAnnotation)")
    public void after(JoinPoint joinPoint, LogAnnotation logAnnotation){
     
        System.out.println("方法最后执行....."+logAnnotation.value());
    }
    @After("logAop()")
    public void after(JoinPoint joinPoint){
     
        System.out.println("方法最后执行.....");
    }

    /**
     * 后置增强,相当于AfterReturningAdvice,方法退出时执行
     * @param res
     * @throws Throwable
     */
    @AfterReturning(returning = "res", pointcut = "@annotation(logAnnotation)")
    public void doAfterReturning(Object res, LogAnnotation logAnnotation) throws Throwable {
     
        // 处理完请求,返回内容
        System.out.println("方法的返回值 : " + res+"----"+logAnnotation.value());
    }
    @AfterReturning(returning = "res", pointcut = "logAop()")
    public void doAfterReturning(Object res) throws Throwable {
     
        // 处理完请求,返回内容
        System.out.println("方法的返回值 : " + res);
    }

    /**
     * 异常抛出增强,相当于ThrowsAdvice
     * @param joinPoint
     * @param exception
     */
    @AfterThrowing(throwing = "exception", pointcut = "logAop()")
    public void throes(JoinPoint joinPoint, Exception exception){
     
        System.out.println("方法异常时执行.....");
    }


}  

请求 http://localhost:8080/logAop
返回结果

方法环绕start.....
aop around
方法环绕start.....
aop around:logAopController
LogAop before:
LogAop before:logAopController
logAop controller
方法最后执行.....logAopController
方法最后执行.....
方法的返回值 : logAop controller
方法的返回值 : logAop controller----logAopController

每一个通知方法都可以将第一个参数定义为JoinPoint类型(环绕通知需要定义第一个参数为ProceedingJoinPoint类型,它是 JoinPoint 的一个子类)。

JoinPoint接口提供了一系列有用的方法:

getArgs():获取连接点方法运行时的入参列表;

getSignature() :获取连接点的方法签名对象;

getTarget() :获取连接点所在的目标对象;

getThis() :获取代理对象本身;

ProceedingJoinPoint继承JoinPoint子接口,它新增了两个用于执行连接点方法的方法:

Object proceed() throws Throwable:通过反射执行目标对象的连接点处的方法;

Object proceed(Object[] var1) throws Throwable:通过反射执行目标对象连接点处的方法,使用新的参数替换原来的参数。

项目地址:https://github.com/815090488/SpringBootAopAnnotation

你可能感兴趣的:(spring,aop,java)