基于注解的切面编程

1.基本概念java

    面向切面编程也叫Aop。面向对象的特色是继承、封装、多态。封装要求咱们将不一样的功能分散到不一样的类中去实现,每一个类有本身的职责,这样的好处是下降了代码的复杂度,使得类能够重用;可是在分散代码的同时,也会增长代码的复杂性,好比一些通用的功能,日志,权限等。在以前进行app后端开发的时候,为了跟踪问题,须要对每一个api的请求日志都记录下来,能够在每一个方法的入口处都加上log.info.....,可是这样不够灵活,若是之后对记录的日志的方式变化,那么改动可想而知,也许你会说封装起来,每一个类中进行调用,可是这样就耦合太严重了。这时候就可使用Aop,在运行时动态的插入代码;这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。web

    通常而言,咱们将切入到指定类指定方法的代码片断称为切面,将切入到哪些类,或者哪些方法的称为切入点。使用Aop,将不一样类中重复的地方抽取出来,造成切面,在须要的地方插入到对象或方法上,从而动态改变原有的行为。spring

2.一个简单权限校验的例子编程

基于注解的切面,须要定义注解,定义切面后端

1>定义注解api

package com.example.springbootDemo.service.aspect;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE,ElementType.METHOD})//注解类型,级别
@Retention(RetentionPolicy.RUNTIME)//运行时注解
public @interface PermissionCheck {
    String value() default "";
}

2>根据注解定义一个切面springboot

package com.example.springbootDemo.service.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class PermissionAspect {
    /**
     * 选取切入点为自定义注解
     */
    @Pointcut("@annotation(com.example.springbootDemo.service.aspect.PermissionCheck)")
    public void permissionCheck(){}

    /**
     * 在切入点业务逻辑执行前进行操做
     * @param joinPoint
     */
    @Before(value = "permissionCheck();")
    public void before(JoinPoint joinPoint) throws Throwable {
        Signature signature = joinPoint.getSignature(); //获取链接点的方法签名对象
        if (!(signature instanceof MethodSignature)){
            throw new PermissionCheckException("user permission check fail,stop this request!");
        }
        MethodSignature methodSignature = (MethodSignature) signature;
        Object target = joinPoint.getTarget();
        Method method = target.getClass().getDeclaredMethod(methodSignature.getName(),methodSignature.getParameterTypes());//获取到当前执行的方法
        PermissionCheck annotation = method.getAnnotation(PermissionCheck.class);//获取方法的注解
        System.out.println(annotation);
        System.out.println(annotation.value());
        System.out.println("我是在执行业务逻辑以前");
    }

    /**
     * 在业务逻辑执行后进行的操做
     * @param joinPoint
     */
    @After(value = "permissionCheck();")
    public void after(JoinPoint joinPoint) throws NoSuchMethodException {
        System.out.println("我是在执行业务逻辑后");
    }

    @Around(value = "permissionCheck();")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("around方法执行前1");
        Object proceed = joinPoint.proceed();
        System.out.println("around方法执行前2");
        System.out.println("proceed:"+proceed.toString());
        return proceed;
    }
}

3>权限验证不知足的时候须要定义异常,定义一个PermissionCheckException来标识权限不知足的异常信息app

package com.example.springbootDemo.service.aspect;

public class PermissionCheckException extends RuntimeException {
    public PermissionCheckException(String message) {
        super(message);
    }
}

4>定义Advice处理该异常this

package com.example.springbootDemo.service.aspect;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

@ControllerAdvice
public class PermissionAdvice {
    @ExceptionHandler(value = PermissionCheckException.class)
    @ResponseStatus(value = HttpStatus.OK)
    @ResponseBody
    public String dealWithPermissionCheckException(PermissionCheckException exception){
        System.out.println(exception.getMessage());
        return exception.getMessage();
    }
}

注:PermissionCheck 注解必须声明为@Retention(RetentionPolicy.RUNTIME),不然,默认的是@Retention(RetentionPolicy.CLASS) 注解会在class字节码文件中存在,但运行时没法得到;.net

3.@Before @Around @After 等 advice 的执行顺序

正常状况的执行顺序

异常状况

注:Around中

Object proceed = joinPoint.proceed();

表示

Proceed with the next advice or target method invocation

表示处理返回的结果对象,必须返回;

相关文章
相关标签/搜索