本文共 5206 字,大约阅读时间需要 17 分钟。
Spring Boot AOP入门指南
1. AOP概述
面向方面编程(AOP)是一种补充面向对象编程(OOP)的编程范式。与OOP中以类为基本单位的模块化思想不同,AOP以切面(Aspect)作为模块化的基本单位。AOP允许我们在不修改源代码的情况下,通过动态代理的方式扩展程序功能。
2. 准备工作
2.1 安装AOP依赖
在项目的build.gradle文件中,添加以下依赖:
compile "org.springframework.boot:spring-boot-starter-aop:${springBootVersion}" 2.2 配置应用程序
在application.yml中添加以下配置:
spring: aop: proxy-target-class: true
3. 切入点定义
3.1 定义切点
切点是AOP的核心概念,用于定义需要进行增强的方法或方法调用。切点的定义基于以下规则:
- 方法的签名(返回类型、方法名、参数类型)
- 方法的访问权限(public、protected、private)
- 方法的修饰词(public、protected、private、static、final等)
示例:
@Pointcut("execution(public String test(..))")public void cutOffPoint() {} 3.2 示例说明
在以下代码中,@Pointcut注解定义了一个切点,表示所有返回类型为String、方法名为test且接受任意参数的方法。例如:
@GetMapping("hello")public String test() { logger.info("欢迎关注Java知音"); return "i love java";} 如果你想在所有返回类型为Area的方法中定义切点,可以使用以下方式:
@Pointcut("execution(public com.example.entity.Area (..))") 4. 通知机制
AOP的核心功能在于通过切点定义的方法,执行特定的通知逻辑。常见的通知类型包括:
4.1 前置通知(@Before)
前置通知在切点开始执行时调用。示例:
@Before("cutOffPoint()")public void beforeTest() { logger.info("我在test方法之前执行");} 4.2 后置通知(@After)
后置通知在切点执行完成后调用。示例:
@After("cutOffPoint()")public void doAfter() { logger.info("我是在test之后执行的");} 4.3 环绕通知(@Around)
环绕通知不仅包括前置和后置通知,还包含目标方法的执行。proceed()方法用于调用目标方法。示例:
@Around("cutOffPoint()")public Object doAround(ProceedingJoinPoint pjp) { ThreadLocal startTime = new ThreadLocal (); startTime.set(System.currentTimeMillis()); logger.info("我是环绕通知执行"); Object obj; try { obj = pjp.proceed(); logger.info("执行返回值 : " + obj); logger.info(pjp.getSignature().getName() + "方法执行耗时: " + (System.currentTimeMillis() - startTime.get())); } catch (Throwable throwable) { obj = throwable.toString(); } return obj;} 4.4 返回结果后的通知(@AfterReturning)
@AfterReturning用于在切点执行并返回结果后调用。示例:
@AfterReturning(returning = "result", pointcut = "cutOffPoint()")public void doAfterReturning(Object result) throws Throwable { logger.info("大家好,我是@AfterReturning,他们都秀完了,该我上场了");} 4.5 错误处理后的通知(@AfterThrowing)
@AfterThrowing用于在切点抛出异常后调用。示例:
@AfterThrowing(throwing = "e", pointcut = "cutOffPoint()")public void doAfterThrowing(Throwable e) { logger.info("大家好,我是@AfterThrowing,他们犯的错误,我来背锅"); logger.info("错误信息" + e.getMessage());} 5. AOP的实际应用场景
5.1 全局异常处理
通过定义切点拦截ResultBean或PageResultBean的方法调用,实现全局异常处理。示例:
@Pointcut(value = "execution(public com.example.beans.PageResultBean *(..))")public void handlerPageResultBeanMethod() {}@Pointcut(value = "execution(public com.example.beans.ResultBean *(..))")public void handlerResultBeanMethod() {}@Around("handlerPageResultBeanMethod()")public Object handlerPageResultBeanMethod(ProceedingJoinPoint pjp) { ThreadLocal start = new ThreadLocal (); start.set(System.currentTimeMillis()); try { PageResultBean resultBean = new PageResultBean(); resultBean.setMsg("处理成功"); resultBean.setCode(ResultBean.SUCCESS); PageResultBeanThreadLocal.set(resultBean); logger.info(pjp.getSignature() + "方法执行耗时: " + (System.currentTimeMillis() - start.get())); } catch (Throwable e) { logger.error(pjp.getSignature() + "错误处理", e); ResultBean resultBean = new ResultBean(); resultBean.setMsg("处理失败"); resultBean.setCode(ResultBean.FAIL); PageResultBeanThreadLocal.set(resultBean); } return PageResultBeanThreadLocal.get();} 5.2 事物管理
默认情况下,Spring Boot的AOP不支持事物管理。如果需要实现事物管理,需要在切点中调用@Transactional注解。例如:
@Transactionalpublic int insertSelective(Area record) { record.setAddress("test"); record.setPostalcode(88888); record.setType(3); int i = areaMapper.insertSelective(record); return i;} 如果需要实现回滚,可以在catch中抛出异常。
6. 日志处理配置
6.1 禁用Spring Boot自带日志
在build.gradle中添加:
configurations { providedRuntime all*.exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'}ext { springBootVersion = '2.0.1.RELEASE'}dependencies { compile "org.springframework.boot:spring-boot-starter-log4j2:${springBootVersion}"} 6.2 配置log4j2日志
在application.yml中添加:
logging: level: com: example: dao: debug config: classpath:log4j2-spring.xml
6.3 log4j2配置文件
6.4 使用日志
在需要打印日志的类中添加:
private static final Logger logger = LoggerFactory.getLogger(YourClass.class);public static void main(String[] args) { logger.error("error级别日志"); logger.warn("warning级别日志"); logger.info("info级别日志");} 通过合理使用日志,开发人员可以在开发环境中打印详细信息,而在线环境中可以将日志级别设置为warning或error,以减少不必要的日志输出。
7. 常见问题解答
7.1 事物回滚问题
如果在业务方法中使用@Transactional注解,并且在catch中不抛出异常,事物管理器将不会回滚事务。要实现回滚,可以在catch中抛出一个异常。
7.2 全局异常处理
通过AOP切入拦截ResultBean或PageResultBean的方法调用,可以实现全局异常处理,避免在业务层逐一处理错误。
8. 总结
AOP是一种强大的编程范式,能够在不修改源代码的情况下扩展程序功能。通过合理使用切点和通知机制,可以实现全局异常处理、日志记录、性能监控等功能。在实际应用中,建议结合事物管理和日志处理,提升程序的健壮性和可维护性。
发表评论
最新留言
关于作者