Spring中的AOP(七)——基于XML配置文件方式的AOP

    除了前面介绍的基于JDK1.5的注解方式来定义切面,切入点和加强处理外,Spring AOP也容许直接使用XML配置文件来管理它们。在JDK1.5以前,只能使用配置文件的方式来管理,在Spring2.X后提供了一个新的aop命名空间来定义切面、切入点和加强处理。java

    相比之下,使用XML配置文件方式有以下优势:
数据库

  • 若是没有使用JDK1.5以上版本,只能使用XML配置文件的方式express

  • 对早期的Spring用于来讲更加习惯,并且这种方式容许使用纯粹的POJO来支持AOPthis

  • 采用XML配置方式时,咱们能够清晰的看到系统中存在哪些切面spa

    同时,XML配置文件的方式也有以下缺点:代理

  • 不能将切面,切入点和加强处理等封装到一个地方。当咱们须要查看切面、切点和加强处理时,必须同时结合Java文件和XML配置文件code

  • XML配置文件方式比@AspectJ方式有更多限制:仅支持“singleton”切面Bean,不能在XML中组合多个命名链接点的声明xml

    除此以外,@AspectJ切面还有一个优势就是能被Spring AOP和AspectJ同时支持,若是有一天咱们须要将应用改成AspectJ来实现AOP,使用@AspectJ将很是容易迁移。
对象

    在Spring的配置文件中,全部的切面、切点和加强处理都必须定义在<aop:config../>元素内部。<beans../>元素能够包含多个<aop:config../>元素,一个<aop:config../>能够包含pointcut、advisor和aspect元素,且这三个元素须要按照此顺序来定义。
事务

    注意:当咱们使用<aop:config../>方式进行配置时,可能与Spring的自动代理方式相互冲突,所以,建议要么所有使用<aop:config../>配置方式,要么所有使用自动代理方式,不要把二者混合使用。


配置切面

    配置<aop:config../>元素时,实质是将已有的Spring Bean转换成切面Bean,因此须要先定义一个普通的Spring Bean。由于切面Bean能够当成一个普通的Spring Bean来配置,因此咱们彻底能够为该切面Bean配置依赖注入。当切面Bean的定义完成后,经过<aop:congig../>元素中是哟个ref属性来引用该Bean,就能够将该Bean转换成切面Bean了。配置<aop:config../>元素时能够指定以下三个属性:

  • id:该切面Bean的标识名

  • ref:指定将要被转换成切面Bean的的普通Bean的id

  • order:指定该切面Bean的优先级,值越小,优先级越高

    以下配置片断定义了一个切面:

<!-- 定义普通的Bean实例 -->
<bean id="afterAdviceBean" class="com.abc.advice.AfterAdviceBean" />
<aop:config>
    <!-- 将容器中的afterAdviceBean转换成切面Bean -->
	<aop:aspect id="afterAdviceAspect" ref="afterAdviceBean">
		...
	</aop:aspect>
</aop:config>

    上面的配置中,将一个AfterAdviceBean类型普通的Bean对象afterAdviceBean转换成了切面Bean对象afterAdviceAspect。


配置加强处理

    与使用@AspectJ彻底同样,使用XML同样能够配置Before、After、AfterReturning、AfterThrowing和Around 5种加强处理,并且彻底支持和@Aspect彻底同样的语义。使用XML配置加强处理分别依赖于以下几个元素:

  • <aop:before../>:配置Before加强处理

  • <aop:after../>:配置After加强处理

  • <aop:after-returning../>:配置AfterReturning加强处理

  • <aop:after-throwing../>:配置AfterThrowing加强处理

  • <aop:around../>:配置Around加强处理

    这些元素都不支持使用子元素,但一般能够指定以下属性:

  • pointcut:指定一个切入点表达式,Spring将在匹配该表达式的链接点织入加强处理

  • pointcut-ref:指定一个已经存在的切入点名称,一般pointcut和pointcut-ref只需使用其中之一

  • method:指定一个方法名,指定切面Bean的该方法做为加强处理

  • throwing:只对<aop:after-throwing../>元素有效,用于指定一个形参名,AfterThrowing加强处理方法,可经过该形参访问目标方法所抛出的异常

  • returning:只对<aop:after-returning../>元素有效,用于指定一个形参名,AfterThrowing加强处理方法,可经过该形参访问目标方法的返回值

    既然选择XML配置文件的方式来管理切面、切点和加强处理,那么切面类里定义切面,切点和加强处理的注解就能够所有删除了。

    定义切点时,XML配置方式和@AspectJ注解方式支持彻底相同的切点指示符,同样能够支持execution、within、args、this、target和bean等切点提示符。另外,XML配置文件方式也和@AspectJ方式同样支持组合切入点表达式,但XML配置方式再也不使用简单的&&、|| 和 ! 做为组合运算符(由于直接在XML文件中须要使用实体引用来表示他们),而是使用以下三个组合运算符:and(至关于&&)、or(至关于||)和not(至关于!)。 下面是一个使用<aop:congig../>的例子,这是把前面的例子中关于切面切点和加强处理的注解去掉后,使用XML配置文件来从新实现这些切面切点的功能:

