2019独角兽企业重金招聘Python工程师标准>>>
1、AOP介绍
AOP 即 Aspect Oriented Program 面向切面编程 ,首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能。
所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务
所谓的周边功能,比如性能统计,日志,事务管理等等
周边功能在Spring的面向切面编程AOP思想里,即被定义为切面
在面向切面编程AOP的思想里面,核心业务功能和切面功能分别独立进行开发
然后把切面功能和核心业务功能 "编织" 在一起,这就叫AOP。
一个方法的执行,会有方法执行前、方法执行后、方法出现异常后、方法返回结果 这几个阶段,AOP的思想就是在这些阶段里动态的切入一段逻辑代码。这种思想可以把业务逻辑里的一些通用的代码抽取出来,打印日志、事务的提交和回滚、监测方法的执行时间等这些通用代码就可以与业务逻辑代码解耦。
2、spring使用aop
引入依赖
<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.0.6.RELEASE</version> </dependency>
定义一个业务逻辑类(BussinessSevice),在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常)
public class BussinessSevice {public int doBussiness(int a,int b){System.out.println("做业务处理");int result = a + b;return result;} }
定义一个日志切面类(LogAspects)
@Aspect注解标明该类是一个切面类
@Pointcut 定义了给spring容器中的那些实例bean的那些方法给切入打印日志代码。
切面类里需要定义一些通知方法,标识了doBussiness方法的哪个阶段去切入打印日志代码。
前置通知(@Before):logStart:在目标方法(doBussiness)运行之前运行
后置通知(@After):logEnd:在目标方法(doBussiness)运行结束之后运行(无论方法正常结束还是异常结束)
返回通知(@AfterReturning):logReturn:在目标方法(doBussiness)正常返回之后运行
异常通知(@AfterThrowing):logException:在目标方法(doBussiness)出现异常以后运行
环绕通知(@Around):手动推进目标方法运行(joinPoint.procced()), 执行之前相当于前置通知, 执行之后相当于返回通知
/*** 日志切面类*/
@Aspect
public class LogAspects {//表示匹配spring容器中包名为com.suzhe.spring.basic.aop.service的所有bean实例的所有的公有方法@Pointcut("execution(public * com.suzhe.spring.basic.aop.service.*.*(..))")public void pointCut(){}/*** 方法前* @param joinPoint*/@Before("pointCut()")public void logStart(JoinPoint joinPoint){System.out.println("logStart 参数列表是:{"+Arrays.asList(joinPoint.getArgs())+"}");}/*** 方法后* @param joinPoint*/@After("pointCut()")public void logEnd(JoinPoint joinPoint){System.out.println("logEnd......");}/*** 方法返回结果后* @param joinPoint*/@AfterReturning(value="pointCut()",returning="result")public void logReturn(JoinPoint joinPoint,Object result){System.out.println("logReturn:{"+result+"}");}/*** 方法出现异常后* @param exception*/@AfterThrowing(value="pointCut()",throwing="exception")public void logException(Exception exception){System.out.println("logException:{"+exception+"}");}/*** 手工调用目标方法的执行* @param proceedingJoinPoint* @return* @throws Throwable*/@Around("pointCut()")public Object Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{System.out.println("@Arount:before...");Object obj = proceedingJoinPoint.proceed();//相当于调用了业务方法System.out.println("@Arount:after..."+obj);return obj;}}
将业务逻辑组件和切面类都加入到容器中,需要开启基于注解的AOP模式,给配置类加上@EnableAspectJAutoProxy注解。
注意: 在spring以后会有很多@EnableXXXX, 表示开启某项功能, 取代XML配置
@EnableAspectJAutoProxy @Configuration public class AopConfig {//业务逻辑类加入容器中@Beanpublic BussinessSevice bussinessSevice(){return new BussinessSevice();}//切面类加入到容器中@Beanpublic LogAspects logAspects(){return new LogAspects();} }
测试代码
@Test public void test01(){AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(AopConfig.class);BussinessSevice b = app.getBean(BussinessSevice.class);int result = b.doBussiness(1,2);System.out.println(result);app.close(); }
运行后
从上面的执行结果可以看出aop各个通知方法的执行顺序
异常情况测试
定义一个业务类,该类执行方法时会抛出异常
public class BussinessExceptionSevice {public int doBussiness(int a,int b){System.out.println("doBussiness ...");int result = a + b;int i = 1/0;return result;} }
将该类注册到spring容器中
@Bean public BussinessExceptionSevice bussinessExceptionSevice(){return new BussinessExceptionSevice(); }
执行测试
@Test public void test02(){AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(AopConfig.class);BussinessExceptionSevice b = app.getBean(BussinessExceptionSevice.class);int result = b.doBussiness(1,2);System.out.println(result);app.close(); }
从测试结果可以看出,异常情况下aop通知方法的执行顺序如下