举例讲解Java的Spring框架中AOP程序设计方式的使用
1、什么是AOP
AOP是AspectOrientedProgramming的缩写,意思是面向方面编程,AOP实际是GoF设计模式的延续。
2、关于SpringAOP的一些术语:
A、切面(Aspect):在SpringAOP中,切面可以使用通用类或者在普通类中以@Aspect注解(@AspectJ风格)来实现
B、连接点(Joinpoint):在SpringAOP中一个连接点代表一个方法的执行
C、通知(Advice):在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括"around"、"before”和"after"等通知。许多AOP框架,包括Spring,都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链
D、切入点(Pointcut):定义出一个或一组方法,当执行这些方法时可产生通知,Spring缺省使用AspectJ切入点语法。
3、通知类型
A、前置通知(@Before):在某连接点(joinpoint)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)
B、返回后通知(@AfterReturning):在某连接点(joinpoint)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回
C、抛出异常后通知(@AfterThrowing):方法抛出异常退出时执行的通知
D、后通知(@After):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)
E、环绕通知(@Around):包围一个连接点(joinpoint)的通知,如方法调用。这是最强大的一种通知类型,环绕通知可以在方法调用前后完成自定义的行为,它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行
4、@AspectJ风格的AOP配置
SpringAOP配置有两种风格:
A、XML风格=采用声明形式实现SpringAOP
B、AspectJ风格=采用注解形式实现SpringAOP
5、实例
切面类TestAspect
packagecom.spring.aop; /** *切面 */ publicclassTestAspect{ publicvoiddoAfter(JoinPointjp){ System.out.println("logEndingmethod:" +jp.getTarget().getClass().getName()+"." +jp.getSignature().getName()); } publicObjectdoAround(ProceedingJoinPointpjp)throwsThrowable{ longtime=System.currentTimeMillis(); ObjectretVal=pjp.proceed(); time=System.currentTimeMillis()-time; System.out.println("processtime:"+time+"ms"); returnretVal; } publicvoiddoBefore(JoinPointjp){ System.out.println("logBeginingmethod:" +jp.getTarget().getClass().getName()+"." +jp.getSignature().getName()); } publicvoiddoThrowing(JoinPointjp,Throwableex){ System.out.println("method"+jp.getTarget().getClass().getName() +"."+jp.getSignature().getName()+"throwexception"); System.out.println(ex.getMessage()); } privatevoidsendEx(Stringex){ //TODO发送短信或邮件提醒 } }
packagecom.spring.service; /** *接口A */ publicinterfaceAService{ publicvoidfooA(String_msg); publicvoidbarA(); }
packagecom.spring.service; /** *接口A的实现类 */ publicclassAServiceImplimplementsAService{ publicvoidbarA(){ System.out.println("AServiceImpl.barA()"); } publicvoidfooA(String_msg){ System.out.println("AServiceImpl.fooA(msg:"+_msg+")"); } }
packagecom.spring.service; /** *Service类B */ publicclassBServiceImpl{ publicvoidbarB(String_msg,int_type){ System.out.println("BServiceImpl.barB(msg:"+_msg+"type:"+_type+")"); if(_type==1) thrownewIllegalArgumentException("测试异常"); } publicvoidfooB(){ System.out.println("BServiceImpl.fooB()"); } }
ApplicationContext
<?xmlversion="1.0"encoding="UTF-8"?> <beansxmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd" default-autowire="autodetect"> <aop:config> <aop:aspectid="TestAspect"ref="aspectBean"> <!--配置com.spring.service包下所有类或接口的所有方法--> <aop:pointcutid="businessService" expression="execution(*com.spring.service.*.*(..))"/> <aop:beforepointcut-ref="businessService"method="doBefore"/> <aop:afterpointcut-ref="businessService"method="doAfter"/> <aop:aroundpointcut-ref="businessService"method="doAround"/> <aop:after-throwingpointcut-ref="businessService"method="doThrowing"throwing="ex"/> </aop:aspect> </aop:config> <beanid="aspectBean"class="com.spring.aop.TestAspect"/> <beanid="aService"class="com.spring.service.AServiceImpl"></bean> <beanid="bService"class="com.spring.service.BServiceImpl"></bean> </beans>
测试类AOPTest
publicclassAOPTestextendsAbstractDependencyInjectionSpringContextTests{ privateAServiceaService; privateBServiceImplbService; protectedString[]getConfigLocations(){ String[]configs=newString[]{"/applicationContext.xml"}; returnconfigs; } /** *测试正常调用 */ publicvoidtestCall() { System.out.println("SpringTestJUnittest"); aService.fooA("JUnittestfooA"); aService.barA(); bService.fooB(); bService.barB("JUnittestbarB",0); } /** *测试After-Throwing */ publicvoidtestThrow() { try{ bService.barB("JUnitcallbarB",1); }catch(IllegalArgumentExceptione){ } } publicvoidsetAService(AServiceservice){ aService=service; } publicvoidsetBService(BServiceImplservice){ bService=service; } }
运行结果如下:
logBeginingmethod:com.spring.service.AServiceImpl.fooA AServiceImpl.fooA(msg:JUnittestfooA) logEndingmethod:com.spring.service.AServiceImpl.fooA processtime:0ms logBeginingmethod:com.spring.service.AServiceImpl.barA AServiceImpl.barA() logEndingmethod:com.spring.service.AServiceImpl.barA processtime:0ms logBeginingmethod:com.spring.service.BServiceImpl.fooB BServiceImpl.fooB() logEndingmethod:com.spring.service.BServiceImpl.fooB processtime:0ms logBeginingmethod:com.spring.service.BServiceImpl.barB BServiceImpl.barB(msg:JUnittestbarBtype:0) logEndingmethod:com.spring.service.BServiceImpl.barB processtime:0ms logBeginingmethod:com.spring.service.BServiceImpl.barB BServiceImpl.barB(msg:JUnitcallbarBtype:1) logEndingmethod:com.spring.service.BServiceImpl.barB methodcom.spring.service.BServiceImpl.barBthrowexception 测试异常