天天看点

Spring AOP之XML配置

1. 配置切面

因为切面Bean可以当成一个普通的SpringBean来配置,所以完全可以为该切面Bean配置依赖注入。当切面Bean定义完成后,通过<aop:aspect…/>元素中使用ref属性来引用该Bean,就可以将该Bean转换成一个切面Bean了。配置<aop:aspect…/>元素时可以指定如下三个属性。

1)        id:定义该切面的标识名

2)        ref:用于将ref属性所引用的普通Bean转换为切面Bean

3)        order:指定该切面Bean的优先级。

如下的配置片段定义了一个切面:

<aop:config>
		<!-- 将fourAdviceBean转换成切面Bean
			切面Bean的新名称为:fourAdviceAspect
			指定该切面的优先级为2 -->
		<aop:aspect id="fourAdviceAspect" ref="fourAdviceBean"
			order="2">
			……..
		</aop:aspect>
	</aop:config>
  <bean id=” fourAdviceAspect” class=”com.owen. fourAdviceAspect”/>
           

2. 配置增强处理

使用XML配置增强处理分别依赖于如下几个元素:

1)        <aop:before…/>:配置Before增强处理

2)        <aop:after…/>:配置After增强处理

3)        <aop:after-returning../>:配置AfterReturning增强

4)        <aop:after-throwing…/>:配置AfterThrowing增强

5)        <aop:around../>配置Around增强处理

上面这些元素都不支持使用子元素,但通常可指定如下的属性:

1)        pointcut:该属性指定一个切入元素表达式,Spring将在匹配表达式的连接点时织入该增强处理。

2)        method:该属性指定一个方法名,指定将切面Bean的该方法转换为增强处理。

3)        pointcut-ref:该属性指定一个已经存在的切点名称,通常pointcut和pointcut-ref两个属性只需使用其中之一。

4)        throwing:该属性只对<after-throwing../>元素有效,用于指定一个形参名,AfterThrowing增强处理方法通过该形参访问目标方法所抛出的异常。

5)        returning:该属性只对<after-returning…/>元素有效,用于指定一个形参名,AfterReturning增强处理方法可通过该形参访问方法的返回值。

3. 例子

1)        下面定义一个简单的切面类。

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增强:执行目标方法之后,模拟结束事务...");
		// 如果rvt的类型是Integer,将rvt改为它的平方
		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());
	}
}
           

2)        除了上面的,再定义一个简单的切面类。

public class SecondAdviceTest
{
	// 定义Before增强处理
	public void authority(String aa)
	{
		System.out.println("目标方法的参数为:" + aa);
		System.out.println("①号Before增强:模拟执行权限检查");
	}
}
           

3)        在Spring配置文件中配置。

<?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-4.0.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
	<aop:config>
		<!-- 将fourAdviceBean转换成切面Bean
			切面Bean的新名称为:fourAdviceAspect
			指定该切面的优先级为2 -->
		<aop:aspect id="fourAdviceAspect" ref="fourAdviceBean"
			order="2">
			<!-- 定义一个After增强处理,
				直接指定切入点表达式
				以切面Bean中的release()方法作为增强处理方法 -->
			<aop:after pointcut="execution(* com.owenapp.service.impl.*.*(..))" 
				method="release"/>
			<!-- 定义一个Before增强处理,
				直接指定切入点表达式
				以切面Bean中的authority()方法作为增强处理方法 -->
			<aop:before pointcut="execution(* com.owenapp.service.impl.*.*(..))" 
				method="authority"/>
			<!-- 定义一个AfterReturning增强处理,
				直接指定切入点表达式
				以切面Bean中的log()方法作为增强处理方法 -->
			<aop:after-returning pointcut="execution(* com.owenapp.service.impl.*.*(..))" 
				method="log" returning="rvt"/>
			<!-- 定义一个Around增强处理,
				直接指定切入点表达式
				以切面Bean中的processTx()方法作为增强处理方法 -->
			<aop:around pointcut="execution(* com.owenapp.service.impl.*.*(..))" 
				method="processTx"/>
		</aop:aspect>

		<!-- 将secondAdviceBean转换成切面Bean
			切面Bean的新名称为:secondAdviceAspect
			指定该切面的优先级为1,该切面里的增强处理将被优先织入 -->
		<aop:aspect id="secondAdviceAspect" ref="secondAdviceBean"
			order="1">
			<!-- 定义一个Before增强处理,
				直接指定切入点表达式
				以切面Bean中的authority()方法作为增强处理方法 
				且该参数必须为String类型(由authority方法声明中msg参数的类型决定) -->
			<aop:before pointcut=
			"execution(* com.owenapp.service.impl.*.*(..)) and args(aa)" 
				method="authority"/>
		</aop:aspect>
	</aop:config>
	<!-- 定义一个普通Bean实例,该Bean实例将被作为Aspect Bean -->
	<bean id="fourAdviceBean"
		class="com.owenapp.aspect.FourAdviceTest"/>
	<!-- 再定义一个普通Bean实例,该Bean实例将被作为Aspect Bean -->
	<bean id="secondAdviceBean"
		class="com.owenapp.aspect.SecondAdviceTest"/>
	<bean id="hello" class="com.owenapp.service.impl.HelloImpl"/>
	<bean id="world" class="com.owenapp.service.impl.WorldImpl"/>
</beans>
           

完成上面的定义后,运行上面的示例程序,将看到使用XML配置文件来管理切面、增强处理的效果。

4. 配置切入点

配置切入点,我们需要配置<aop:pointcut…/>元素,这里需要指定下面的属性:

1)        id:指定该切点的标识名。

2)        exception:指定该切点关联的切入点表达式。

下面笔者定义一个AfterThrowing增强处理,包含该增强处理的切面类如下:

public class RepairAspect
{
	// 定义一个普通方法作为Advice方法
	// 形参ex用于访问目标方法中抛出的异常
	public void doRecoveryActions(Throwable ex)
	{
		System.out.println("目标方法中抛出的异常:" + ex);
		System.out.println("模拟Advice对异常的修复...");
	}
}
           

下面的配置文件将负责配置该Bean实例,并将该Bean实例转换成切面Bean。

<?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-4.0.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
	<aop:config>
		<!-- 定义一个切入点:myPointcut
			通过expression指定它对应的切入点表达式 -->
		<aop:pointcut id="myPointcut" 
			expression="execution(* com.owen.app.service.impl.*.*(..))"/>
		<aop:aspect id="afterThrowingAdviceAspect"
			ref="afterThrowingAdviceBean">
			<!-- 定义一个AfterThrowing增强处理,指定切入点
				以切面Bean中的doRecoveryActions()方法作为增强处理方法 -->
			<aop:after-throwing pointcut-ref="myPointcut" 
				method="doRecoveryActions" throwing="ex"/>
		</aop:aspect>
	</aop:config>
	<!-- 定义一个普通Bean实例,该Bean实例将被作为Aspect Bean -->
	<bean id="afterThrowingAdviceBean"
		class="com.owen.app.aspect.RepairAspect"/>
	<bean id="hello" class="com.owen.app.service.impl.HelloImpl"/>
	<bean id="world" class="com.owen.app.service.impl.WorldImpl"/>
</beans>
           

上面配置了一个myPontcut,这校准其他切面Bean就可多次复用该切点了。上面的配置文件在配置<aop:pointcut../>元素时,使用point-ref引用了一个已有的切入点。