一、AOP是什么?
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
最简单的AOP为方法接口,下面将以全局异常处理和自定义注解来举例。
二、图示AOP
三、全局切入(全局异常处理)
package io.common.exception;
import io.common.utils.R;
import org.apache.shiro.authz.AuthorizationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @ControllerAdvice 注解,可以用于定义@ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有@RequestMapping中
* 如果全部异常处理返回json,那么可以使用 @RestControllerAdvice 代替 @ControllerAdvice ,这样在方法上就可以不需要添加 @ResponseBody
*/
@RestControllerAdvice
public class RRExceptionHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
/**
* 捕获自定义异常
*/
@ExceptionHandler(RRException.class)
public R handleRRException(RRException e){
R r = new R();
r.put("code", e.getCode());
r.put("msg", e.getMessage());
return r;
}
/**
* 捕获 DuplicateKeyException 异常
*/
@ExceptionHandler(DuplicateKeyException.class)
public R handleDuplicateKeyException(DuplicateKeyException e){
logger.error(e.getMessage(), e);
return R.error("数据库中已存在该记录");
}
/**
* 捕获 AuthorizationException 异常
*/
@ExceptionHandler(AuthorizationException.class)
public R handleAuthorizationException(AuthorizationException e){
logger.error(e.getMessage(), e);
return R.error("没有权限,请联系管理员授权");
}
/**
* 捕获全部异常
*/
@ExceptionHandler(Exception.class)
public R handleException(Exception e){
logger.error(e.getMessage(), e);
return R.error();
}
}
将上面这个类写入代码,就能实现全局异常处理,这样我们就通过AOP实现了将异常处理切入到代码报错之后的操作。
四、局部切入(自定义注解)
1、定义注释名
package com.appgoo.app.test.AOP;
import java.lang.annotation.*;
// 说明了所修饰的对象范围
@Target(ElementType.METHOD)
// 定义注解的生命周期。RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@Retention(RetentionPolicy.RUNTIME)
// Documented注解表明这个注释是由 javadoc记录的,在默认情况下也有类似的记录工具。如果一个类型声明被注释了文档化,它的注释成为公共API的一部分。
@Documented
public @interface AnnotationMonitor {
String value() default "";
}
2、定义注释内容
package com.appgoo.app.test.AOP;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
// 注解将一个java类定义为切面类
@Aspect
@Component
public class AnnotationMonitorAop {
/**
* 定义一个切入点
*/
@Pointcut("@annotation(com.appgoo.app.test.AOP.AnnotationMonitor)")
public void AnnotationMonitorAop() {
}
/**
* 在切入点前后切入内容,并自己控制何时执行切入点自身的内容
*/
@Around("AnnotationMonitorAop()")
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("------------------切入点前切入内容----------------------");
return point.proceed();
}
/**
* 在切入点开始处切入内容
*/
@Before("AnnotationMonitorAop()")
public void Before() {
System.out.println("------------------开始处切入内容----------------------");
}
/**
* 在切入点结尾处切入内容
*/
@After("AnnotationMonitorAop()")
public void After() {
System.out.println("------------------结尾处切入内容----------------------");
}
/**
* 在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)
*/
@AfterReturning("AnnotationMonitorAop()")
public void AfterReturning() {
System.out.println("------------------切入点return内容之后切入内容----------------------");
}
/**
* 用来处理当切入内容部分抛出异常之后的处理逻辑
*/
@AfterThrowing(value = "AnnotationMonitorAop()", throwing="ex")
public void afterThrowing(Throwable ex) {
System.out.println("------------------抛出异常----------------------");
System.out.println(ex.toString());
}
}
3、使用注解
@AnnotationMonitor
String testAop() {
int i = 3, j = 0;
int result = i / j;
System.out.println(result);
return "接口调用成功";
}