转载于:https://www.cnblogs.com/LemonFive/p/10983875.html
本文基于SpringBoot编写了一个简单的Spring AOPDemo。
maven依赖添加如下 <!--引入SpringBoot的Web模块--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--引入AOP依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
注意:在完成了引入AOP依赖包后,不需要去做其他配置。AOP的默认配置属性中,spring.aop.auto属性默认是开启的,也就是说只要引入了AOP依赖后,默认已经增加了@EnableAspectJAutoProxy,不需要在程序主类中增加@EnableAspectJAutoProxy来启用。
web请求入口:对应系统纵向的核心业务模块。
package com.example.demo.aop; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @desc: 核心业务模块 * @author: CSH **/ @RestController @RequestMapping("/aopController") public class AopController { @RequestMapping(value = "/Curry") public void Curry(){ System.out.println("库里上场打球了!!"); } @RequestMapping(value = "/Harden") public void Harden(){ System.out.println("哈登上场打球了!!"); } @RequestMapping(value = "/Antetokounmpo") public void Antetokounmpo(){ System.out.println("字母哥上场打球了!!"); } @RequestMapping(value = "/Jokic") public void Jokic(){ System.out.println("约基奇上场打球了!!"); } @RequestMapping(value = "/Durant/{point}") public void Durant(@PathVariable("point") int point){ System.out.println("杜兰特上场打球了!!"); } }
定义切面类:在类上添加@Aspect 和@Component 注解即可将一个类定义为切面类。
@Aspect 注解 使之成为切面类
@Component 注解 把切面类加入到IOC容器中
package com.example.demo.aop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; /** * @desc: 经纪人切面 * @author: CSH **/ @Aspect @Component public class BrokerAspect { /** * 定义切入点,切入点为com.example.demo.aop.AopController中的所有函数 *通过@Pointcut注解声明频繁使用的切点表达式 */ @Pointcut("execution(public * com.example.demo.aop.AopController.*(..)))") public void BrokerAspect(){ } /** * @description 在连接点执行之前执行的通知 */ @Before("BrokerAspect()") public void doBeforeGame(){ System.out.println("经纪人正在处理球星赛前事务!"); } /** * @description 在连接点执行之后执行的通知(返回通知和异常通知的异常) */ @After("BrokerAspect()") public void doAfterGame(){ System.out.println("经纪人为球星表现疯狂鼓掌!"); } /** * @description 在连接点执行之后执行的通知(返回通知) */ @AfterReturning("BrokerAspect()") public void doAfterReturningGame(){ System.out.println("返回通知:经纪人为球星表现疯狂鼓掌!"); } /** * @description 在连接点执行之后执行的通知(异常通知) */ @AfterThrowing("BrokerAspect()") public void doAfterThrowingGame(){ System.out.println("异常通知:球迷要求退票!"); } }
/** * @description 使用环绕通知 */ @Around("BrokerAspect()") public void doAroundGame(ProceedingJoinPoint pjp) throws Throwable { try{ System.out.println("经纪人正在处理球星赛前事务!"); pjp.proceed(); System.out.println("返回通知:经纪人为球星表现疯狂鼓掌!"); } catch(Throwable e){ System.out.println("异常通知:球迷要求退票!"); } }
环绕通知接受ProceedingJoinPoint作为参数,它来调用被通知的方法。通知方法中可以做任何的事情,当要将控制权交给被通知的方法时,需要调用ProceedingJoinPoint的proceed()方法。当你不调用proceed()方法时,将会阻塞被通知方法的访问。
当通知方法需要传入参数我们又该怎样处理呢?
和之前创建的切面一样,这里的不同点在于切点还声明了要提供给通知方法的参数。
切点表达式args(point)表明传递给GameDataAspect()方法中的int类型参数也会传递到通知中去,参数名point和缺点方法签名中的参数相匹配
package com.example.demo.aop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * @desc:技术统计 * @author: CSH **/ @Aspect @Component public class GameDataAspect { /** * 定义切入点,切入点为com.example.demo.aop.AopController中的所有函数 *通过@Pointcut注解声明频繁使用的切点表达式 */ @Pointcut("execution(public * com.example.demo.aop.AopController.Durant(int)) && args(point))") public void GameDataAspect(int point){ } /** * @description 使用环绕通知 */ @Around("GameDataAspect(point)") public void doAroundGameData(ProceedingJoinPoint pjp,int point) throws Throwable { try{ System.out.println("球星上场前热身!"); pjp.proceed(); System.out.println("球星本场得到" + point + "分" ); } catch(Throwable e){ System.out.println("异常通知:球迷要求退票!"); } } }
本文代码Github链接https://github.com/LemonFive/SpringBootAopDemo