自从开始使用Spring,就接触到AOP,但一直未能深入,沉淀一段时间后,开始全面整理! :D
这里针对一个接口中各个方法做为切面,通过Hello接口实现的例子来诠释Spring AOP 2.0 的特性。
[b]
相关内容:
[url=http://snowolf.iteye.com/blog/236264]征服Spring AOP—— Schema[/url]
[url=http://snowolf.iteye.com/blog/1481442]征服Spring AOP—— @AspectJ[/url]
[/b]
定义一个接口Hello,定义可触发BeforeAdvice、AfterAdvice、AroundAdvice、ThrowsAdvice、Introduction的方法。
Hello接口
针对Hello接口做具体实现,注意sayHelloThrows方法实现中,刻意抛出异常,用于触发ThrowsAdvice。
SayHello类,对Hello做具体实现。
先来个测试代码:
Spring配置:
这里的[b]org.zlex.aop.Advice[/b]用于各个Advice的具体实现,以下是该类中各个方法的诠释。
对上述SayHello类的方法做具体Advice实现:
BeforeAdvice
Spring配置:
控制台输出:
[quote]
=====Before Advice Begin=====
Before: sayHelloBefore
Say Hello Before!
=====Before Advice End=====
[/quote]
BeforeAdvice在sayHelloBefore方法执行前调用Before类的invoke方法。
AfterAdvice
Spring配置:
控制台输出:
[quote]
=====After Advice Begin=====
Say Hello After!
After: sayHelloAfter
=====After Advice End=====
[/quote]
BeforeAdvice和AfterAdvice在实现上没有差异,其差别只是触发时机而已。
AfterAdvice只是在目标方法执行后触发,但无法获得目标方法的返回值,对于这点可以通过AfterReturningAdvice增强实现。
AfterReturningAdvice
Spring配置:
控制台输出:
[quote]
=====After Returning Advice Begin=====
Say Hello After Returning!
After: sayHelloAfterReturning
Return Value: Hello
=====After Returning Advice End=====
[/quote]
AroundAdvice
Spring配置:
控制台输出:
[quote]
=====Around Advice Begin=====
Around: sayHelloAround
Before
Say Hello Around!
End
=====Around Advice End=====
[/quote]
AroundAdvice是BeforeAdvice和AfterAdvice的综合体。可以,在方法触发前、后分别进行操作。
如果方法执行过程中产生异常,就需要ThrowsAdvice。
AfterThrowingAdvice
Spring配置:
控制台输出:
[quote]
=====After Throwing Advice Begin=====
Say Hello Throws!
AfterThrowing: sayHelloAfterThrowing
Exception Message: Hello Exception
=====After Throwing Advice End=====
[/quote]
AfterThrowingAdvice是Spring事务处理的核心触发环节。当事务提交产生异常时,将直接触发AfterThrowingAdvice,产生数据库回滚等动作。
除了上述常规增强实现外,还可以通过IntroductionInterceptor构建一个原本不存在的实现。
Introduction
Introduction 可以对一个类的代码在不做任何修改(非入侵式),而使得该类拥有另一套方法,或者说具备另一套本领。
现在,我们就让这个实现了Hello接口的SayHello类拥有Ok接口的实现。
Ok接口,使得Hello接口的所有实现类都绑定这个接口:
IntroductionOk用于实现Ok接口,使得Hello接口实现类都具有sayOk的本领:
Spring配置:
控制台输出:
[quote]
=====Introduction Advice Begin=====
Introduction: sayHelloIntroduction
Say Hello Introduction!
Ok!
=====Introduction Advice End=====
[/quote]
同样是Hello接口,在执行了sayHelloIntroduction方法时被拦截,同时输出[i]say Hello introduction![/i],此时还可以执行Ok的方法输出[i]Ok![/i]。显然,Hello的实现类多了Ok接口的本领。
关于表达式符号:
[quote].*+定义目标为包下的所有类
+定义目标为该接口的所有实现类[/quote]
Spring Beans 结构图如下:
[img]http://dl.iteye.com/upload/attachment/0066/2781/1e1a64ae-c080-3f1d-a438-78c5c6e7557e.jpg[/img]
代码详见附件! :D
[b]
相关内容:
[url=http://snowolf.iteye.com/blog/236264]征服Spring AOP—— Schema[/url]
[url=http://snowolf.iteye.com/blog/1481442]征服Spring AOP—— @AspectJ[/url]
[/b]
这里针对一个接口中各个方法做为切面,通过Hello接口实现的例子来诠释Spring AOP 2.0 的特性。
[b]
相关内容:
[url=http://snowolf.iteye.com/blog/236264]征服Spring AOP—— Schema[/url]
[url=http://snowolf.iteye.com/blog/1481442]征服Spring AOP—— @AspectJ[/url]
[/b]
定义一个接口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" />
这里的[b]org.zlex.aop.Advice[/b]用于各个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>
控制台输出:
[quote]
=====Before Advice Begin=====
Before: sayHelloBefore
Say Hello Before!
=====Before Advice End=====
[/quote]
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>
控制台输出:
[quote]
=====After Advice Begin=====
Say Hello After!
After: sayHelloAfter
=====After Advice End=====
[/quote]
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>
控制台输出:
[quote]
=====After Returning Advice Begin=====
Say Hello After Returning!
After: sayHelloAfterReturning
Return Value: Hello
=====After Returning Advice End=====
[/quote]
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>
控制台输出:
[quote]
=====Around Advice Begin=====
Around: sayHelloAround
Before
Say Hello Around!
End
=====Around Advice End=====
[/quote]
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>
控制台输出:
[quote]
=====After Throwing Advice Begin=====
Say Hello Throws!
AfterThrowing: sayHelloAfterThrowing
Exception Message: Hello Exception
=====After Throwing Advice End=====
[/quote]
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>
控制台输出:
[quote]
=====Introduction Advice Begin=====
Introduction: sayHelloIntroduction
Say Hello Introduction!
Ok!
=====Introduction Advice End=====
[/quote]
同样是Hello接口,在执行了sayHelloIntroduction方法时被拦截,同时输出[i]say Hello introduction![/i],此时还可以执行Ok的方法输出[i]Ok![/i]。显然,Hello的实现类多了Ok接口的本领。
关于表达式符号:
[quote].*+定义目标为包下的所有类
+定义目标为该接口的所有实现类[/quote]
Spring Beans 结构图如下:
[img]http://dl.iteye.com/upload/attachment/0066/2781/1e1a64ae-c080-3f1d-a438-78c5c6e7557e.jpg[/img]
代码详见附件! :D
[b]
相关内容:
[url=http://snowolf.iteye.com/blog/236264]征服Spring AOP—— Schema[/url]
[url=http://snowolf.iteye.com/blog/1481442]征服Spring AOP—— @AspectJ[/url]
[/b]