转发:https://www.iteye.com/blog/elim-2396043

7 基于XML配置的Spring AOP

基于XML配置的Spring AOP需要引入AOP配置的Schema,然后我们就可以使用AOP Schema下定义的config、aspect、pointcut等标签进行Spring AOP配置了。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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"> </beans>

基于XML配置的Spring AOP的核心配置是config元素,其它的诸如切面配置、切入点配置等都是配置在它的下面的,所以我们需要先定义一个config元素。

7.1 配置切面

切面的配置是通过aspect元素配置的,我们需要通过其ref属性指定切面类对应的Spring bean的id或name,还可以通过其order属性指定切面类的在拦截的时候的优先级。需要说明的是在使用Spring时基于XML的配置和基于注解的配置往往是可以混用的,所以在下面示例中我们使用的切面类引用不一定非得在Spring的bean配置文件中进行配置。

<bean id="schemaBasedAspect" class="com.elim.spring.aop.aspect.SchemaBasedAspect"/>

<!-- 基于XML的AOP配置是基于config元素开始的 -->
<aop:config>
<!-- 定义切面 -->
<aop:aspect id="aspect1" ref="schemaBasedAspect" order="1">
</aop:aspect>
</aop:config>

7.2 配置切入点

切入点可以是直接配置在config元素下的,意为顶级切入点,也可以是配置在指定的aspect下面的。切入点的配置是通过pointcut元素来配置的,在配置的时候我们需要指定id和expression属性,expression属性就对应的是切入点的表达式,其配置规则跟基于Aspectj注解配置时的规则是一样的。如下示例中就定义了两个pointcut,一个是顶级的,一个是在aspectj1中定义的。需要注意的是顶级的Pointcut必须定义在aspect之前。

<aop:config>
<aop:pointcut expression="bean(userService)" id="userServicePointCut2"/>
<!-- 定义切面 -->
<aop:aspect id="aspect1" ref="schemaBasedAspect" order="1">
<aop:pointcut expression="bean(userService)" id="userServicePointCut"/>
</aop:aspect>
</aop:config>

如果我们的切入点是以Aspectj注解的形式定义在类里面的,我们也可以像在前面介绍的基于Aspectj注解配置那样进行引用,如在下面这个配置就是使用的在SchemaBasedAspect类的pointcut方法上通过@Pointcut指定的表达式。

<aop:pointcut expression="com.elim.spring.aop.aspect.SchemaBasedAspect.pointcut()" id="pointcut"/>

7.3 配置Advice

切面的最终目的是为了拦截指定切入点的方法执行,然后加入自己特定逻辑的,有了切面定义和切入点的定义后,我们需要定义在哪些切入点上需要使用切面的哪些Advice,即执行切面类的哪些方法。我们知道Advice有before、after、after returning、after throwing和around五种,对应的分别是before、after、after-returning、after-throwing和around标签,它们都是定义在aspect标签下的。这五类Advice在定义时的用法基本上是类似的,通过method方法指定Advice对应的是aspect类的哪个方法,然后通过pointcut指定切入点的表达式,或者通过pointcut-ref指定需要引用的是哪个切入点。如下示例中我们就定义了两个Advice,before Advice指定了对应的是切面类的doBefore方法,然后通过pointcut-ref指定需要使用的切入点是id为userServicePointCut的切入点;around Advice指定了对应的是切面类的doAround方法,然后通过pointcut直接指定了需要作用的切入点表达式。

<aop:aspect id="aspect1" ref="schemaBasedAspect" order="1">
<!-- 定义一个Around Advice -->
<aop:before method="doBefore" pointcut-ref="userServicePointCut" />
<aop:around method="doAround" pointcut="bean(userService)"/>
<aop:pointcut expression="bean(userService)" id="userServicePointCut"/>
</aop:aspect>

和基于注解的配置类似,如果我们需要在afterReturning Advice中访问返回值,我们也可以给对应的处理方法一个返回值对应类型(或Object类型)的参数,然后通过after-returning元素的returning属性指定返回值需要赋予给Advice处理方法的哪个参数,参数名需要一致。同样afterThrowing类型的Advice需要在处理方法中接收抛出的异常时,也可以给定对应的处理方法一个Exception类型的参数,然后通过after-throwing元素的throwing属性指定抛出的异常需要赋值给Advice处理方法的哪个参数。

<aop:after-returning method="doAfterReturning" pointcut-ref="pointcut" returning="returnValue"/>
<aop:after-throwing method="doAfterThrowing" pointcut-ref="pointcut" throwing="ex"/>

