8.4.6 基于XML配置文件的管理方式 2. 配置增强处理
与使用@AspectJ
完全一样,使用XML
一样可以配置Before
、After
、 AfterReturning
、 AfterThrowing
和Around
五种增强处理,而且完全支持和@AspectJ
完全一样的语义。
使用XML
配置增强处理分别依赖于如下几个元素。
XML 元素 |
描述 |
<aop:before> |
配置 Before 增强处理。 |
<aop:after> |
配置Afer 增强处理。 |
<aop:after-returning> |
配置AfterReturning 增强处理。 |
<aop:after-throwing> |
配置AfterThrowing 增强处理 |
<aop:around> |
配置 Around 增强处理。 |
上面这些元素都不支持使用子元素,但通常可指定如下属性。
属性 |
描述 |
pointcut或者pointcut-ref |
pointcut 属性指定一个切入表达式, pointcut-ref 属性指定已有的切入点名称, Spring 将在匹配该表达式的连接点时织入该增强处理。通常pointcut 和pointcut-ref 两个属性只需使用其中之一。 |
method |
该属性指定一个方法名,指定将切面Bean 的该方法转换为增强处理。 |
throwing |
该属性只对<after-throwing> 元素有效,用于指定一个形参名, AfteThrowing 增强处理方法可通过该形参访问目标方法所抛出的异常。 |
returning |
该属性只对< after-returning …>元素有效,用于指定一个形参名, Afterreturning 增强处理方法可通过该形参访问目标方法的返回值 |
既然应用选择使用XML
配置方式来配置增强处理,所以切面类里定义切面、切入点和增强处理的注解全都可删除了。
XML配置方式中的切入点指示符
当定义切入点表达式时,XML
配置方式和@AspectJ
注解方式支持完全相同的切入点指示符,一样可以支持execution
、 within
、args
、 this
、target
和bean
等切入点指示符。
XML配置方式中的组合运算符
XML
配置方式和@AspectJ
注解方式一样支持组合切入点表达式,但XML
配置方式不再使用简单的&&
、‖
和!
作为组合运算符(因为直接在XML
文件中需要使用实体引用来表示它们),而是使用如下三个组合运算符:and
(相当于&&
)、or
(相当于‖
)和not
(相当于!
)。
程序示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| E:\workspace_QingLiangJiJavaEEQiYeYingYongShiZhang5\XML-config └─src\ ├─beans.xml ├─lee\ │ └─BeanTest.java └─org\ └─crazyit\ └─app\ ├─aspect\ │ ├─FourAdviceTest.java │ └─SecondAdviceTest.java └─service\ ├─Hello.java ├─impl\ │ ├─HelloImpl.java │ └─WorldImpl.java └─World.java
|
下面的程序定义了一个简单的切面类,该切面类只是将前面@Aspect
示例中切面类的全部注解删除后的结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| package org.crazyit.app.aspect;
import org.aspectj.lang.*; import java.util.Arrays;
public class FourAdviceTest { public Object processTx(ProceedingJoinPoint jp) throws java.lang.Throwable { System.out.println("Around增强:执行目标方法之前,模拟开始事务..."); Object[] args = jp.getArgs(); if (args != null && args.length > 0 && args[0].getClass() == String.class) { args[0] = "【增加的前缀】" + args[0]; } Object rvt = jp.proceed(args); System.out.println("Around增强:执行目标方法之后,模拟结束事务..."); if (rvt != null && rvt instanceof Integer) rvt = (Integer) rvt * (Integer) rvt; return rvt; } public void authority(JoinPoint jp) { System.out.println("②Before增强:模拟执行权限检查"); System.out.println( "②Before增强:被织入增强处理的目标方法为:" + jp.getSignature().getName()); System.out .println("②Before增强:目标方法的参数为:" + Arrays.toString(jp.getArgs())); System.out.println("②Before增强:被织入增强处理的目标对象为:" + jp.getTarget()); } public void log(JoinPoint jp, Object rvt) { System.out.println("AfterReturning增强:获取目标方法返回值:" + rvt); System.out.println("AfterReturning增强:模拟记录日志功能..."); System.out.println("AfterReturning增强:被织入增强处理的目标方法为:" + jp.getSignature().getName()); System.out.println( "AfterReturning增强:目标方法的参数为:" + Arrays.toString(jp.getArgs())); System.out.println("AfterReturning增强:被织入增强处理的目标对象为:" + jp.getTarget()); } public void release(JoinPoint jp) { System.out.println("After增强:模拟方法结束后的释放资源..."); System.out.println( "After增强:被织入增强处理的目标方法为:" + jp.getSignature().getName()); System.out.println("After增强:目标方法的参数为:" + Arrays.toString(jp.getArgs())); System.out.println("After增强:被织入增强处理的目标对象为:" + jp.getTarget()); } }
|
上面的FourAdviceTest.java
几乎是一个POJO
类,该Java
类的4个方法的第一个参数都是JoinPoint
类型,之所以将4个方法的第一个参数定义为JoinPoint
类型,是为了访问连接点的相关信息,当然Spring AOP
只支持使用方法执行作为连接点,所以这里使用JoinPoint
只是为了获取目标方法的方法名、参数值等信息。
除此之外,本示例程序中还定义了如下一个简单的切面类。
1 2 3 4 5 6 7 8 9 10 11
| package org.crazyit.app.aspect;
public class SecondAdviceTest { public void authority(String aa) { System.out.println("①号Before增强:模拟执行权限检查"); System.out.println("目标方法的第一个参数为:" + aa); } }
|
上面切面类的authority
方法里多了一个String aa
的形参,则应用试图通过aa
这个形参来访间目标方法的参数值,这需要在配置该切面Bean
时使用args
切入点指示符。
本应用中的Spring
配置文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| <?xml version="1.0" encoding="GBK"?> <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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="fourAdviceBean" class="org.crazyit.app.aspect.FourAdviceTest" /> <bean id="secondAdviceBean" class="org.crazyit.app.aspect.SecondAdviceTest" /> <bean id="hello" class="org.crazyit.app.service.impl.HelloImpl" /> <bean id="world" class="org.crazyit.app.service.impl.WorldImpl" /> <aop:config> <aop:aspect id="fourAdviceAspect" ref="fourAdviceBean" order="2"> <aop:after pointcut="execution(* org.crazyit.app.service.impl.*.*(..))" method="release" /> <aop:before pointcut="execution(* org.crazyit.app.service.impl.*.*(..))" method="authority" /> <aop:after-returning pointcut="execution(* org.crazyit.app.service.impl.*.*(..))" method="log" returning="rvt" /> <aop:around pointcut="execution(* org.crazyit.app.service.impl.*.*(..))" method="processTx" /> </aop:aspect> <aop:aspect id="secondAdviceAspect" ref="secondAdviceBean" order="1">
<aop:before pointcut="execution(* org.crazyit.app.service.impl.*.*(..)) and args(aa,..)" method="authority" /> </aop:aspect> </aop:config> </beans>
|
上面的配置文件中依次配置了fourAdviceBean
、 secondAdviceBean
、 hello
、world
这4个Bean
,它们没有丝毫特别之处,完全可以像管理普通Bean
一样管理它们。
上面配置文件中的aop:config
元素中的代码用于将fourAdviceBean
转换成一个切面Bean
,并将该Bean
里包含的4个方法转换成4个增强处理。
- 当配置
fourAdviceAspect
切面时,为其指定了order="2"
,这将意味着该切面里的增强处理的织入顺序为2
;
- 而配置
secondAdviceAspect
切面时,为其指定了order="1"
,
- 所以
Spring AOP
将优先织入secondAdviceAspect
里的增强处理,再织入fourAdviceAspect
里的增强处理。