Spring学习(21)--- AOP之Advice应用(上) 出处:http://www.cnblogs.com/JsonShare
前置通知(Before advice) | 在某个连接点(join point)之前执行的通知,但不能阻止连接点前的执行(除非它抛出异常) |
返回后通知(After returning advice) | 在某个连接点(join point)正常完成后执行的通知 |
抛出异常后通知(After throwing advice) | 在方法抛出异常退出时执行的通知 |
后通知(After(finally) advice) | 当某个连接点退出的时候执行的通知(无论是正常返回还是异常退出) |
环绕通知(Around advice) | 包围一个连接点(join point)的通知 |
导入需要的包:aspectjweaver.jar、aopalliance-1.0.jar
(一)Before Advice
例子:
新建两个类:
package com.aop.schema; /** * * 切面类 * */ public class MyAspect { public void before(){ System.out.println("MyAspect.before"); } }
package com.aop.schema; /** * * 业务类 * */ public class ApsectBiz { public void biz(){ System.out.println("ApsectBiz.biz"); } }
XML配置:
<?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-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd"> <bean id="myAspect" class="com.aop.schema.MyAspect"></bean> <bean id="apsectBiz" class="com.aop.schema.ApsectBiz"></bean> <aop:config> <aop:aspect id="myAspectAOP" ref="myAspect"> <aop:pointcut id="myPointcut" expression="execution(* com.aop.schema.ApsectBiz.*(..))" /> <aop:before method="before" pointcut-ref="myPointcut"/> </aop:aspect> </aop:config> </beans>
单元测试:
package com.aop.schema; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class UnitTest { @Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-aop.xml"); ApsectBiz biz = (ApsectBiz)context.getBean("apsectBiz"); biz.biz(); } }
结果:
七月 09, 2015 10:30:24 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@31b3c607: startup date [Thu Jul 09 22:30:24 CST 2015]; root of context hierarchy 七月 09, 2015 10:30:24 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [spring-aop.xml] MyAspect.before ApsectBiz.biz
PS:ApsectBiz.biz是业务方法,在它之前,执行了前置通知MyAspect.before,符合想要的结果
(二)After returning advice
例子:
修改一下切面类MyAspect(添加afterreturning方法):
package com.aop.schema; /** * * 切面类 * */ public class MyAspect { public void before(){ System.out.println("MyAspect.before"); } public void afterreturning(){ System.out.println("MyAspect.afterreturning"); } }
XML配置修改为:
<?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-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd"> <bean id="myAspect" class="com.aop.schema.MyAspect"></bean> <bean id="apsectBiz" class="com.aop.schema.ApsectBiz"></bean> <aop:config> <aop:aspect id="myAspectAOP" ref="myAspect"> <aop:pointcut id="myPointcut" expression="execution(* com.aop.schema.ApsectBiz.*(..))" /> <aop:before method="before" pointcut-ref="myPointcut"/> <aop:after-returning method="afterreturning" pointcut-ref="myPointcut"/> </aop:aspect> </aop:config> </beans>
单元测试同上:
结果:
七月 09, 2015 10:38:41 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@31b3c607: startup date [Thu Jul 09 22:38:41 CST 2015]; root of context hierarchy 七月 09, 2015 10:38:41 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [spring-aop.xml] MyAspect.before ApsectBiz.biz MyAspect.afterreturning
(三)After throwing advice
说明:使用throwing属性来指定可被传递的异常的参数名称
例子:
修改一下切面类MyAspect(添加afterthrowing方法):
package com.aop.schema; /** * * 切面类 * */ public class MyAspect { public void before(){ System.out.println("MyAspect.before"); } public void afterreturning(){ System.out.println("MyAspect.afterreturning"); } public void afterthrowing(){ System.out.println("MyAspect.afterthrowing"); } }
修改业务类ApsectBiz(抛出一个异常):
package com.aop.schema; /** * * 业务类 * */ public class ApsectBiz { public void biz(){ System.out.println("ApsectBiz.biz"); throw new RuntimeException(); //故意抛出异常 } }
XML配置:
<?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-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd"> <bean id="myAspect" class="com.aop.schema.MyAspect"></bean> <bean id="apsectBiz" class="com.aop.schema.ApsectBiz"></bean> <aop:config> <aop:aspect id="myAspectAOP" ref="myAspect"> <aop:pointcut id="myPointcut" expression="execution(* com.aop.schema.ApsectBiz.*(..))" /> <aop:before method="before" pointcut-ref="myPointcut"/> <aop:after-returning method="afterreturning" pointcut-ref="myPointcut"/> <aop:after-throwing method="afterthrowing" pointcut-ref="myPointcut"/> </aop:aspect> </aop:config> </beans>
单元测试同上:
测试结果:
七月 09, 2015 10:47:46 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@31b3c607: startup date [Thu Jul 09 22:47:46 CST 2015]; root of context hierarchy 七月 09, 2015 10:47:46 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [spring-aop.xml] MyAspect.before ApsectBiz.biz MyAspect.afterthrowing
PS:有没有发现有什么问题? MyAspect.afterreturning没有了,biz()中抛出异常,biz()方法没有正常返回,所以MyAspect.afterreturning没有了。
(四)After(finally) advice
修改一下切面类MyAspect(添加after方法):
package com.aop.schema; /** * * 切面类 * */ public class MyAspect { public void before(){ System.out.println("MyAspect.before"); } public void afterreturning(){ System.out.println("MyAspect.afterreturning"); } public void afterthrowing(){ System.out.println("MyAspect.afterthrowing"); } public void after(){ System.out.println("MyAspect.after"); } }
XML配置:
<?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-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd"> <bean id="myAspect" class="com.aop.schema.MyAspect"></bean> <bean id="apsectBiz" class="com.aop.schema.ApsectBiz"></bean> <aop:config> <aop:aspect id="myAspectAOP" ref="myAspect"> <aop:pointcut id="myPointcut" expression="execution(* com.aop.schema.ApsectBiz.*(..))" /> <aop:before method="before" pointcut-ref="myPointcut"/> <aop:after-returning method="afterreturning" pointcut-ref="myPointcut"/> <aop:after-throwing method="afterthrowing" pointcut-ref="myPointcut"/> <aop:after method="after" pointcut-ref="myPointcut"/> </aop:aspect> </aop:config> </beans>
单元测试同上:
结果:
七月 09, 2015 10:56:10 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@31b3c607: startup date [Thu Jul 09 22:56:10 CST 2015]; root of context hierarchy 七月 09, 2015 10:56:10 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [spring-aop.xml] MyAspect.before ApsectBiz.biz MyAspect.afterthrowing MyAspect.after
(五)Around advice
注意:通知方法的第一个参数必ProceedingJoinPoint类型
例子:
修改一下切面类MyAspect(添加around方法):
package com.aop.schema; import org.aspectj.lang.ProceedingJoinPoint; /** * * 切面类 * */ public class MyAspect { public void before(){ System.out.println("MyAspect.before"); } public void afterreturning(){ System.out.println("MyAspect.afterreturning"); } public void afterthrowing(){ System.out.println("MyAspect.afterthrowing"); } public void after(){ System.out.println("MyAspect.after"); } public void around(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("MyAspect.around_1"); Object obj=pjp.proceed(); System.out.println("MyAspect.around_2"); } }
XML配置:
<?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-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd"> <bean id="myAspect" class="com.aop.schema.MyAspect"></bean> <bean id="apsectBiz" class="com.aop.schema.ApsectBiz"></bean> <aop:config> <aop:aspect id="myAspectAOP" ref="myAspect"> <aop:pointcut id="myPointcut" expression="execution(* com.aop.schema.ApsectBiz.*(..))" /> <aop:before method="before" pointcut-ref="myPointcut"/> <aop:after-returning method="afterreturning" pointcut-ref="myPointcut"/> <aop:after-throwing method="afterthrowing" pointcut-ref="myPointcut"/> <aop:after method="after" pointcut-ref="myPointcut"/> <aop:around method="around" pointcut-ref="myPointcut"/> </aop:aspect> </aop:config> </beans>
单元测试同上:
结果:
七月 09, 2015 11:15:20 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@31b3c607: startup date [Thu Jul 09 23:15:20 CST 2015]; root of context hierarchy 七月 09, 2015 11:15:20 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [spring-aop.xml] MyAspect.before MyAspect.around_1 ApsectBiz.biz java.lang.RuntimeException at com.aop.schema.ApsectBiz.biz(ApsectBiz.java:11) at com.aop.schema.ApsectBiz$$FastClassBySpringCGLIB$$ae10254d.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85) at com.aop.schema.MyAspect.around(MyAspect.java:31) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610) at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:68) 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.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:58) 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.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52) 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.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653) at com.aop.schema.ApsectBiz$$EnhancerBySpringCGLIB$$1fbf7bae.biz(<generated>) at com.aop.schema.UnitTest.test(UnitTest.java:13) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) at org.junit.runners.ParentRunner.run(ParentRunner.java:309) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) MyAspect.after MyAspect.afterreturning
PS:有异常,仔细看,原来是around(ProceedingJoinPoint pjp)的try catch捕捉到了biz()抛出的异常,现在把异常注释掉(try catch里面怎么处理异常?这里要看具体的业务需要,这里先注释掉)
package com.aop.schema; /** * * 业务类 * */ public class ApsectBiz { public void biz(){ System.out.println("ApsectBiz.biz"); //throw new RuntimeException(); //故意抛出异常 } }
测试结果:
七月 09, 2015 11:18:17 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@31b3c607: startup date [Thu Jul 09 23:18:17 CST 2015]; root of context hierarchy 七月 09, 2015 11:18:17 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [spring-aop.xml] MyAspect.before MyAspect.around_1 ApsectBiz.biz MyAspect.around_2 MyAspect.after MyAspect.afterreturning
Spring学习(22)--- AOP之Advice应用(下)
(六)Advice parameters(advice带参数的情况)
例子:
修改MyAspect(添加around_init方法):
1 package com.aop.schema; 2 3 import org.aspectj.lang.ProceedingJoinPoint; 4 5 /** 6 * 7 * 切面类 8 * 9 */ 10 public class MyAspect { 11 12 public void before(){ 13 System.out.println("MyAspect.before"); 14 } 15 16 public void afterreturning(){ 17 System.out.println("MyAspect.afterreturning"); 18 } 19 20 public void afterthrowing(){ 21 System.out.println("MyAspect.afterthrowing"); 22 } 23 24 public void after(){ 25 System.out.println("MyAspect.after"); 26 } 27 28 public void around(ProceedingJoinPoint pjp) { 29 try { 30 System.out.println("MyAspect.around_1"); 31 Object obj=pjp.proceed(); 32 System.out.println("MyAspect.around_2"); 33 } catch (Throwable e) { 34 e.printStackTrace(); 35 } 36 } 37 38 public void around_init(ProceedingJoinPoint pjp,String name,int age) { 39 System.out.println(name+" "+age); 40 try { 41 System.out.println("MyAspect.around_1"); 42 Object obj=pjp.proceed(); 43 System.out.println("MyAspect.around_2"); 44 } catch (Throwable e) { 45 e.printStackTrace(); 46 } 47 } 48 }
修改ApsectBiz类(添加init方法):
1 package com.aop.schema; 2 /** 3 * 4 * 业务类 5 * 6 */ 7 public class ApsectBiz { 8 9 public void biz(){ 10 System.out.println("ApsectBiz.biz"); 11 //throw new RuntimeException(); //故意抛出异常 12 } 13 14 public void init(String name,int age){ 15 System.out.println("ApsectBiz.init : "+ name +" " +age); 16 } 17 }
XML配置:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:aop="http://www.springframework.org/schema/aop" 5 xmlns:context="http://www.springframework.org/schema/context" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans-4.1.xsd 8 http://www.springframework.org/schema/context 9 http://www.springframework.org/schema/context/spring-context-4.1.xsd 10 http://www.springframework.org/schema/aop 11 http://www.springframework.org/schema/aop/spring-aop-4.1.xsd"> 12 13 <bean id="myAspect" class="com.aop.schema.MyAspect"></bean> 14 15 <bean id="apsectBiz" class="com.aop.schema.ApsectBiz"></bean> 16 17 <aop:config> 18 <aop:aspect id="myAspectAOP" ref="myAspect"> 19 <!-- 先注释掉,便于观察结果 20 <aop:pointcut id="myPointcut" expression="execution(* com.aop.schema.ApsectBiz.*(..))" /> 21 <aop:before method="before" pointcut-ref="myPointcut"/> 22 <aop:after-returning method="afterreturning" pointcut-ref="myPointcut"/> 23 <aop:after-throwing method="afterthrowing" pointcut-ref="myPointcut"/> 24 <aop:after method="after" pointcut-ref="myPointcut"/> 25 <aop:around method="around" pointcut-ref="myPointcut"/> 26 --> 27 28 <aop:around method="around_init" pointcut="execution(* com.aop.schema.ApsectBiz.init(String,int)) and args(name,age)"/> 29 </aop:aspect> 30 </aop:config> 31 32 </beans>
单元测试:
package com.aop.schema; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class UnitTest { @Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-aop.xml"); ApsectBiz biz = (ApsectBiz)context.getBean("apsectBiz"); biz.init("Json",25); } }
结果:
七月 09, 2015 11:48:42 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@118e0f0f: startup date [Thu Jul 09 23:48:42 CST 2015]; root of context hierarchy 七月 09, 2015 11:48:42 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [spring-aop.xml] Json 25 MyAspect.around_1 ApsectBiz.init : Json 25 MyAspect.around_2