Spring aop介绍
最近一段时间重新学习了Spring的aop思想, 虽然在项目中使用的比较少, 但是还是这里要记录下.
aop的使用有两种方式: XML和注解
1. XML方式
下面使用框架是SpringMVC+Mybatis+Aop, 这里只讨论Aop的作用, 其他如springmvc和mybatis的配置,这里就不给出具体代码了...
先给出XML的配置:
<!-- Aop(面向切面的编程, xml配置) --> <bean id="aspectDemoOne" class="com.springdemo.aop.AspectDemoOne" /> <aop:config> <aop:pointcut expression="execution(* com.springdemo.controller.*.*(..))" id="pointcut" /> <!-- 监听包com.springdemo.controller下所有的类和所有的方法 -->
<!--下面的method属性对应的方法必须要在类AspectDemoOne中全部对应-->
<aop:aspect ref="aspectDemoOne"> <!-- 前置通知 --> <aop:before method="beforMethod" pointcut-ref="pointcut" /> <!-- 后置通知 --> <aop:after method="afterMethod" pointcut-ref="pointcut"/> <!-- 返回通知 --> <aop:after-returning method="afterReturnMethod" pointcut-ref="pointcut" returning="result"/> <!-- 异常通知 --> <aop:after-throwing method="afterThrowingMethod" pointcut-ref="pointcut" throwing="ex"/> <!-- 环绕通知 --> <aop:around method="aroundMethod" pointcut-ref="pointcut"/> </aop:aspect> </aop:config>
下面是测试用的AspectDemoOne类:
package com.springdemo.aop; import java.util.Arrays; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; public class AspectDemoOne { private static final Logger LOG = LogManager.getLogger(AspectDemoOne.class); /** before * 前置通知 * @param joinPoint */ public void beforeMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); List<Object> args = Arrays.asList(joinPoint.getArgs()); LOG.info("beforeMethod=>this method=>" + methodName + " begin. param<" + args + ">"); } /** after * 后置通知(无论方法是否发生异常都会执行, 所以访问不到方法的返回值) * @param joinPoint */ public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); LOG.info("afterMethod=>this method=>" + methodName); } /** after-returning * 返回通知(在方法正常结束执行的代码) * 返回通知可以访问到方法的返回值! * @param joinPoint */ public void afterReturnMethod(JoinPoint joinPoint, Object result){ String methodName = joinPoint.getSignature().getName(); LOG.info("afterReturnMethod=>this method=>" + methodName + " end.result<" + result + ">"); } /** after-throwing * 异常通知(方法发生异常执行的代码) * 可以访问到异常对象;且可以指定在出现特定异常时执行的代码 * @param joinPoint * @param ex */ public void afterThrowingMethod(JoinPoint joinPoint, Exception ex){ String methodName = joinPoint.getSignature().getName(); LOG.info("afterThrowingMethod=>this method=>" + methodName + " end.ex message<" + ex + ">"); } /** around * 环绕通知(需要携带类型为ProceedingJoinPoint类型的参数) * 环绕通知包含前置、后置、返回、异常通知;ProceedingJoinPoin 类型的参数可以决定是否执行目标方法 * 且环绕通知必须有返回值,返回值即目标方法的返回值 * @param point */ public Object aroundMethod(ProceedingJoinPoint point){ Object result = null; String methodName = point.getSignature().getName(); try { //前置通知 LOG.info("aroundMethod=>the method=>" + methodName + " start. param<" + Arrays.asList(point.getArgs()) + ">"); //执行目标方法 result = point.proceed(); //返回通知 LOG.info("aroundMethod=>the method=>" + methodName + " end. result<" + result + ">"); } catch (Throwable e) { //异常通知 LOG.info("aroundMethod=>this method=>" + methodName + " end.ex message<" + e + ">"); throw new RuntimeException(e); } //后置通知 LOG.info("aroundMethod=>the method=>" + methodName + " end."); return result; } }
下面是Controller包下面的一个:
@Controller @RequestMapping(value = "/author") public class AuthorController { private static final Logger LOG = LogManager.getLogger(AuthorController.class); @Autowired private AuthorService authorService; @RequestMapping(value="/request") @ResponseBody public Author requestExample(@RequestBody Author[] authors) { for (Author author : authors) { LOG.info("name="+author.getName()+",age="+author.getAge()+",country="+author.getCountry()); } Author author = new Author(); author.setName("authorFour"); author.setAge(25); author.setCountry("Germany"); return author; } }
输入URL: http://localhost/MavenSpringMVC/author/request
2. 注解方式
其他的配置和上面的一样, 其中xml的配置可以删除,下面用spring的注解方式定义Aop思想:
给出测试用的AspectDemoTwo类:
package com.springdemo.aop; import java.util.Arrays; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Aspect @Order(1) @Component public class AspectDemoTwo { private static final Logger LOG = LogManager.getLogger(AspectDemoTwo.class); /** * 定义一个方法,用于声明切入点表达式,方法中一般不需要添加其他代码 * 使用@Pointcut声明切入点表达式 * 后面的通知直接使用方法名来引用当前的切点表达式;如果是其他类使用,加上包名即可 */ @Pointcut("execution(public * com.springdemo.controller.*Controller.*(..))") public void declearJoinPointExpression() { } /** * before 前置通知 * * @param joinPoint */ //该标签声明次方法是一个前置通知:在目标方法开始之前执行 @Before("declearJoinPointExpression()") public void beforeMethod(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); List<Object> args = Arrays.asList(joinPoint.getArgs()); LOG.info("beforeMethod=>this method=>" + methodName + " begin. param<" + args + ">"); } /** * after 后置通知(无论方法是否发生异常都会执行, 所以访问不到方法的返回值) * * @param joinPoint */ @After("declearJoinPointExpression()") public void afterMethod(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); LOG.info("afterMethod=>this method=>" + methodName); } /** * after-returning 返回通知(在方法正常结束执行的代码) 返回通知可以访问到方法的返回值! * * @param joinPoint */ @AfterReturning(value="declearJoinPointExpression()", returning="result") public void afterReturnMethod(JoinPoint joinPoint, Object result) { String methodName = joinPoint.getSignature().getName(); LOG.info("afterReturnMethod=>this method=>" + methodName + " end.result<" + result + ">"); } /** * after-throwing 异常通知(方法发生异常执行的代码) 可以访问到异常对象;且可以指定在出现特定异常时执行的代码 * * @param joinPoint * @param ex */ @AfterThrowing(value="declearJoinPointExpression()", throwing="ex") public void afterThrowingMethod(JoinPoint joinPoint, Exception ex) { String methodName = joinPoint.getSignature().getName(); LOG.info("afterThrowingMethod=>this method=>" + methodName + " end.ex message<" + ex + ">"); } /** * around 环绕通知(需要携带类型为ProceedingJoinPoint类型的参数) * 环绕通知包含前置、后置、返回、异常通知;ProceedingJoinPoin 类型的参数可以决定是否执行目标方法 * 且环绕通知必须有返回值,返回值即目标方法的返回值 * * @param point */ @Around(value="declearJoinPointExpression()") public Object aroundMethod(ProceedingJoinPoint point) { Object result = null; String methodName = point.getSignature().getName(); try { // 前置通知 LOG.info("aroundMethod=>the method=>" + methodName + " start. param<" + Arrays.asList(point.getArgs()) + ">"); // 执行目标方法 result = point.proceed(); // 返回通知 LOG.info("aroundMethod=>the method=>" + methodName + " end. result<" + result + ">"); } catch (Throwable e) { // 异常通知 LOG.info("aroundMethod=>this method=>" + methodName + " end.ex message<" + e + ">"); throw new RuntimeException(e); } // 后置通知 LOG.info("aroundMethod=>the method=>" + methodName + " end."); return result; } }
输入URL: http://localhost/MavenSpringMVC/author/request
09:33:59.959 [http-nio-8080-exec-6] INFO com.springdemo.aop.AspectDemoTwo - aroundMethod=>the method=>showAuthorByBootGrid start. param<[]> 09:33:59.959 [http-nio-8080-exec-6] INFO com.springdemo.aop.AspectDemoTwo - beforeMethod=>this method=>showAuthorByBootGrid begin. param<[]> 09:34:00.005 [http-nio-8080-exec-6] INFO com.springdemo.aop.AspectDemoTwo - aroundMethod=>the method=>showAuthorByBootGrid end. result<author/bootgrid> 09:34:00.005 [http-nio-8080-exec-6] INFO com.springdemo.aop.AspectDemoTwo - aroundMethod=>the method=>showAuthorByBootGrid end. 09:34:00.005 [http-nio-8080-exec-6] INFO com.springdemo.aop.AspectDemoTwo - afterMethod=>this method=>showAuthorByBootGrid 09:34:00.005 [http-nio-8080-exec-6] INFO com.springdemo.aop.AspectDemoTwo - afterReturnMethod=>this method=>showAuthorByBootGrid end.result<author/bootgrid>
...
09:34:11.008 [http-nio-8080-exec-10] INFO com.springdemo.aop.AspectDemoTwo - aroundMethod=>the method=>authorBootGridTwo end. result<>
09:34:11.008 [http-nio-8080-exec-10] INFO com.springdemo.aop.AspectDemoTwo - aroundMethod=>the method=>authorBootGridTwo end.
09:34:11.008 [http-nio-8080-exec-10] INFO com.springdemo.aop.AspectDemoTwo - afterMethod=>this method=>authorBootGridTwo
09:34:11.008 [http-nio-8080-exec-10] INFO com.springdemo.aop.AspectDemoTwo - afterReturnMethod=>this method=>authorBootGridTwo end.result<>