基于Spring AOP使用自定义注解实现拦截控制

114 阅读2分钟

pom.xml

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>learn</artifactId>
        <groupId>com.evan</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>spring-aop-basic-learn</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--spring aop支持-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>${aspectjweaver.version}</version>
        </dependency>

    </dependencies>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <spring.version>5.3.9</spring.version>
        <aspectjweaver.version>1.9.6</aspectjweaver.version>
    </properties>
</project>

业务

package com.evan.service;

import com.evan.entity.User;

import java.util.List;

public interface UserService {
    List<User> findUserList();

    void addUser();
}
package com.evan.service.impl;

import com.evan.annotation.MyAnnotation;
import com.evan.entity.User;
import com.evan.service.UserService;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;

@Service
public class UserServiceImpl implements UserService {
    @MyAnnotation("evan")
    @Override
    public List<User> findUserList() {
        System.out.println("执行方法:findUserList");
        return Collections.singletonList(new User("evan", 18));
    }

    /**
     * add user
     */
    @Override
    public void addUser() {
        System.out.println("execute method: addUser");
        // do something
    }
}

自定义注解

package com.evan.annotation;

import java.lang.annotation.*;

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

切面

package com.evan.aspect;

import com.evan.annotation.MyAnnotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Method;

@Aspect
public class MyAnnotationAspect {

    @Pointcut("@annotation(com.evan.annotation.MyAnnotation)")
    private void pointCut() {
    }


    @Around("pointCut()")
    public Object doAround(ProceedingJoinPoint jointPoint) throws NoSuchMethodException {
        System.out.println("环绕通知: 进入方法");


        // 获取当前访问的class类及类名
        Class<?> clazz = jointPoint.getTarget().getClass();
        String clazzName = jointPoint.getTarget().getClass().getName();

        // 获取访问的方法名
        String methodName = jointPoint.getSignature().getName();
        // 获取方法所有参数及其类型
        Object[] args = jointPoint.getArgs();

        System.out.println("获取当前访问的class类及类名" + clazzName);
        System.out.println("获取访问的方法名" + methodName);
        System.out.println("获取方法所有参数及其类型" + args);

        Class[] argClz = ((MethodSignature) jointPoint.getSignature()).getParameterTypes();
        // 获取访问的方法对象
        Method method = clazz.getDeclaredMethod(methodName, argClz);


        System.out.println("获取访问的方法对象" + method);


        // 判断当前访问的方法是否存在指定注解
        if (method.isAnnotationPresent(MyAnnotation.class)) {
            MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
            // 获取注解标识值与注解描述
            String value = annotation.value();
            System.out.println(value);

            // 执行目标方法
            Object o = null;
            try {
                o = jointPoint.proceed();
                System.out.println("打印方法是执行返回结果:" + o.toString());
                return o;
            } catch (Throwable e) {
                //throw new RuntimeException(e);
                System.out.println(e.getMessage());
            } finally {
                System.out.println("环绕通知: 退出方法");
            }
        }
        return null;
    }
}

配置类

package com.evan.config;

import com.evan.aspect.MyAnnotationAspect;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configurable
@EnableAspectJAutoProxy
@ComponentScan("com.evan")
public class AnnotationConfig {

    @Bean
    public MyAnnotationAspect myAnnotationAspect() {
        return new MyAnnotationAspect();
    }
}

测试类

package com.evan;

import com.evan.config.AnnotationConfig;
import com.evan.config.MyConfig;
import com.evan.entity.User;
import com.evan.service.ArithmeticCalculator;
import com.evan.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.List;

public class AnnotationTest {

    @Test
    public void test01() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AnnotationConfig.class);
        UserService userService = context.getBean(UserService.class);
        List<User> userList = userService.findUserList();
        System.out.println(userList);
    }
}

测试结果

环绕通知: 进入方法
获取当前访问的class类及类名com.evan.service.impl.UserServiceImpl
获取访问的方法名findUserList
获取方法所有参数及其类型[Ljava.lang.Object;@16c069df
获取访问的方法对象public java.util.List com.evan.service.impl.UserServiceImpl.findUserList()
evan
执行方法:findUserList
打印方法是执行返回结果:[User(name=evan, age=18)]
环绕通知: 退出方法
[User(name=evan, age=18)]