`

征服Spring AOP—— Schema

阅读更多
自从开始使用Spring,就接触到AOP,但一直未能深入,沉淀一段时间后,开始全面整理!
这里针对一个接口中各个方法做为切面,通过Hello接口实现的例子来诠释Spring AOP 2.0 的特性。


相关内容:
征服Spring AOP—— Schema
征服Spring AOP—— @AspectJ


定义一个接口Hello,定义可触发BeforeAdvice、AfterAdvice、AroundAdvice、ThrowsAdvice、Introduction的方法。
Hello接口
public interface Hello {

	/**
	 * 前置增强
	 */
	void sayHelloBefore();

	/**
	 * 后置增强
	 */
	void sayHelloAfter();

	/**
	 * 后置返回增强
	 * 
	 * @return 
	 */
	String sayHelloAfterReturning();

	/**
	 * 环绕增强
	 */
	void sayHelloAround();

	/**
	 * 介入增强
	 */
	void sayHelloIntroduction();

	/**
	 * 异常抛出增强
	 */
	void sayHelloThrows();
}

针对Hello接口做具体实现,注意sayHelloThrows方法实现中,刻意抛出异常,用于触发ThrowsAdvice。
SayHello类,对Hello做具体实现。
public class SayHello implements Hello {
	/*
	 * (non-Javadoc)
	 * 
	 * @see org.zlex.aop.Hello#sayHelloBefore()
	 */
	public void sayHelloBefore() {
		System.out.println("Say Hello Before!");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.zlex.aop.Hello#sayHelloAfter()
	 */
	public void sayHelloAfter() {
		System.out.println("Say Hello After!");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.zlex.aop.Hello#sayHelloAfterRunning()
	 */
	@Override
	public String sayHelloAfterReturning() {
		System.out.println("Say Hello After Returning!");
		// 返回值
		return "Hello";
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.zlex.aop.Hello#sayHelloAround()
	 */
	public void sayHelloAround() {
		System.out.println("Say Hello Around!");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.zlex.aop.Hello#sayHelloAfterThrowing()
	 */
	@Override
	public void sayHelloAfterThrowing() {
		System.out.println("Say Hello Throws!");
		// 强制抛出异常,触发AfterThrowingAdvice
		throw new RuntimeException("Hello Excetion");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.zlex.aop.Hello#sayHelloIntroduction()
	 */
	public void sayHelloIntroduction() {
		System.out.println("Say Hello Introduction!");
	}

}


先来个测试代码:
public class AllTest {
	private ApplicationContext app;
	private Hello hello;

	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void before() throws Exception {
		app = new ClassPathXmlApplicationContext("applicationContext.xml");
		hello = (Hello) app.getBean("hello");
	}

	@Test
	public void testBefore() {
		System.out.println("=====Before Advice Begin=====");
		hello.sayHelloBefore();
		System.out.println("=====Before Advice End=====");
	}

	@Test
	public void testAfter() {
		System.out.println("=====After Advice Begin=====");
		hello.sayHelloAfter();
		System.out.println("=====After Advice End=====");
	}

	@Test
	public void testAfterReturning() {
		System.out.println("=====After Returning Advice Begin=====");
		String value = hello.sayHelloAfterReturning();
		// AfterReturning获得返回值,但不修改值内容!
		assertEquals("Hello", value);
		System.out.println("=====After Returning Advice End=====");
	}

	@Test
	public void testAround() {
		System.out.println("=====Around Advice Begin=====");
		hello.sayHelloAround();
		System.out.println("=====Around Advice End=====");
	}

	@Test
	public void testAfterThrowing() {
		System.out.println("=====After Throwing Advice Begin=====");
		try {
			hello.sayHelloAfterThrowing();
		} catch (Exception e) {
			assertNotNull(e);
		}
		System.out.println("=====After Throwing Advice End=====");
	}

	@Test
	public final void testIntroduction() {
		System.out.println("=====Introduction Begin=====");
		// 由于对Hello接口进行了引入,使得实现了Hello接口的类可以具备Ok接口的功能
		hello.sayHelloIntroduction();
		((Ok) hello).sayOk();
		System.out.println("=====Introduction End=====");
	}

}


Spring配置:
	<bean
		id="hello"
		class="org.zlex.aop.SayHello" />
	<bean
		id="advice"
		class="org.zlex.aop.Advice" />


这里的org.zlex.aop.Advice用于各个Advice的具体实现,以下是该类中各个方法的诠释。

对上述SayHello类的方法做具体Advice实现:
BeforeAdvice
	/**
	 * Before
	 * 
	 * @param joinPoint
	 */
	public void before(JoinPoint joinPoint) {
		System.out.println("Before: " + joinPoint.getSignature().getName());
	}


Spring配置:
	<!-- before -->
	<aop:config>
		<aop:pointcut
			id="beforePoint"
			expression="execution(* org.zlex.aop.Hello.sayHelloBefore(..))" />
		<aop:aspect
			id="beforeAspect"
			ref="advice"
		>
			<aop:before
				method="before"
				pointcut-ref="beforePoint" />
		</aop:aspect>
	</aop:config>


控制台输出:
引用

=====Before Advice Begin=====
Before: sayHelloBefore
Say Hello Before!
=====Before Advice End=====

BeforeAdvice在sayHelloBefore方法执行前调用Before类的invoke方法。

AfterAdvice
	public void after(JoinPoint joinPoint) {
		System.out.println("After: " + joinPoint.getSignature().getName());
	}

Spring配置:
	<!-- after -->
	<aop:config>
		<aop:pointcut
			id="afterPoint"
			expression="execution(* org.zlex.aop.Hello.sayHelloAfter(..))" />
		<aop:aspect
			id="afterAspect"
			ref="advice"
		>
			<aop:after
				method="after"
				pointcut-ref="afterPoint" />
		</aop:aspect>
	</aop:config>


控制台输出:
引用

=====After Advice Begin=====
Say Hello After!
After: sayHelloAfter
=====After Advice End=====

BeforeAdvice和AfterAdvice在实现上没有差异,其差别只是触发时机而已。

AfterAdvice只是在目标方法执行后触发,但无法获得目标方法的返回值,对于这点可以通过AfterReturningAdvice增强实现。

AfterReturningAdvice
	public void afterReturning(JoinPoint joinPoint, String retVal) {
		// 返回值参数名称(retVal)必须与XML配置文件中的'returning="retVal"'保持一致
		System.out.println("After: " + joinPoint.getSignature().getName());
		System.out.println("Return Value: " + retVal);
	}

Spring配置:
	<!-- afterReturning -->
	<aop:config>
		<aop:pointcut
			id="afterReturningPoint"
			expression="execution(* org.zlex.aop.Hello.sayHelloAfterReturning(..))" />
		<aop:aspect
			id="afterAspect"
			ref="advice"
		>
			<aop:after-returning
				method="after"
				pointcut-ref="afterReturningPoint"
				returning="retVal"
			/>
		</aop:aspect>
	</aop:config>


控制台输出:
引用

=====After Returning Advice Begin=====
Say Hello After Returning!
After: sayHelloAfterReturning
Return Value: Hello
=====After Returning Advice End=====


AroundAdvice
	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println("Around: " + joinPoint.getSignature().getName());
		System.out.println("Before");
		Object obj = joinPoint.proceed();
		System.out.println("End");
		return obj;
	}


Spring配置:
	<!-- around -->
	<aop:config>
		<aop:pointcut
			id="aroundPoint"
			expression="execution(* org.zlex.aop.Hello.sayHelloAround(..))" />
		<aop:aspect
			id="aroundAspect"
			ref="advice"
		>
			<aop:around
				method="around"
				pointcut-ref="aroundPoint" />
		</aop:aspect>
	</aop:config>


控制台输出:
引用

=====Around Advice Begin=====
Around: sayHelloAround
Before
Say Hello Around!
End
=====Around Advice End=====

AroundAdvice是BeforeAdvice和AfterAdvice的综合体。可以,在方法触发前、后分别进行操作。

如果方法执行过程中产生异常,就需要ThrowsAdvice。
AfterThrowingAdvice
	public void afterThrowing(JoinPoint joinPoint, Exception e) {
		// 异常参数名称(e)必须与XML配置文件中的'throwing="e"'保持一致
		System.out.println("AfterThrowing: "
				+ joinPoint.getSignature().getName());
		System.out.println("Exception Message: " + e.getMessage());
	}


Spring配置:
	<!-- afterThrowing -->
	<aop:config>
		<aop:pointcut
			id="afterThrowingPoint"
			expression="execution(* org.zlex.aop.Hello.sayHelloAfterThrowing(..))" />
		<aop:aspect
			id="afterThrowingAspect"
			ref="advice"
		>
			<aop:after-throwing
				method="afterThrowing"
				pointcut-ref="afterThrowingPoint"
				throwing="e"
			/>
		</aop:aspect>
	</aop:config>

控制台输出:
引用

=====After Throwing Advice Begin=====
Say Hello Throws!
AfterThrowing: sayHelloAfterThrowing
Exception Message: Hello Exception
=====After Throwing Advice End=====


AfterThrowingAdvice是Spring事务处理的核心触发环节。当事务提交产生异常时,将直接触发AfterThrowingAdvice,产生数据库回滚等动作。

除了上述常规增强实现外,还可以通过IntroductionInterceptor构建一个原本不存在的实现。
Introduction
	public Object introduction(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out
				.println("Introduction: " + joinPoint.getSignature().getName());
		return joinPoint.proceed();
	}


Introduction 可以对一个类的代码在不做任何修改(非入侵式),而使得该类拥有另一套方法,或者说具备另一套本领。
现在,我们就让这个实现了Hello接口的SayHello类拥有Ok接口的实现。
Ok接口,使得Hello接口的所有实现类都绑定这个接口:
public interface Ok {
	void sayOk();
}

IntroductionOk用于实现Ok接口,使得Hello接口实现类都具有sayOk的本领:
public class IntroductionOk implements Ok {
 
	@Override
	public void sayOk() {
		System.out.println("Ok!");
	}
}


Spring配置:
	<!-- introduction -->
	<!-- .*+是用于包下的,不是用于接口 +定义目标为该接口的所有实现类 -->
	<bean
		id="ok"
		class="org.zlex.aop.IntroductionOk" />
	<aop:config>
		<aop:aspect ref="advice">
			<aop:pointcut
				id="introductionPoint"
				expression="execution(* org.zlex.aop.Hello.sayHelloIntroduction(..))" />
			<aop:declare-parents
				implement-interface="org.zlex.aop.Ok"
				types-matching="org.zlex.aop.Hello+"
				delegate-ref="ok" />
			<aop:around
				method="introduction"
				pointcut-ref="introductionPoint" />
		</aop:aspect>
	</aop:config>



控制台输出:
引用

=====Introduction Advice Begin=====
Introduction: sayHelloIntroduction
Say Hello Introduction!
Ok!
=====Introduction Advice End=====

同样是Hello接口,在执行了sayHelloIntroduction方法时被拦截,同时输出say Hello introduction!,此时还可以执行Ok的方法输出Ok!。显然,Hello的实现类多了Ok接口的本领。

关于表达式符号:
引用
.*+定义目标为包下的所有类
+定义目标为该接口的所有实现类




Spring Beans 结构图如下:



代码详见附件!



相关内容:
征服Spring AOP—— Schema
征服Spring AOP—— @AspectJ

  • 大小: 224.6 KB
6
0
分享到:
评论
1 楼 1314520ln 2009-05-12  
写的很清晰,多谢分享~

相关推荐

    征服Spring AOP—— @AspectJ

    在IT行业中,Spring框架是Java企业级应用开发的首选,而Spring AOP(面向切面编程)则是其核心特性之一,用于实现横切关注...通过学习和实践,你将能更好地掌握这一强大的工具,从而在你的IT职业生涯中征服Spring AOP。

    Spring aop 基于schema的AOP支持及JoinPoint的使用、如何使用CGLIB代理

    **Spring AOP 基于Schema的AOP支持** 在Spring框架中,AOP(面向切面编程)是一种强大的设计模式,它允许我们定义横切关注点,如日志、事务管理等,这些关注点可以独立于业务逻辑进行管理。Spring AOP提供了基于XML...

    spring aop jar 包

    Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的重要组成部分,它提供了一种在不修改源代码的情况下,对程序进行功能增强的技术。这个"spring aop jar 包"包含了实现这一功能所需的类和接口,...

    死磕Spring之AOP篇 - Spring AOP两种代理对象的拦截处理(csdn)————程序.pdf

    Spring AOP 是一种面向切面编程的技术,它允许我们在不修改源代码的情况下,对应用程序的特定部分(如方法调用)进行增强。在 Spring 中,AOP 的实现主要依赖于代理模式,有两种代理方式:JDK 动态代理和 CGLIB 动态...

    五、Spring源码分析——Spring Aop

    《Spring AOP 源码分析》 在深入探讨Spring AOP之前,我们先要理解AOP(面向切面编程)的基本概念。AOP是一种编程范式,它将关注点分离,使得我们可以将横切关注点(如日志、事务管理、安全检查等)与业务逻辑解耦...

    Spring Aop Schema实现

    本篇文章将深入探讨Spring AOP的Schema实现,即基于XML配置的方式来理解和应用AOP。 一、Spring AOP基础概念 1. 切面(Aspect):切面是关注点的模块化,例如日志、事务管理。在Spring AOP中,切面由通知(Advice...

    Spring AOP 16道面试题及答案.docx

    Spring AOP,全称为Aspect Oriented Programming,是面向切面编程的一种编程范式,它是对传统的面向对象编程(OOP)的一种补充。在OOP中,核心是对象,而在AOP中,核心则是切面。切面是关注点的模块化,即程序中的...

    简单spring aop 例子

    Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来处理系统中的交叉关注点问题,如日志、事务管理、安全性等。本示例将简要介绍如何在Spring应用中实现AOP,通过实际的...

    spring aop依赖jar包

    现在,我们回到主题——"springaop依赖的jar包"。在Spring 2.5.6版本中,使用Spring AOP通常需要以下核心jar包: - `spring-aop.jar`:这是Spring AOP的核心库,包含了AOP相关的类和接口。 - `spring-beans.jar`:...

    Spring AOP之基于Schema配置总结与案例

    **Spring AOP:基于Schema配置的总结与案例** 在Java企业级开发中,Spring框架以其强大的功能和灵活性深受开发者喜爱。其中,Spring AOP(面向切面编程)是解决横切关注点问题的一个重要工具,它允许我们把业务逻辑...

    Spring AOP完整例子

    Spring AOP(面向切面编程)是Spring框架的核心特性之一,它允许开发者在不修改源代码的情况下,通过插入切面来增强或改变程序的行为。在本教程中,我们将深入探讨Spring AOP的不同使用方法,包括定义切点、通知类型...

    spring-aop.jar各个版本

    spring-aop-1.1.1.jar spring-aop-1.2.6.jar spring-aop-1.2.9.jar spring-aop-2.0.2.jar spring-aop-2.0.6.jar spring-aop-2.0.7.jar spring-aop-2.0.8.jar spring-aop-2.0.jar spring-aop-2.5.1.jar spring-aop-...

    Spring AOP面向方面编程原理:AOP概念

    ### Spring AOP面向方面编程原理:AOP概念详解 #### 一、引言 随着软件系统的日益复杂,传统的面向对象编程(OOP)逐渐暴露出难以应对某些横切关注点(cross-cutting concerns)的问题。为了解决这一挑战,面向方面编程...

    spring aop 自定义注解保存操作日志到mysql数据库 源码

    一、适合人群 1、具备一定Java编程基础,初级开发者 2、对springboot,mybatis,mysql有基本认识 3、对spring aop认识模糊的,不清楚如何实现Java 自定义注解的 ...4、spring boot,mybatis,druid,spring aop的使用

    Spring AOP实现机制

    **Spring AOP 实现机制详解** Spring AOP(面向切面编程)是Spring框架的核心特性之一,它允许程序员在不修改源代码的情况下,通过“切面”来插入额外的业务逻辑,如日志、事务管理等。AOP的引入极大地提高了代码的...

    基于注解实现SpringAop

    基于注解实现SpringAop基于注解实现SpringAop基于注解实现SpringAop

    Spring 入门案例——AOP

    Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来实现横切关注点,如日志、事务管理、性能监控等。本入门案例将帮助你理解并掌握Spring AOP的基本概念和使用方法。 在...

    spring AOP依赖三个jar包

    Spring AOP,即Spring的面向切面编程模块,是Spring框架的重要组成部分,它允许开发者在不修改源代码的情况下,对程序进行横切关注点的处理,如日志、事务管理等。实现这一功能,主要依赖于三个核心的jar包:aop...

    Spring AOP依赖jar包

    http://www.springframework.org/schema/aop/spring-aop.xsd"&gt; &lt;!-- 启用 AOP --&gt; &lt;aop:config&gt; &lt;aop:aspect id="loggingAspect" ref="loggingService"&gt; &lt;!-- 定义切入点 --&gt; &lt;aop:pointcut id=...

Global site tag (gtag.js) - Google Analytics