参数传递也是类似的,在Advice处理方法上给定指定的参数,然后在定义Pointcut表达式的时候加上对应的参数传递限制,如“args(id)”、“this(userService)”等,在需要指定参数的绑定顺序时,可以通过before、around等Advice标签的arg-names属性指定。如下示例中我们就要求id为userServicePointCut的Pointcut需要接收一个参数,这个参数是需要跟对应的Advice处理方法绑定的,而before Advice是使用该Pointcut的,所以就要求id与对应的处理方法参数绑定,而且对应的方法参数名需要是id。

<aop:aspect id="aspect1" ref="schemaBasedAspect" order="1">
<aop:before method="doBefore" pointcut-ref="userServicePointCut"/>
<aop:around method="doAround" pointcut="bean(userService)" />
<aop:pointcut expression="bean(userService) &amp;&amp; args(id)" id="userServicePointCut"/>
</aop:aspect>

我们对应的doBefore处理方法是这样的。

public void doBefore(int id) {
System.out.println("======================doBefore======================" + id);
}

在上面的示例中在定义id为userServicePointcut的表达式的时候用到了“&&”,这是因为在XML中&是特殊字符,我们必须对它进行转义。其实在XML中配置Pointcut表达式时我们可以使用“and”、“or”和“not”替代“&&”、“||”和“!”。

7.4 declare-parents

在基于注解的形式定义AOP时,我们有一个@DeclareParents注解可以给所有匹配的bean生成的代理默认加上指定的接口实现,并使用默认的实现。如果是基于XML配置时如果想达到对应的效果我们可以通过declare-parents元素来达到对应的效果。示例如下,切面类SchemaBasedAspect有一个doBefore方法接收一个CommonParent参数,我们在配置切面时配置了一个before Advice将调用切面类的doBefore方法;通过declare-parents元素指定service包下面所有的类都实现CommonParent接口,底层在调用的时候将会调用CommonParentImpl的实现。CommonParent接口的源码没有提供,其只定义了一个返回类型为void的doSomething()方法。然后我们的before Advice将拦截id为userService的bean的所有方法调用,注意因为我们声明了所有的Service都将实现CommonParent接口,所以生成的id为userService的bean其实也是实现了CommonParent接口的,在调用的doBefore方法时传递的就是id为userService的bean,我们在doBefore方法中又继续调用CommonParent的doSomething方法就相当于重新调用了id为userService的bean的方法,会造成before Advice循环拦截和调用。很显然此种情况下,我们是不希望CommonParent的方法调用还被拦截的,所以我们在对应的Pointcut表达式上把CommonParent的doSomething方法排除了。在应用注解的时候不用排除也不会循环调用,但是使用XML配置时必须排除。

public void doBefore(CommonParent commonParent) {
System.out.println("======================doBefore======================");
commonParent.doSomething();
}
<bean id="schemaBasedAspect" class="com.elim.spring.aop.aspect.SchemaBasedAspect" />
<bean id="commonParent" class="com.elim.spring.aop.service.CommonParentImpl" />
<!-- 基于XML的AOP配置是基于config元素开始的 -->
<aop:config>
<aop:aspect id="aspect1" ref="schemaBasedAspect" order="1">
<aop:before method="doBefore" pointcut-ref="userServicePointCut" />
<aop:pointcut expression="bean(userService) and this(commonParent) and !execution(void com.elim.spring.aop.service.CommonParent.doSomething())"
id="userServicePointCut" />
<!-- 加上通用的父类 -->
<aop:declare-parents types-matching="com.elim.spring.aop.service..*"
implement-interface="com.elim.spring.aop.service.CommonParent"
delegate-ref="commonParent"/>
</aop:aspect>
</aop:config>

7.5 启用CGLIB代理类

默认情况下当bean实现了接口时Spring AOP是基于JDK的动态代理的,也就是说我们生成的bean只能调用接口中定义的方法,如果我们的bean是没有实现接口的,则会采用CGLIB代理。如果我们希望不管bean是否实现了接口都采用CGLIB代理,则在基于Aspectj注解进行AOP配置时,我们可以通过aspectj-autoproxy元素的proxy-target-class=”true”启用CGLIB代理。

<aop:aspectj-autoproxy proxy-target-class="true" />

如果是基于XML的配置时,我们也希望强制使用CGLIB代理时怎么办呢?我们可以在config元素上配置proxy-target-class=”true”。

<aop:config proxy-target-class="true">
</aop:config>

(注:本文是基于Spring4.1.0所写,Elim写于2017年1月23日星期一)