<bean id="adviceTest" class="com.abc.advice.AdviceTest" />
<aop:config>
    <!-- 注意这里可使用order属性为Aspect指定优先级 -->
    <aop:aspect id="firstAspect" ref="adviceTest" order="2">
    
        <!-- @Before切点 -->
        <aop:before pointcut="execution(* com.abc.service.*.*(..))" 
                method="permissionCheck"/>
                
        <!-- @After切点 -->
        <aop:after pointcut="execution(* com.abc.service.*.*(..))" 
                method="releaseResource"/>
                
        <!-- @AfterReturning切点 -->
        <aop:after-returning pointcut="execution(* com.abc.service.*.*(..))" 
                method="log"/>
                
        <!-- @AfterThrowing切点 -->
        <aop:after-throwing pointcut="execution(* com.abc.service.*.*(..))" 
                method="handleException"/>
                
        <!-- @Around切点(多个切点提示符使用and、or或者not链接) -->
        <aop:around pointcut="execution(* com.abc.service.*.*(..)) and args(name,time,..)" 
                method="process"/>
    </aop:aspect>
</aop:config>

    上面的定义中,特地为firstAspec指定了order=2,代表firstAspect的优先级为2,若是这个XML文件中还有order=1的Aspect,那么这个Aspect将被Spring AOP优先织入。其执行结果,和前面几篇文章中介绍的相同,这里再也不给出。


配置切点

    在Spring中经过<aop:pointcut../>元素来定义切点。当把<aop:pointcut../>元素做为<aop:config../>的子元素时,代表该切点能够被多个切面共享;当把<aop:pointcut../>元素做为<aop:aspect../>的子元素时,代表该切点只能在这个切面内使用。配置<aop:pointcut../>时,一般须要配置以下两个属性:

  • id:指定该切点的标识名

  • expression:指定该切点关联的切点表达式

    以下的配置定义了一个简单的切点:

<aop:pointcut id="point1" expression="execution(* com.abc.service.*.*(..))" />

    另外,若是程序中已经使用注解的方式定义了切点,在<aop:pointcut../>元素中指定切入点表达式时还有另外一种用法,看例子:

<aop:pointcut id="point2" expression="com.abc.service.AdviceTest.myPointcut()" />

    下面的程序中定义了一个AfterThrowing加强处理,包含该加强处理的切面类以下:

package com.abc.advice;

public class AfterThrowingAdviceTest {
    //定义一个普通方法做为加强处理方法,这个方法名将在XML配置文件中指定
    public void doRecoveryAction(Throwable th) {
        System.out.println("目标方法抛出异常:" + th);
        System.out.println("模拟数据库事务恢复");
    }
}

    与前面的切面类彻底相似,该Java类就是一个普通的Java类。下面的配置文件将负责配置该Bean实例,并将该Bean转换成切面Bean:

<bean id="afterThrowingAdviceTest" 
    class="com.abc.advice.AfterThrowingAdviceTest" />
<aop:config>
    <!-- 这个切点将能够被多个<aop:aspect../>使用 -->
    <aop:pointcut id="myPointcut" 
        expression="execution(* com.abc.service.*.*(..))" />
    
    <!-- 这个aspect由上面的Bean afterThrowingAdviceTest转化而来 -->
    <aop:aspect id="aspect1" ref="afterThrowingAdviceTest">
        <!-- 定义一个AfterThrowing加强处理,指定切入点以切面Bean中
            的doRecoverryAction做为加强处理方法 -->
        <aop:after-throwing pointcut-ref="myPointcut" 
            method="doRecoveryAction" throwing="th" />
    </aop:aspect>
</aop:config>

    上面的<aop:pointcut../>元素定义了一个全局的切点myPointcut,这样其余切面Bean就能够屡次复用这个切点了。<aop:after-throwing../>元素中,使用pointcut-ref属性指定了一个已经存在的切点。


    【完】

相关文章
相关标签/搜索