一、通过接口实现通知效果
配置applicationContext.xml文件,指定切面,在切面中接入各种通知
<!-- 配置扫描器 不同的包用逗号分隔 --> <context:component-scan base-package="aop"> </context:component-scan> <!-- 前置通知类 --> <bean id="logBefore" class="aop.LogBefore"></bean> <bean id="logAfter" class="aop.LogAfter"></bean> <bean id="logException" class="aop.LogException"></bean> <bean id="logAround" class="aop.LogAround"></bean> <aop:config> <!-- 配置切入点 execution中的内容可以与*(灵活替代各种路径和修饰符以及方法名)和..(指任意参数)任意搭配 多个用execution(..) or execution(..)连接 --> <aop:pointcut expression="execution(public void service.impl.StudentSevImpl.addStudent(entity.Student))" id="myPoint"/> <!-- 将前置通知和切入点连接起来 --> <aop:advisor advice-ref="logBefore" pointcut-ref="myPoint"/> <aop:advisor advice-ref="logAfter" pointcut-ref="myPoint"/> <aop:advisor advice-ref="logException" pointcut-ref="myPoint"/> <aop:advisor advice-ref="logAround" pointcut-ref="myPoint"/> </aop:config>
tip:aop中常用的几个expression表达式 “bean(要切入的bean标签id)”、"execution(public * *.*.*.*(args))"、"within(package+通配符)"。
1.1、前置通知MethodBeforeAdvice接口
public class LogBefore implements MethodBeforeAdvice{ //前置通知方法的实现 @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("前置通知……"); } }
1.2、后置通知AfterReturningAdvice接口
public class LogAfter implements AfterReturningAdvice{ /** * target:指调用插入点方法的对象 * method:切入点的方法 * args:切入点方法的参数 * returnValue:切入点方法的返回值 */ @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("后置通知:"+target+",方法名为:"+method.getName()+",参数为:"+args[0]+",返回值:"+returnValue); } }
1.3、异常通知ThrowsAdvice接口
public class LogException implements ThrowsAdvice{ /** * void afterThrowing([Method, args, target], ThrowableSubclass) * [Method, args, target]:这三个参数要么一起存在,要么都不要 * 虽然是空接口,但必须实现该方法 */ public void afterThrowing(Method method,Object[] args,Object target, Throwable e) { System.out.println("异常通知:"+target+",方法名为:"+method.getName()+",参数为:"+args[0]+",异常类型:"+e.getStackTrace()); } }
1.4、环绕通知MethodInterceptor接口
public class LogAround implements MethodInterceptor{ /** * 本质是通过拦截器实现 */ @Override public Object invoke(MethodInvocation invocation) throws Throwable { Object proceed = null; //方法体1:相当于前置通知 System.out.println("环绕方法的前置通知..."); try { proceed = invocation.proceed(); //放行方法,获取方法执行后的返回值 Object target = invocation.getThis(); Method method = invocation.getMethod(); Object[] args = invocation.getArguments(); //方法体2:相当于后置通知 System.out.println("环绕方法的后置通知...对象:"+target+",方法:"+method.getName()+",参数:"+args[0]+",返回值:"+proceed); }catch(Exception e) { //方法体3:相当于异常通知 System.out.println("环绕方法的异常通知..."); } return proceed; } }
二、通过注解来实现AOP通知
在applicationContext.xml中开启注解:
<!-- 开启注解对aop的支持 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
@Component将改类放入IOC容器中,@Aspect声明为通知类
@Component("logAnnotation") @Aspect public class LogBeforeAnnotation { /** * 运用*和..定义方法的范围 * JoinPoint:获取执行方法各种参数的对象,类似环绕对象的invocation * returningValue:在后置通知注解中,returning来设置返回值 */ @Before("execution(public void service.*.addStudent(..))") public void myBefore() { System.out.println("-------注解的前置通知---------"); } @AfterReturning(pointcut="execution(public void service.*.addStudent(..))",returning="returnValue") public void myAfter(JoinPoint jp,Object returnValue) { Object[] args = jp.getArgs(); Object target = jp.getTarget(); //签名即方法的签名 Signature signature = jp.getSignature(); String methodName = signature.getName(); System.out.println("-------注解的后置通知---------"); System.out.println("执行方法的对象:"+target+",方法名:"+methodName+",参数:"+Arrays.toString(args)+",返回值:"+returnValue); } @AfterThrowing(pointcut="within(service.impl..*)",throwing="e") public void myException(JoinPoint jp,NullPointerException e) { System.out.println("-----注解异常通知:"+e.getStackTrace()); } }
三、通过Schema的方式配置
在applicationContext.xml中开启schema
<bean id="logSchema" class="aop.LogSchema"></bean> <aop:config> <!-- 配置切入点 execution中的内容可以与*(灵活替代各种路径和修饰符以及方法名)和..(指任意参数)任意搭配 多个用execution(..) or execution(..)连接 --> <aop:pointcut expression="execution(public void service.impl.StudentSevImpl.addStudent(entity.Student))" id="myPoint"/> <!-- 通过Schema的方式配置通知 --> <aop:aspect ref="logSchema"> <aop:before method="before" pointcut-ref="myPoint"/> <aop:after-returning method="afterReturning" pointcut-ref="myPoint" returning="returnValue"/> <aop:after-throwing method="whenException" throwing="e" pointcut-ref="myPoint"/> <aop:around method="myAround" pointcut-ref="myPoint"/> </aop:aspect> </aop:config>
用JoinPoint来代替 对象target, 方法method, 参数 args,如果是环绕通知则须用ProceedingJoinPoint来代替
public class LogSchema { public void afterReturning(JoinPoint jp,Object returnValue) throws Throwable { Object target = jp.getTarget(); Signature method = jp.getSignature(); Object[] args = jp.getArgs(); System.out.println("Schema后置通知:"+target+",方法名为:"+method.getName()+",参数为:"+args[0]+",返回值:"+returnValue); } public void before() throws Throwable { System.out.println("Schema前置通知……"); } public void whenException(JoinPoint jp,NullPointerException e) { System.out.println("-----Schema异常通知:"+e.getStackTrace()); } public Object myAround(ProceedingJoinPoint pJoinPoint) { Object returnVlaue = null; try { System.out.println("Schema方法的前置通知..."); returnVlaue = pJoinPoint.proceed(); Object target = pJoinPoint.getTarget(); String name = pJoinPoint.getSignature().getName(); Object[] args = pJoinPoint.getArgs(); System.out.println("Schema方法的后置通知...对象:"+target+",方法:"+name+",参数:"+args[0]+",返回值:"+returnVlaue); }catch(Exception e) { System.out.println("Schema方法的异常通知..."); } catch (Throwable e) { e.printStackTrace(); } return returnVlaue; } }