美文网首页
SpringBoot之切面实践

SpringBoot之切面实践

作者: 程序员小白成长记 | 来源:发表于2020-06-23 10:44 被阅读0次

    术语GET

    Pointcut: a predicate that matches join points. Advice is associated with a pointcut expression and runs at any join point matched by the pointcut

    Advice: action taken by an aspect at a particular join point.

    SpringAop vs AspectJ

    参考

    spring aop官方文档
    使用spring Aop实现后台权限验证
    springAop实现简单的权限角色验证
    说说 Spring AOP 中 @Aspect 的高级用法

    二、案例

    image.png

    2.1 注解实现切面


    1. 注解Verify

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface Verify {
    }
    
    

    2. 切面VerifyAspect(切入点+通知)
    【注意】@Aspect、@Component注解

    @Aspect
    @Component
    public class VerifyAspect {
    
        /**
         * 切入点,已经被增强的连接点
         */
        @Pointcut("@annotation(com.example.demo.aop.annotation.Verify)")
        public void pointcut(){
            System.out.println("pointcut()");
        }
    
        /**
         * 前置通知
         */
        @Before("pointcut()")
        public void beforePointCut(){
            System.out.println("beforePoint()");
        }
    }
    

    3. 测试Controller

    @RestController
    public class TestController {
    
        @Verify
        @RequestMapping(value="/aspect/test", method = RequestMethod.GET)
        public void test(){
            System.out.println("test()");
        }
    }
    

    4. pom.xml

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    
    image.png
    5. 结果验证
    GET /aspect/test
    返回结果:
    beforePoint()
    test()
    

    2.1 注解实现切面(获取拦截方法参数,注解信息)


    image.png
    1. 自定义注解 VerifyAnnotation
    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 VerifyAnnotation {
        // default 后只能是常量
        int roleType() default 0;
    }
    

    2.编写切面 VerifyAnnotationAspect

    import com.example.demo.aop.annotation.VerifyAnnotation;
    import org.apache.commons.lang3.ArrayUtils;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.Signature;
    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.springframework.stereotype.Component;
    
    import java.lang.reflect.Method;
    import java.lang.reflect.Parameter;
    
    @Aspect
    @Component
    public class VerifyAnnotationAspect {
    
        /**
         * 切入点,已经被增强的连接点
         */
        @Pointcut("@annotation(com.example.demo.aop.annotation.VerifyAnnotation)")
        public void pointcut(){
            System.out.println("pointcut()");
        }
    
        /**
         * 前置通知
         */
        @Before("pointcut()")
        public void beforePointCut(JoinPoint joinPoint) throws NoSuchMethodException {
            System.out.println("beforePoint()");
            // 拦截的对象
            // eg: TestController@5809
            Object target = joinPoint.getTarget();
            // 拦截的方法名称
            String methodName = joinPoint.getSignature().getName();
            // 拦截的方法参数,不包含字段名,方法参数*值*数组(下标与传参下标对应)
            // eg: args[0] = 1
            Object[] args = joinPoint.getArgs();
            // 拦截方法参数类型(下标与传参下标对应)
            Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterTypes();
            // 通过方法名称,传参类型获得方法,防止重载
            Method method = target.getClass().getMethod(methodName, parameterTypes);
            // parameter[0].name(id)
            // parameter[0].getType()(int)
            Parameter[] parameter = method.getParameters();
            // 方法签名(方法的调用类型、方法名称、参数名称、参数类型、返回类型)
            Signature signature = joinPoint.getSignature();
            MethodSignature methodSignature = (MethodSignature) signature;
            // 参数名称数组
            // eg: parameterNames[0] = "id"
            String[] parameterNames = methodSignature.getParameterNames();
            int idIndex = ArrayUtils.indexOf(parameterNames, "id");
            int id = (int)args[idIndex];
            // 获取方法上中的注解
            VerifyAnnotation verifyAnnotation = method.getAnnotation(VerifyAnnotation.class);
            int roltType = verifyAnnotation.roleType();
            return;
        }
    }
    

    3. TestController

    import com.example.demo.aop.annotation.VerifyAnnotation;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class TestController {
    
        @VerifyAnnotation(roleType = 0)
        @RequestMapping(value="/aspect/test/{id}", method = RequestMethod.GET)
        public void test(@PathVariable int id){
            System.out.println("test()");
            System.out.println("id:" + id);
        }
    }
    

    4.访问
    GET /aspect/test/1
    可以通过打断点查看是否获取相应信息

    相关文章

      网友评论

          本文标题:SpringBoot之切面实践

          本文链接:https://www.haomeiwen.com/subject/biiffktx.html