欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring与AOP之AspectJ基于XML的实现

程序员文章站 2022-07-12 14:14:14
...

AspectJ 除了提供了基于注解的 AOP 的实现外,还提供了以 XML 方式的实现。切面就是一个 POJO 类,而用于增强的方法就是普通的方法。通过配置文件,将切面中的功能增强织入到了目标类的目标方法中。

实现步骤

(1) 定义业务接口与实现类

//主业务接口
public interface ISomeService {
	//主业务方法
	void doFirst();
	//主业务方法
	String doSecond();
	//主业务方法
	void doThird();

}
//目标类
public class SomeServiceImpl implements ISomeService {

	//目标方法
	@Override
	public void doFirst() {
		System.out.println("执行doFirst()方法");
	}

	//目标方法
	@Override
	public String doSecond() {
		System.out.println("执行doSecond()方法");
		return "abcde";
	}

	//目标方法
	@Override
	public void doThird() {
		System.out.println("执行doThird()方法" + 3 / 0);
		System.out.println("执行doThird()方法");
	}

}

(2) 定义切面 POJO 类

该类为一个 POJO 类,将作为切面出现。其中定义了若干普通方法,将作为不同的通知方法。

// 表示当前类为切面
public class MyAspectJ {
	
	//前置通知
	public void myBefore() {
		System.out.println("执行前置通知方法");
	}
	
//	@Before("execution(* *..ISomeService.doFirst(..))")
	public void myBefore(JoinPoint jp) {
		System.out.println("执行前置通知方法 jp = " + jp);
	}
	
	//后置通知
	public void myAfterReturning() {
		System.out.println("执行后置通知方法");
	}
	
	public void myAfterReturning(Object result) {
		System.out.println("执行后置通知方法 result = " + result);
	}
	
	//环绕通知
	public Object myAround(ProceedingJoinPoint pjp) throws Throwable{
		System.out.println("执行环绕通知方法,目标方法执行之前");
		
		//执行目标方法
		Object result = pjp.proceed();
		System.out.println("执行环绕通知方法,目标方法执行之后");
		if (result != null) {
			result = ((String)result).toUpperCase();
		}
		return result;
	}
	
	//异常通知
	public void myAfetrThrowing() {
		System.out.println("执行异常通知方法");
	}
	
	//使用切入点,叫 doThirdPointcut()
	public void myAfterThrowing(Exception ex) {
		System.out.println("执行异常通知方法 ex = " + ex.getMessage());
	}
	
	//最终通知
	public void myAfter() {
		System.out.println("执行最终通知方法");
	}
	
	
}

(3) 注册目标对象与 POJO 切面类

<!-- 注册切面 -->
<bean id="myAspectJ" class="com.huang.xml.MyAspectJ"/>
	
<!-- 注册目标对象 -->
<bean id="someService" class="com.huang.xml.SomeServiceImpl"/>

(4) 在容器中定义 AOP 配置

<!-- AOP配置 -->
	<aop:config>
	    
	    <aop:aspect ref="myAspectJ">
	    <aop:pointcut expression="execution(* *..ISomeService.doFirst(..))" id="doFirstPointcut"/>
	    <aop:pointcut expression="execution(* *..ISomeService.doSecond(..))" id="doSecondPointcut"/>
	    <aop:pointcut expression="execution(* *..ISomeService.doThird(..))" id="doThirdPointcut"/>

	    </aop:aspect>
	</aop:config>

通过其子标签<aop:pointcut/>定义切入点,该标签有两个属性, id 与 expression。分别用于指定该切入点的名称及切入点的值。 expression 的值为 execution 表达式。

子标签<aop:aspect/>定义具体的织入规则:根据不同的通知类型,确定不同的织入时间;将 method 指定的增强方法,按照指定织入时间,织入到切入点指定的目标方法中。

<aop:aspect/>的 ref 属性用于指定使用哪个切面。<aop:aspect/>的子标签是各种不同的通知类型。不同的通知所包含的属性是不同的,但也有共同的属性。

  • method:指定该通知使用的切面中的增强方法。
  • pointcut-ref:指定该通知要应用的切入点。

AspectJ 的 6 种通知的 XML 标签如下:

  • <aop:before/>:前置通知
  • lt;aop:after-returning/>: 后置通知
  • <aop:around/>:环绕通知
  • <aop:after-throwing/>:异常通知
  • <aop:after/>:最终通知
  • <aop:declare-parents/>:引入通知

(5) 定义测试类

	@Test
	public void test01() {
		String resource = "com/huang/xml/applicationContext.xml";
		ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
		//serviceProxy为代理对象,而非目标对象
		ISomeService service = (ISomeService) ac.getBean("someService");  
		service.doFirst();
		System.out.println("----------------------");
		service.doSecond();
		System.out.println("----------------------");
		service.doThird();
	}

<aop:before/>前置通知

<!-- 前置通知 -->
<aop:before method="myBefore" pointcut-ref="doFirstPointcut"/>
<aop:before method="myBefore(org.aspectj.lang.JoinPoint)" pointcut-ref="doFirstPointcut"/>

运行结果

Spring与AOP之AspectJ基于XML的实现

<aop:after-returning/>后置通知

其 XML 的配置中,有一个属性 returning,指定用于接收目标方法的返回值所使用的变量名。其可作为增强方法的参数出现。

<!-- 后置通知 -->
<aop:after-returning method="myAfterReturning" pointcut-ref="doSecondPointcut"/>
<aop:after-returning method="myAfterReturning(java.lang.Object)" pointcut-ref="doSecondPointcut" returning="result"/>

运行结果

Spring与AOP之AspectJ基于XML的实现

<aop:around/>环绕通知

环绕通知的增强方法一般返回类型为 Object,是目标方法的返回值。并且可以包含一个参数 ProceedingJoinPoint,其方法 proceed()可执行目标方法。

<!-- 环绕通知 -->
<aop:around method="myAround" pointcut-ref="doSecondPointcut"/>

运行结果

Spring与AOP之AspectJ基于XML的实现

<aop:after-throwing/>异常通知

其 XML 的配置中,有一个属性 throwing,指定用于接收目标方法所抛出异常的变量名。其可作为增强方法的参数出现,该参数为 Throwable 类型。

<!-- 异常通知 -->
<aop:after-throwing method="myAfterThrowing(java.lang.Exception)" pointcut-ref="doThirdPointcut" throwing="ex"/>

运行结果

Spring与AOP之AspectJ基于XML的实现

<aop:after/>最终通知

<!-- 最终通知 -->
<aop:after method="myAfter" pointcut-ref="doThirdPointcut"/>

运行结果

Spring与AOP之AspectJ基于XML的实现