描述
AOP(Aspect Oriented Programming)称为面向切面编程, 在不改变原有的逻辑的基础上,增加一些额外的功能。那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
AOP的基本概念
(1)Aspect(切面):通常是一个类,里面可以定义切入点和通知
(2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用
(3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around
(4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式
(5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类
Advice通知类型
1、@Before:在目标方法被调用之前做增强处理,只需要指定切入点表达式即可
2、@AfterReturning:在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后,还可以指定一个返回值形参名returning,代表目标方法的返回值
3、@AfterThrowing:主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后,还可以指定一个throwing的返回值形参名,可以通过该形参名来访问目标方法中所抛出的异常对象
4、@After:在目标方法完成之后做增强,无论目标方法时候成功完成。@After可以指定一个切入点表达式
5、@Around:环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint
,需要调用ProceedingJoinPoint.proceed()
实现方式
1、写死拦截代码在方法里面,实际上不算AOP
2、基于代理的AOP,JDK动态代理,CGLIB代理
3、(主要)@Aspect注解驱动的切面, Spring框架完全支持 AspectJ
4、通过aop:fonfig标签配置,声明的方式
AOP使用场景
权限
ERROR错误处理
Debug调试
LOGGER记录跟踪
代码(@Aspect注解驱动的切面)
下面的代码主要功能是针对接口的拦截,LOGGER记录跟踪 ,Debug调试
@Aspect
@Component
public class CommonLogInterceptor {
@Autowired
ItmpOperatorLogMapper itmpOperatorLogMapper;
private Logger logger = LoggerFactory.getLogger(CommonLogInterceptor.class);
private static final int OVERFLOW = 5000;
/**
* controller日志Aop
*/
@Pointcut("execution(* cn.gzsendi.itmp.itmpmanageserver.controller.*.*(..))")
public void enterController() {
}
/**
* ps:@Around兼具了@before和afterReturn的功能。
*
* @param jt ProceedingJoinPoint
* @return 返回方法的值
* @throws Throwable jt.proceed()异常
*/
@Around("enterController()")
public Object aroundController(ProceedingJoinPoint jt) throws Throwable {
//获取请求
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (servletRequestAttributes == null) {
return null;
}
//执行方法之前
long startTime = System.currentTimeMillis();
HttpServletRequest request = servletRequestAttributes.getRequest();
UserInfo userInfo = CurrentUserInfo.get();
MethodSignature signature = (MethodSignature) jt.getSignature();
logger.info("【Controller】请求的url: {}", request.getRequestURI());
logger.info("【Controller】请求方式: {}", request.getMethod());
logger.info("【Controller】接口参数: {}", DataeStringUtils.omitOverflowString(Arrays.toString(jt.getArgs()), OVERFLOW));
logger.info("【Controller】请求用户信息: {} - {} - {}", userInfo.getRoleId(), userInfo.getRoleName(), userInfo.getUserName());
logger.info("【Controller】请求的方法:{}.{}", signature.getDeclaringTypeName(), signature.getName());
Object object = jt.proceed();
//执行方法之后
long excuteTime = System.currentTimeMillis() - startTime;
logger.info("【Controller】请求的方法:{}.{}() 执行时间 {} ms", signature.getDeclaringTypeName(), signature.getName(), excuteTime);
logger.info("【Controller】返回:{}", object);
return object;
}
/**
* service日志Aop
*/
@Pointcut("execution(* cn.gzsendi.itmp.itmpmanageserver.service.impl.*.*(..))")
public void enterService() {
}
@Before("enterService()")
public void beforeService(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
logger.info("【Service】服务方法: {}.{}()", signature.getDeclaringTypeName(), signature.getName());
logger.info("【Service】服务参数: {}", DataeStringUtils.omitOverflowString(Arrays.toString(joinPoint.getArgs()), OVERFLOW));
}
@Around("enterService()")
public Object aroundService(ProceedingJoinPoint jt) throws Throwable {
MethodSignature signature = (MethodSignature) jt.getSignature();
long startTime = System.currentTimeMillis();
Object object = jt.proceed();
logger.info("【Service】服务方法:{}.{}() 执行时间 {} ms", signature.getDeclaringTypeName(), signature.getName(), System.currentTimeMillis() - startTime);
return object;
}
}
异常的全局拦截
@ControllerAdvice
public class ExceptionHandlerAop {
private Logger logger = LoggerFactory.getLogger(ExceptionHandlerAop.class);
@ExceptionHandler(BaseException.class)
@ResponseBody
public SimpleResponse exception(BaseException e) {
logger.error("未处理的异常 -> ", e);
return SimpleResponse.failure(e.getMsg());
}
@ExceptionHandler(IllegalArgumentException.class)
@ResponseBody
public SimpleResponse exception(IllegalArgumentException e) {
logger.error("参数错误 -> ", e);
return SimpleResponse.failure(String.format("参数错误->[%s]", e.getMessage()));
}
/**
* 针对Controller层JSON转换错误的异常
*
* @param e 异常对象
* @return SimpleResponse
*/
@ExceptionHandler({HttpMessageConversionException.class, HttpMessageNotReadableException.class, HttpMessageNotWritableException.class})
@ResponseBody
public SimpleResponse<String> exceptionHandler(Exception e) {
logger.error("Controller层JSON数据转对象发生异常:", e);
return SimpleResponse.failure("接口传入参数非法:请检查请求JSON是否正确");
}
@ExceptionHandler(Exception.class)
@ResponseBody
public SimpleResponse exception(Exception e) {
logger.error("未处理的异常 -> ", e);
return SimpleResponse.failure(String.format("未处理的异常->[%s]", e.getMessage()));
}
}