Spring aop的两种配置方式(XML配置AOP、注解配置AOP)
闲来无聊对项目中用到的AOP配置进行了一下归并。
AOP配置方式一(XML配置AOP):
1. 编写通知类
1 /** 2 * 通过XML的方式配置AOP 3 */ 4 public class AspectXmlCheck { 5 Logger logger = LoggerFactory.getLogger(AspectXmlCheck.class); 6 7 /** 8 * 前通知方法 9 * @param jp 连接点对象 10 */ 11 public void beforeCheck(JoinPoint jp) { 12 Object[] args = jp.getArgs(); 13 Stream.of(args).forEach(arg -> { 14 logger.info("before: " + (arg == null ? "null" : arg.toString())); 15 }); 16 } 17 18 /** 19 * 后通知方法 20 * @param jp 连接点对象 21 * @param retVal 连接点对象执行后返回的对象 22 */ 23 public void afterCheck(JoinPoint jp, Object retVal) { 24 logger.info("after: " + (retVal == null ? "null" : retVal.toString())); 25 } 26 27 /** 28 * 环绕通知方法 29 * @param pjp 连接点对象 30 */ 31 public Object aroundCheck(ProceedingJoinPoint pjp) { 32 Object[] args = pjp.getArgs(); 33 Stream.of(args).forEach(arg -> { 34 logger.info("around before: " + (arg == null ? "null" : arg.toString())); 35 }); 36 37 Object proceed = null; 38 try { 39 proceed = pjp.proceed(); 40 } catch (Throwable throwable) { 41 logger.error("around execute error:", throwable); 42 } 43 logger.info("around after: " + (proceed == null ? "null" : proceed.toString())); 44 45 return proceed; 46 } 47 }
2. 在spring配置文件中引入aop标签的命名空间及地址(否则aop标签识不了)
3. 在spring配置文件中定义切面(execution表达式请自行脑补)
<bean id="aspectXmlCheck" class="com.cn.simple.aspect.AspectXmlCheck" /> <aop:config> <aop:aspect id="myAspectCheck" ref="aspectXmlCheck"> <aop:pointcut id="checkPointCut" expression="execution(* com.cn.simple.service.SimpleService.doSomething(..))"/> <aop:before method="beforeCheck" pointcut-ref="checkPointCut"/> <aop:after-returning method="afterCheck" pointcut-ref="checkPointCut" arg-names="jp,retVal" returning="retVal"/> <aop:around method="aroundCheck" pointcut-ref="checkPointCut"/> </aop:aspect> </aop:config>
AOP配置方式二(注解配置AOP):
1. 在spring配置文件中引入aop标签的命名空间及地址(否则aop标签识不了)
2. 在spring配置文件中打开动态代理
<!--使用注解配置AOP必须打开如下,否则无效,XML配置AOP则无需--> <!-- 通过aop命名空间的<aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面。 默认为false,表示使用jdk动态代理织入增强,当配为<aop:aspectj-autoproxy poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强--> <aop:aspectj-autoproxy />
3. 编写切面类
/** * 通过注解的方式切入 */ @Component @Aspect public class AspectAnnCheck { Logger logger = LoggerFactory.getLogger(AspectAnnCheck.class); /** * 方式一 * 1. 先定义切入点(方法名随便定义,用于后续定义通知的时候引用) * 2. 定义通知(并引用切入点) Before,After,AfterReturning,AfterThrowing,Around */ /** * 先定义切入点(方法名随便定义,用于后续定义通知的时候引用) */ @Pointcut(value = "execution(* com.cn.simple.service.SimpleService.*(..))") public void saySomething() { } /** * 前通知 * 找到切入点,同时满足添加了AopCheckAnn注解的方法进行通知 * @param jp 目标类连接点对象 * @param aopCheckAnn 注解对象 */ @Before(value = "saySomething() && @annotation(aopCheckAnn)") public void saySomethingBefore(JoinPoint jp, AopCheckAnn aopCheckAnn) { Object[] args = jp.getArgs(); String thing = Arrays.toString(args); logger.info("1.before say: " + thing + " to " + aopCheckAnn.toWho() + " for " + aopCheckAnn.forWhat()); } /** * 后通知 * 找到切入点,同时满足添加了AopCheckAnn注解的方法进行通知 * @param jp 目标类连接点对象 * @param aopCheckAnn 注解对象 * @param retVal 连接点对象执行后返回的对象 */ @AfterReturning(value = "saySomething() && @annotation(aopCheckAnn)", argNames = "jp, aopCheckAnn, retVal", returning = "retVal") public void saySomethingAfterReturning(JoinPoint jp, AopCheckAnn aopCheckAnn, Object retVal) { logger.info("1.after say: " + (retVal == null ? "none" : retVal.toString()) + " to " + aopCheckAnn.toWho() + " for " + aopCheckAnn.forWhat()); } /** * 环绕通知 * 找到切入点,同时满足添加了AopCheckAnn注解的方法进行通知 * @param pjp 连接点对象 * @param aopCheckAnn 注解对象 * @return 连接点对象执行后返回的对象 */ @Around(value = "saySomething() && @annotation(aopCheckAnn)") public Object saySomethingAround(ProceedingJoinPoint pjp, AopCheckAnn aopCheckAnn) { Object[] args = pjp.getArgs(); Object proceed = null; try { proceed = pjp.proceed(); } catch (Throwable throwable) { logger.error("around execute error:", throwable); } logger.info("1.around say: " + (proceed == null ? "none" : proceed.toString()) + " to " + aopCheckAnn.toWho() + " for " + aopCheckAnn.forWhat()); return proceed; } /** * 方式二 * 直接通知并定义切面 */ /** * 前通知 * @param jp 目标类连接点对象 * @param aopCheckAnn 注解对象 */ @Before(value = "execution(* com.cn.simple.service.SimpleService.saySomething(..)) && @annotation(aopCheckAnn)") public void sayBefore(JoinPoint jp, AopCheckAnn aopCheckAnn) { Object[] args = jp.getArgs(); String thing = Arrays.toString(args); logger.info("2.before say: " + thing + " to " + aopCheckAnn.toWho() + " for " + aopCheckAnn.forWhat()); } /** * 后通知 * 找到切入点,同时满足添加了AopCheckAnn注解的方法进行通知 * @param jp 目标类连接点对象 * @param aopCheckAnn 注解对象 * @param retVal 连接点对象执行后返回的对象 */ @AfterReturning(value = "execution(* com.cn.simple.service.SimpleService.saySomething(..)) && @annotation(aopCheckAnn)", argNames = "jp, aopCheckAnn, retVal", returning = "retVal") public void sayAfterReturning(JoinPoint jp, AopCheckAnn aopCheckAnn, Object retVal) { logger.info("2.after say: " + (retVal == null ? "none" : retVal.toString()) + " to " + aopCheckAnn.toWho() + " for " + aopCheckAnn.forWhat()); } /** * 环绕通知 * 找到切入点,同时满足添加了AopCheckAnn注解的方法进行通知 * @param pjp 连接点对象 * @param aopCheckAnn 注解对象 * @return 连接点对象执行后返回的对象 */ @Around(value = "execution(* com.cn.simple.service.SimpleService.saySomething(..)) && @annotation(aopCheckAnn)") public Object sayAround(ProceedingJoinPoint pjp, AopCheckAnn aopCheckAnn) { Object[] args = pjp.getArgs(); Object proceed = null; try { proceed = pjp.proceed(); } catch (Throwable throwable) { logger.error("around execute error:", throwable); } logger.info("2.around say: " + (proceed == null ? "none" : proceed.toString()) + " to " + aopCheckAnn.toWho() + " for " + aopCheckAnn.forWhat()); return proceed; } }
@Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE, ElementType.METHOD }) public @interface AopCheckAnn { String toWho() default "none"; String forWhat() default "nothing"; }