AOP(Aspect Oriented Programing 面向切面編程)
-
通過預(yù)編譯方式和運行期動態(tài)代理實現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)。AOP是OOP的延續(xù),是軟件開發(fā)中的一個熱點,也是Spring框架中的一個重要內(nèi)容,是函數(shù)式編程的一種衍生范型。利用AOP可以對業(yè)務(wù)邏輯的各個部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發(fā)的效率。
-
AOP的三種實現(xiàn)方式
-
采用BeanNameAutoProxyCreator進(jìn)行代理自動創(chuàng)建。
<!--被代理對象(target)--> <bean id="orderServiceBean" class="com.apesource.service.impl.OrderServiceImpl"/> <bean id="userServiceBean" class="com.apesource.service.impl.UserServiceImpl"/> <!--通知(Advice)--> <bean id="logAdviceBean" class="com.apesource.advice.LogAdvice"/> <bean id="performanceAdviceBean" class="com.apesource.advice.PerformanceAdvice"/> <!--切入點(Pointcut):通過正則表達(dá)式描述指定切入點(某些指定方法)--> <bean id="createMethodPointcutBean" class="org.springframework.aop.support.JdkRegexpMethodPointcut"> <!--注入正則表達(dá)式:描述哪些方法為切入點--> <property name="pattern" value=".*create.*"/> </bean> <!--Advisor(高級通知) = Advice(通知) + Pointcut(切入點)--> <bean id="performanceAdvisorBean" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <!--注入切入點--> <property name="pointcut" ref="createMethodPointcutBean"/> <!--注入通知--> <property name="advice" ref="performanceAdviceBean"/> </bean> <!--自動代理創(chuàng)建--> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <!--Bean名稱規(guī)則(數(shù)組):指定哪些bean創(chuàng)建自動代理--> <property name="beanNames"> <list> <value>*ServiceBean</value> <value>*TaskBean</value><!--自己設(shè)置需要自動代理的后綴名--> </list> </property> <!--通知列表:需要執(zhí)行哪些通知--> <property name="interceptorNames"> <list> <value>performanceAdvisorBean</value> <value>logAdviceBean</value> </list> </property> </bean> -
使用AspectJ框架,可任意選擇類來定義通知,在xml中進(jìn)行配置
<!--業(yè)務(wù)組件bean--> <bean id="orderServiceBean" class="com.apesource.service.impl.OrderServiceImpl"/> <!--日志Aspect切面--> <bean id="logAspectBean" class="com.apesource.advice.LogAspect"/> <!--使用Aspect實現(xiàn)切面,使用spring AOP進(jìn)行配置--> <aop:config> <!--配置切面--> <!--注入切面bean--> <aop:aspect ref="logAspectBean"> <!--定義Pointcut:通過expression表達(dá)式,來查找特定的方法(pointcut)--> <aop:pointcut id="serviceMethodPointcut" expression="execution(* com.apesource.service.impl.*.create*(..) )"/> <!--配置"前置通知"--> <!--在pointcut切入點(serviceMethodPointcut)查找到的方法執(zhí)行“前”,執(zhí)行當(dāng)前l(fā)ogAspectBean的doBefore--> <aop:before method="doBefore" pointcut-ref="serviceMethodPointcut"/> <!--配置"后置通知"--> <!--returning屬性:配置當(dāng)前方法中用來接收返回值的參數(shù)名--> <aop:after-returning returning="returnVal" method="afterReturningAdvice" pointcut-ref="serviceMethodPointcut"/> <aop:after method="afterAdvice" pointcut-ref="serviceMethodPointcut"/> <!--配置"異常通知"--> <!--throwing屬性:配置大年方法中用來接收當(dāng)前異常的參數(shù)名--> <aop:after-throwing throwing="ex" method="throwingAdvice" pointcut-ref="serviceMethodPointcut"/> <!--配置環(huán)繞通知--> <aop:around method="aroundAdvice" pointcut-ref="serviceMethodPointcut"/> </aop:aspect> </aop:config> -
使用注解,在xml中配置自動掃描器和AspectJ的自動代理,在自定義需要通知的類或方法前添加注解。
<!--自動掃描器--> <context:component-scan base-package="com.apesource"/> <!--配置AspectJ的自動代理--> <aop:aspectj-autoproxy/>@Aspect @Component public class LogAnotationAspect { private static final String POINTCUT_EXPRESSION = "execution(* com.apesource.service.impl.*.create*(..) )"; /** * 前置通知 */ @Before(POINTCUT_EXPRESSION) public void doBefore(JoinPoint joinPoint){ System.out.println("========【使用AspectJ實現(xiàn)前置通知】開始==========="); System.out.println("目標(biāo)對象:" + joinPoint.getTarget()); System.out.println("目標(biāo)方法:" + joinPoint.getSignature().getName()); System.out.println("參數(shù)列表:" + joinPoint.getArgs()); System.out.println("========【使用AspectJ實現(xiàn)前置通知】結(jié)束==========="); } /** * 后置通知:方法正常執(zhí)行后,有返回值,執(zhí)行該后置通知;如果該方法執(zhí)行出現(xiàn)異常,則不執(zhí)行后置通知 */ @AfterReturning(value = POINTCUT_EXPRESSION,returning = "returnVal") public void afterReturningAdvice(JoinPoint joinPoint,Object returnVal){ System.out.println("========【使用AspectJ實現(xiàn)后置通知】開始==========="); System.out.println("目標(biāo)對象:" + joinPoint.getTarget()); System.out.println("目標(biāo)方法:" + joinPoint.getSignature().getName()); System.out.println("參數(shù)列表:" + joinPoint.getArgs()); System.out.println("返回值:" + returnVal); System.out.println("========【使用AspectJ實現(xiàn)后置通知】結(jié)束==========="); } /** * 后置通知 */ @After(POINTCUT_EXPRESSION) public void afterAdvice(JoinPoint joinPoint){ System.out.println("========【使用AspectJ實現(xiàn)后置通知】開始==========="); System.out.println("目標(biāo)對象:" + joinPoint.getTarget()); System.out.println("目標(biāo)方法:" + joinPoint.getSignature().getName()); System.out.println("參數(shù)列表:" + joinPoint.getArgs()); System.out.println("========【使用AspectJ實現(xiàn)后置通知】結(jié)束==========="); } /** * 異常通知:方法出現(xiàn)異常時,執(zhí)行該通知 * @param joinpoint * @param ex */ @AfterThrowing(value = POINTCUT_EXPRESSION,throwing = "ex") public void throwingAdvice(JoinPoint joinpoint,Exception ex){ System.out.println("==========【使用AspectJ實現(xiàn)異常通知】開始=================="); System.out.println("目標(biāo)對象:" + joinpoint.getTarget()); System.out.println("目標(biāo)方法:" + joinpoint.getSignature().getName()); System.out.println("出現(xiàn)異常:" + ex.getMessage()); System.out.println("==========【使用AspectJ實現(xiàn)異常通知】結(jié)束=================="); } /** * 環(huán)繞通知 */ @Around(POINTCUT_EXPRESSION) public Object aroundAdvice(ProceedingJoinPoint joinpoint) throws Throwable{ System.out.println("#########$環(huán)繞通知的前置部分$###############"); Object returnVal = joinpoint.proceed(); System.out.println("#########$環(huán)繞通知的后置部分$###############"); return returnVal; } }
-