1、获取拦截方法的返回值和抛的异常信息
获取方法返回的值分为两个步骤:
1、在返回值通知的方法中,追加一个参数 Object result
2、然后在@AfterReturning注解中添加参数returning=“参数名”
获取方法抛出的异常分为两个步骤:
1、在异常通知的方法中,追加一个参数Exception exception
2、然后在@AfterThrowing 注解中添加参数 throwing=“参数名”
修改LogUtil切面类的代码
@AfterReturning(value = "execution(public int com.atguigu.aop.Calculator.add(int, int))"
+ " || " + "execution(public * com.atguigu.aop.Calculator.d*(..))", returning = "result")
public static void logAfterReturn(JoinPoint joinPoint, Object result) {
System.out.println("返回之后: 日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"
+ Arrays.asList(joinPoint.getArgs()) + ",返回值:" + result);
}
@AfterThrowing(value = "execution(public int com.atguigu.aop.Calculator.add(int, int))"
+ " || " + "execution(public * com.atguigu.aop.Calculator.d*(..))", throwing = "exception")
public static void logThrowException(JoinPoint joinPoint, Exception exception) {
System.out.println("抛异常:日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"
+ Arrays.asList(joinPoint.getArgs()) + ",异常对象:" + exception);
}
测试结果
2、Spring的环绕通知
1、环绕通知使用@Around注解。
2、环绕通知如果和其他通知同时执行。环绕通知会优先于其他通知之前执行。
3、环绕通知一定要有返回值(环绕如果没有返回值。后面的其他通知就无法接收到目标方法执行的结果)。
4、在环绕通知中。如果拦截异常。一定要往外抛。否则其他的异常通知是无法捕获到异常的。
在LogUtil切面类中添加环绕通知
@Around(value = "execution(* *(..))")
public static Object logAround(ProceedingJoinPoint proceedingJoinPoint) {
//获取请求参数
Object[] args = proceedingJoinPoint.getArgs();
Object resultObject = null;
try {
System.out.println("环绕前置");
//调用目标方法
resultObject = proceedingJoinPoint.proceed(args);
System.out.println("环绕后置");
} catch (Throwable e) {
System.out.println("环绕异常:" + e);
throw new RuntimeException(e);
} finally {
System.out.println("环绕返回后");
}
//返回返回值
return resultObject;
}
修改测试的代码
@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringAopTest {
@Autowired
private Calculator calculator;
@Test
public void test1() {
//加法
calculator.add(1, 2);
}
}
执行结果
3、切入点表达式的重用
切入点表达式的重点,需要分三个步骤:
1、在切面类中定义一个空的方法
public static void pointcut1() {}
2、在方法中使用@Pointcut定义一个切入连表达式
@Pointcut(value="execution(public int com.atguigu.aop.Calculator.add(int, int))" + " || "
+ "execution(public * com.atguigu.aop.Calculator.*(..))")
public static void pointcut1() {}
3、其他的通知注解中使用方法名()的形式引用方法上定义的切入点表达式。
比如:@Before("pointcut1()")
4、多个通知的执行顺序
当有多个切面,多个通知的时候:
1、通知的执行顺序默认是由切面类的字母先后顺序决定。
2、在切面类上使用@Order注解决定通知执行的顺序(值越小,越先执行)
再添加另一个切面类
@Component
@Aspect
@Order(1)
public class Validation {
@Before(value = "com.atguigu.aop.LogUtil.pointcut1()")
public static void before(JoinPoint joinPoint) {
System.out.println("这是Validation的前置通知,拦截的方法是:" + joinPoint.getSignature().getName());
}
@After(value = "com.atguigu.aop.LogUtil.pointcut1()")
public static void after(JoinPoint joinPoint) {
System.out.println("这是Validation的后置通知,拦截的方法是:" + joinPoint.getSignature().getName());
}
@AfterReturning(value = "com.atguigu.aop.LogUtil.pointcut1()", returning = "result")
public static void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println("这是Validation的后置通知,拦截的方法是:" + joinPoint.getSignature().getName()
+ ", 返回值:" + result);
}
}
修改原来LogUtil中的切面内容(去掉环绕通知,留下前置,后置,返回后通知)
@Aspect
@Component
@Order(2)
public class LogUtil {
@Pointcut(value="execution(public int com.atguigu.aop.Calculator.add(int, int))" + " || "
+ "execution(public * com.atguigu.aop.Calculator.*(..))")
public static void pointcut1() {}
测试的代码
@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringAopTest {
@Autowired
private Calculator calculator;
@Test
public void test1() {
//加法
calculator.add(1, 0);
}
}
运行的结果
5、如何基于xml配置aop程序
需要导入的包
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.3.jar
log4j-1.2.17.jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
spring-test-4.0.0.RELEASE.jar
工程中编写的类
public class Calculator {
public int div(int num1, int num2) {
return num1 / num2;
}
public int add(int num1, int num2) {
return num1 + num2;
}
}
LogUtil切面类
public class LogUtil {
public static void logBefore(JoinPoint joinPoint) {
System.out.println("前置 日记 :【" + joinPoint.getSignature().getName() + "】 方法调用前 。参数是:"
+ Arrays.asList(joinPoint.getArgs()));
}
public static void logAfter(JoinPoint joinPoint) {
System.out.println("后置 日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"
+ Arrays.asList(joinPoint.getArgs()));
}
public static void logAfterReturn(JoinPoint joinPoint, Object result) {
System.out.println("返回之后: 日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"
+ Arrays.asList(joinPoint.getArgs()) + ",返回值:" + result);
}
public static void logThrowException(JoinPoint joinPoint, Exception exception) {
System.out.println("抛异常:日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"
+ Arrays.asList(joinPoint.getArgs()) + ",异常对象:" + exception);
}
}
Validation切面类
public class Validation {
public static void before(JoinPoint joinPoint) {
System.out.println("这是Validation的前置通知,拦截的方法是:" + joinPoint.getSignature().getName());
}
public static void after(JoinPoint joinPoint) {
System.out.println("这是Validation的后置通知,拦截的方法是:" + joinPoint.getSignature().getName());
}
public static void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println("这是Validation的后置通知,拦截的方法是:" + joinPoint.getSignature().getName()
+ ", 返回值:" + result);
}
}
ApplicationContext.xml配置文件中的内容
<!-- 注册bean对象
添加@Component
-->
<bean id="calculator" class="com.atguigu.aop.Calculator" />
<bean id="logUtil" class="com.atguigu.aop.LogUtil" />
<bean id="validation" class="com.atguigu.aop.Validation" />
<!-- 配置AOP -->
<aop:config>
<!-- 定义可以共用的切入点 -->
<aop:pointcut expression="execution(* com.atguigu.aop.Calculator.*(..))" id="pointcut1"/>
<!-- 定义切面类 -->
<aop:aspect order="1" ref="logUtil">
<!-- 这是前置通知
method属性配置通知的方法
pointcut配置切入点表达式
-->
<aop:before method="logBefore" pointcut="execution(* com.atguigu.aop.Calculator.*(..))"/>
<aop:after method="logAfter" pointcut="execution(* com.atguigu.aop.Calculator.*(..))"/>
<aop:after-returning method="logAfterReturn"
returning="result" pointcut="execution(* com.atguigu.aop.Calculator.*(..))"/>
<aop:after-throwing method="logThrowException" throwing="exception"
pointcut="execution(* com.atguigu.aop.Calculator.*(..))"/>
</aop:aspect>
<!-- 定义切面类 -->
<aop:aspect order="2" ref="validation">
<aop:before method="before" pointcut-ref="pointcut1"/>
<aop:after method="after" pointcut-ref="pointcut1"/>
<aop:after-returning method="afterReturning"
returning="result" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>
测试的代码
@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringAopTest {
@Autowired
Calculator calculator;
@Test
public void test1() {
calculator.add(1, 2);
}
}