一,前言
二,准备
创建JavaWeb项目,配置Spring,创建方法类,测试类,切面类
三,代码实现
1.配置xml文件
<!-- 定义目标对象 --> <bean id="stuimpl" class="com.stu.impl.StuImpl"></bean> <!-- 定义切面对象 --> <bean id="log" class="com.stu.Log"></bean> <!-- 切面配置 --> <aop:config> <!-- 切入点表达式:execution:具体到方法,within:具体到类,类中的所有方法,*:任意字符 ..:多层 execution(public void com.aaa.aop3.BookImpl.add(int)) execution(* * com..*.select*(..)) within(com.aaa.aop3.BookImpl):com.aaa.aop3.BookImpl下的所有方法 within(com.aaa.aop3.*):com.aaa.aop3包下所有类中所有方法 --> <!-- 定义一个可以被多个切面共享的切入点 --> <!-- <aop:pointcut expression="within(com.aaa.aop3.BookImpl)" id="points"/> --> <aop:pointcut expression="execution(* com.stu.impl.StuImpl.*(..))" id="points"/> <!-- 将id=log的对象作为切面使用 --> <aop:aspect ref="log"> <!-- method:方法 pointcut-ref:切入点 同时配置后置/异常/最终通知时:按照配置的先后顺序执行 -->
<!-- before:前置通知,总是在连接点调用前执行 --> <!-- <aop:before method="start" pointcut-ref="points"/> --> <!-- 后置通知:在方法正常执行完成之后调用 --> <!-- <aop:after-returning method="afterReturning" pointcut-ref="points"/> --> <!-- 异常通知:在方法异常执行之后调用 --> <!-- <aop:after-throwing method="afterThrowing" pointcut-ref="points" throwing="e"/> --> <!-- 最终通知:在方法执行完成之后调用 --> <!-- <aop:after method="after" pointcut-ref="points"/> --> <!-- 环绕通知:围绕方法的执行前后执行 --> <aop:around method="around" pointcut="execution(* com.stu.impl.StuImpl.*(..))"/> </aop:aspect> </aop:config>
2.Log类
package com.stu; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; public class Log { //定义方法开始时间和结束时间 long startTime; long afterTime; public void start() { //获取系统当前时间的毫秒数 startTime = System.currentTimeMillis(); System.out.println("前置通知before"); } // JoinPoint:连接点对象 public void after(JoinPoint jp) { System.out.println("最终通知after"); afterTime = System.currentTimeMillis(); Signature signature = jp.getSignature(); System.out.println(signature.getDeclaringTypeName()+"."+signature.getName()+"方法执行了"+(afterTime-startTime)+"ms"); } public void afterReturning() { System.out.println("后置通知afterReturning"); } public void afterThrowing(JoinPoint jp,Exception e) throws Exception { System.out.println("异常通知afterThrowing"); System.out.println("发生异常,异常的原因是" + e.getMessage()); } /** * ProceedingJoinPoint:正在执行的连接点,只能写在环绕通知中 * * @return返回值表示的连接点的返回值 */ public Object around(ProceedingJoinPoint pjp) { Object obj = null; System.out.println("环绕通知around"); try { System.out.println("环绕前置通知"); startTime = System.currentTimeMillis(); // proceed():执行连接点,返回连接点的返回值 // 获取正在执行的连接点对象所在的类,打印结果:class org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint Class<? extends ProceedingJoinPoint> class1 = pjp.getClass(); //System.out.println("class:" + class1); // 当前执行的连接点,打印结果:int com.stu.impl.StuImpl.update(int,int) Signature signature = pjp.getSignature(); //System.out.println("signature:" + signature); // 连接点的方法名,打印结果:update String name = signature.getName(); //System.out.println("name:" + name); // 连接点所在的类,打印结果:class com.stu.impl.StuImpl Class declaringType = signature.getDeclaringType(); //System.out.println("declaringType:" + declaringType); // 连接点所在的类名全路径,打印结果:com.stu.impl.StuImpl String declaringTypeName = signature.getDeclaringTypeName(); //System.out.println("declaringTypeName:" + declaringTypeName); // 调用连接点的目标对象,打印结果:com.stu.impl.StuImpl@6e4784bc Object target = pjp.getTarget(); //System.out.println("target:" + target); // 连接点传递的参数列表 Object[] args = pjp.getArgs(); System.out.println("args.length:" + args.length); for (Object o : args) {
System.out.println("arg:"+o);
} obj = pjp.proceed(); System.out.println("环绕后置通知"); } catch (Throwable e) { System.out.println("环绕异常通知"); Signature signature = pjp.getSignature(); System.out.println(signature.getDeclaringTypeName()+"."+signature.getName()+"方法时发生异常,异常的原因是" + e.getMessage()); } finally { System.out.println("环绕最终通知"); afterTime = System.currentTimeMillis(); Signature signature = pjp.getSignature(); System.out.println(signature.getDeclaringTypeName()+"."+signature.getName()+"方法执行了"+(afterTime-startTime)+"ms"); } return obj; } }
3.测试类
package com.stu; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.stu.impl.StuImpl; public class StuTest { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); StuImpl stuimpl = context.getBean(StuImpl.class);
Object object = stuimpl.test(1, 2);
System.out.println("object的值"+o); } }
4.打印结果:使用环绕通知,异常后返回值0,使用Object接受返回值并输出
环绕通知around
环绕前置通知
args.length:2
arg:1
arg:2
test方法
环绕后置通知
环绕最终通知
com.stu.impl.StuImpl.test方法执行了16ms
object的值1