概念
AOP为(Aspect Oriented Programming)面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.
AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
Spring 的AOP中主要是将日志记录,安全控制,异常处理,性能统计,事务处理等功能从业务逻辑代码中分离出来运行于非逻辑的方法中,做到与业务逻辑互不影响。
常用注解
标注于类上
@Aspect:把当前类标识为一个切面供容器读取
标注于方法上
@Around:环绕增强,相当于MethodInterceptor
@AfterReturning:后置增强,相当于AfterReturningAdvice,方法正常退出时执行
@Before:标识一个前置增强方法,相当于BeforeAdvice的功能,相似功能的还有
@AfterThrowing:异常抛出增强,相当于ThrowsAdvice
@After: final增强,不管是抛出异常或者正常退出都会执行
@Pointcut:Pointcut表达式命名。只需要方法签名,而不需要在方法体内编写实际代码。
@Order 优先级,数字越小优先级越高
实战例子
现在有三个拦截器,第一是完成对系统内所有异常的捕获
第二个是完成身份的校验,第三个请求幂等
@Order(1)
@Around("execution(* com.baidu.service.impl.*.*(..)) && @annotation(Auth)")
public Object proceedLog(ProceedingJoinPoint pjp, Auth auth) {
//拿到请求参数
Object[] args = pjp.getArgs();
Object result = null;
try {
//执行目标方法
result = pjp.proceed(args);
return result;
} catch (Exception e) {
//对所有异常进行日志记录
}
}
@Order(2)
@Before("execution(* com.baidu.service.impl.*.*(..)) && @annotation(Auth)")
public void authCheck(JoinPoint pjp, Auth auth) {
//首先拿到请求的参数值
String paramName = auth.userId.split("\\.")[1];
String methodName = "get" + paramName.replaceFirst(paramName.substring(0, 1), paramName.substring(0, 1).toUpperCase());
Method method = pjp.getArgs().getClass().getDeclaredMethod(methodName, null);
string userId = String.valueOf(method.invoke(obj));
string userType = auth.userType().getCode();
//对用户身份和权限的校验
}
@Order(3)
@Around("execution(public * com.baidu..*.*(..)) && @annotation(idempotent)")
public Object idempotent(ProceedingJoinPoint pjp, Idempotent idempotent){
//对更新类的操作,确保请求幂等,下次更新,敬请关注
}
//自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Auth{
UserTypeEnum userType();
//身份相关的一些属性
string userId() default "";
}
//自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Idempotent{
//幂等key
string idempotentkey() default "";
//过期天数
int expireDate() default 0;
}
如上,在Pointcut表达式里,只要是对用路径下的类并且有Auth的注解,那么每次请求都会经过proceedLog方法的环绕,校验用户的身份权限,然后调用目标方法,如果有异常便会被proceedLog方法记录到日志
@Override
@Auth(userType = UserTypeEnum.ADMIN, userId = "#request.userId")
public Result update(Request request) {
}