1、引入相关jar包
2、Spring的配置文件 applicationContext.xml 中引入context、aop对应的命名空间;配置自动扫描的包,同时使切面类中相关方法中的注解生效,需自动地为匹配到的方法所在的类生成代理对象。
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 配置自动扫描的包 --> <context:component-scan base-package="com.qcc.beans.aop"></context:component-scan> <!-- 自动为切面方法中匹配的方法所在的类生成代理对象。 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy></beans>3、创建简单计算器的接口ArithmeticCalculator.java及实现类ArithmeticCalculatorImpl.java
package com.qcc.beans.aop;public interface ArithmeticCalculator { int add(int i, int j); int sub(int i, int j); int mul(int i, int j); int div(int i, int j);}package com.qcc.beans.aop;import org.springframework.stereotype.Component;//将实现类加入Spring的IOC容器进行管理@Component("arithmeticCalculator")public class ArithmeticCalculatorImpl implements ArithmeticCalculator { @Override public int add(int i, int j) { int result = i + j; return result; } @Override public int sub(int i, int j) { int result = i - j; return result; } @Override public int mul(int i, int j) { int result = i * j; return result; } @Override public int div(int i, int j) { int result = i / j; return result; }}4、现在想在实现类中的每个方法执行前、后、以及是否发生异常等信息打印出来,需要把日志信息抽取出来,写到对应的切面的类中 LoggingAspect.java 中 要想把一个类变成切面类,需要两步, ① 在类上使用 @Component 注解 把切面类加入到IOC容器中 ② 在类上使用 @Aspect 注解 使之成为切面类
下面直接上完整代码,用@Aspect注解方式来实现前置通知、返回通知、后置通知、异常通知、环绕通知。
package com.qcc.beans.aop;import java.util.Arrays;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.springframework.stereotype.Component;/** * 日志切面 * * @author QianChaoChen 00002336<br> * @date 2017年3月3日 下午3:03:29 */@Component@Aspectpublic class LoggingAspect { /** * 前置通知:目标方法执行之前执行以下方法体的内容 * @param jp */ @Before("execution(* com.qcc.beans.aop.*.*(..))") public void beforeMethod(JoinPoint jp){ String methodName = jp.getSignature().getName(); System.out.println("【前置通知】the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs())); } /** * 返回通知:目标方法正常执行完毕时执行以下代码 * @param jp * @param result */ @AfterReturning(value="execution(* com.qcc.beans.aop.*.*(..))",returning="result") public void afterReturningMethod(JoinPoint jp, Object result){ String methodName = jp.getSignature().getName(); System.out.println("【返回通知】the method 【" + methodName + "】 ends with 【" + result + "】"); } /** * 后置通知:目标方法执行之后执行以下方法体的内容,不管是否发生异常。 * @param jp */ @After("execution(* com.qcc.beans.aop.*.*(..))") public void afterMethod(JoinPoint jp){ System.out.println("【后置通知】this is a afterMethod advice..."); } /** * 异常通知:目标方法发生异常的时候执行以下代码 */ @AfterThrowing(value="execution(* com.qcc.beans.aop.*.*(..))",throwing="e") public void afterThorwingMethod(JoinPoint jp, NullPointerException e){ String methodName = jp.getSignature().getName(); System.out.println("【异常通知】the method 【" + methodName + "】 occurs exception: " + e); }// /**// * 环绕通知:目标方法执行前后分别执行一些代码,发生异常的时候执行另外一些代码// * @return // */// @Around(value="execution(* com.qcc.beans.aop.*.*(..))")// public Object aroundMethod(ProceedingJoinPoint jp){// String methodName = jp.getSignature().getName();// Object result = null;// try {// System.out.println("【环绕通知中的--->前置通知】:the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs()));// //执行目标方法// result = jp.proceed();// System.out.println("【环绕通知中的--->返回通知】:the method 【" + methodName + "】 ends with " + result);// } catch (Throwable e) {// System.out.println("【环绕通知中的--->异常通知】:the method 【" + methodName + "】 occurs exception " + e);// }// // System.out.println("【环绕通知中的--->后置通知】:-----------------end.----------------------");// return result;// }}5、编写Main方法进行测试
package com.qcc.beans.aop;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Main { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator"); System.out.println(arithmeticCalculator.getClass()); int result = arithmeticCalculator.add(3, 5); System.out.println("result: " + result); result = arithmeticCalculator.div(5, 0); System.out.println("result: " + result); }}运行结果:
class com.sun.proxy.$Proxy10【前置通知】the method 【add】 begins with [3, 5]【后置通知】this is a afterMethod advice...【返回通知】the method 【add】 ends with 【8】result: 8【前置通知】the method 【div】 begins with [5, 0]【后置通知】this is a afterMethod advice...Exception in thread "main" java.lang.ArithmeticException: / by zero at com.qcc.beans.aop.ArithmeticCalculatorImpl.div(ArithmeticCalculatorImpl.java:28) at sun.reflect.NativeMethodaccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:43) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:52) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:58) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207) at com.sun.proxy.$Proxy10.div(Unknown Source) at com.qcc.beans.aop.Main.main(Main.java:15)把其它代码都注释掉,把环绕通知的方法释放出来,测试结果如下:
【环绕通知中的--->前置通知】:the method 【add】 begins with [3, 5]【环绕通知中的--->返回通知】:the method 【add】 ends with 8【环绕通知中的--->后置通知】:-----------------end.----------------------result: 8【环绕通知中的--->前置通知】:the method 【div】 begins with [5, 0]【环绕通知中的--->异常通知】:the method 【div】 occurs exception java.lang.ArithmeticException: / by zero【环绕通知中的--->后置通知】:-----------------end.----------------------Exception in thread "main" org.springframework.aop.AopInvocationException: Null return value from advice does not match primitive return type for: public abstract int com.qcc.beans.aop.ArithmeticCalculator.div(int,int) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:219) at com.sun.proxy.$Proxy7.div(Unknown Source) at com.qcc.beans.aop.Main.main(Main.java:15)从以上发现,返回通知和异常通知不会同时出现;不管是否发生异常,后置通知都会正常打印。
新闻热点
疑难解答