Spring Aop(七)——基于XML配置的Spring Aop的更多相关文章

  1. 一步一步深入spring(6)--使用基于XML配置的spring实现的AOP

    上节我们提到了使用基于注解实现的AOP,这节我们将用基于xml配置的方式来实现的AOP. 1.首先建立一个类,作为切面类,这个类主要用来实现注解中各种通知要实现的方法. package com.yan ...

  2. 基于XML配置的spring aop增强配置和使用

    在我的另一篇文章中(http://www.cnblogs.com/anivia/p/5687346.html),通过一个例子介绍了基于注解配置spring增强的方式,那么这篇文章,只是简单的说明,如何 ...

  3. Spring 基于xml配置方式的AOP

    我们具体用代码来说明: 1.ArithmeticCalculator.java package com.proc; public interface ArithmeticCalculator { in ...

  4. Spring 基于xml配置方式的AOP(8)

    1.ArithmeticCalculator.java 1 package com.proc; 2 3 public interface ArithmeticCalculator { 4 int ad ...

  5. 【原】Spring和Dubbo基于XML配置整合过程

    背景 随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进. 单一应用架构 当网站流量很小时,只需一个 ...

  6. 基于XML配置的Spring MVC 简单的HelloWorld实例应用

    1.1 问题 使用Spring Web MVC构建helloworld Web应用案例. 1.2 方案 解决本案例的方案如下: 1. 创建Web工程,导入Spring Web MVC相关开发包. Sp ...

  7. 基于XML配置的Sping AOP详解

    一.编写基本处理方法 package com.kang.sping.xml.aop; public class Math{ //加 public int add(int n1,int n2){ int ...

  8. spring实战六之使用基于java配置的Spring

    之前接触的都是基于XML配置的Spring,Spring3.0开始可以几乎不使用XML而使用纯粹的java代码来配置Spring应用.使用基于java配置的Spring的步骤如下: 1. 创建基于ja ...

  9. Spring学习之旅(七)基于XML配置与基于AspectJ注解配置的AOP编程比较

    本篇博文用一个稍复杂点的案例来对比一下基于XML配置与基于AspectJ注解配置的AOP编程的不同. 相关引入包等Spring  AOP编程准备,请参考小编的其他博文,这里不再赘述. 案例要求: 写一 ...

随机推荐

  1. Java&Selenium自动化测试调用JS实现单击

    Java&Selenium自动化测试调用JS实现单击 /* * the method of invoking js to do something * * @author davieyang ...

  2. PHP基础知识 - 字符串处理函数

    addcslashes — 为字符串里面的部分字符添加反斜线转义字符 addslashes — 用指定的方式对字符串里面的字符进行转义 bin2hex — 将二进制数据转换成十六进制表示 chop — ...

  3. linux上构建ftp服务器

    linux上构建ftp服务器 服务器搭建 https://help.aliyun.com/knowledge_detail/60152.html,可以参考这篇博文. 配置文件详解 进入/etc/vsf ...

  4. django安装好之后,django-admin仍然不能使用的问题

    我使用的是python3,python3不能找到django的正确位置.需要下面这样才能正确建立mysite python3 /usr/lib/python2./site-packages/djang ...

  5. unittest简单使用的介绍

    无论是paython+request接口测试.ui自动化测试等,都常会用到unittest的框架,简单的介绍如下:

  6. 这些Winforms界面开发技巧你还没学会?OUT了

    DevExpress Winforms Controls内置140多个UI控件和库,完美构建流畅.美观且易于使用的应用程序.无论是Office风格的界面,还是分析处理大批量的业务数据,DevExpre ...

  7. 利用tycho插件自动生成pom文件

    mvn org.eclipse.tycho:tycho-pomgenerator-plugin:generate-poms -DgroupId=com.vogella.tychoexample com ...

  8. 004——转载C#禁止改变窗体大小

    原文链接:http://www.cnblogs.com/shaozhuyong/p/5545005.html 1.先把MaximizeBox和MinimumBox设置为false,这时你发现最大最小化 ...

  9. myeclipse打开jsp后死掉,或变卡的问题

    很多小伙伴在myeclipse下打开jsp会特别卡,甚至会卡死掉,我也遇到过很多次这种情况,下面分享一下解决方法: 1,打开 Window -> Preferences -> Genera ...

  10. Comet OJ - Contest #3 (A 比赛 加强版)二分答案

    考试的时候同届神犇 JZYshurak 出了一个  n=$10^5$ 的数据加强版. 刚开始没什么思路,但是忽然想到这个可以转成二分判定+暴力枚举的模型. 二分 ans, 使得大于等于 ans 的值小 ...