最近在學(xué)習(xí)spring,做了一些關(guān)于Spring AOP的總結(jié)和例子,參考書籍是李剛老師著的《輕量級J2EE企業(yè)應(yīng)用實(shí)戰(zhàn)》。如下:
Spring AOP介紹
Spring的AOP是上面代理模式的深入。使用Spring AOP,開發(fā)者無需實(shí)現(xiàn)業(yè)務(wù)邏輯對象工廠,無需實(shí)現(xiàn)代理工廠,這兩個(gè)工廠都由Spring容器充當(dāng)。Spring AOP不僅允許使用XML文件配置目標(biāo)方法,ProxyHandler也允許使用依賴注入管理,Spring AOP提供了更多靈活的選擇。
在下面Spring AOP的示例中,InvocationHandler采用動(dòng)態(tài)配置,需要增加的方法也采用動(dòng)態(tài)配置,一個(gè)目標(biāo)對象可以有多個(gè)攔截器(類似于代理模式中的代理處理器)。
下面是原始的目標(biāo)對象:
//目標(biāo)對象的接口
public interface Person
{
//該接口聲明了兩個(gè)方法
void info();
void run();
}
下面是原始目標(biāo)對象的實(shí)現(xiàn)類,實(shí)現(xiàn)類的代碼如下:
//目標(biāo)對象的實(shí)現(xiàn)類,實(shí)現(xiàn)類實(shí)現(xiàn)Person接口
public class PersonImpl implements Person
{
//兩個(gè)成員屬性
private String name;
private int age;
//name屬性的 setter方法
public void setName(String name)
{
this.name = name;
}
//age屬性的setter方法
public void setAge(int age)
{
this.age = age;
}
//info方法,該方法僅僅在控制臺打印一行字符串
public void info()
{
System.out.println("我的名字是: " + name + " , 今年年齡為: " + age);
}
//run方法,該方法也在控制臺打印一行字符串。
public void run()
{
if (age < 45)
{
System.out.println("我還年輕,奔跑迅速...");
}
else
{
System.out.println("我年老體弱,只能慢跑...");
}
}
}
該P(yáng)erson實(shí)例將由Spring容器負(fù)責(zé)產(chǎn)生和管理,name屬性和age屬性也采用依賴注入管理。
為了充分展示Spring AOP的功能,此處為Person對象創(chuàng)建三個(gè)攔截器。第一個(gè)攔截器是調(diào)用方法前的攔截器,代碼如下:
//調(diào)用目標(biāo)方法前的攔截器,攔截器實(shí)現(xiàn)MethodBeforeAdvice接口
public class MyBeforeAdvice implements MethodBeforeAdvice
{
//實(shí)現(xiàn)MethodBeforeAdvice接口,必須實(shí)現(xiàn)before方法,該方法將在目標(biāo)
//方法調(diào)用之前,自動(dòng)被調(diào)用。
public void before(Method m, Object[] args, Object target) throws Throwable
{
System.out.println("方法調(diào)用之前...");
System.out.println("下面是方法調(diào)用的信息:");
System.out.println("所執(zhí)行的方法是:" + m);
System.out.println("調(diào)用方法的參數(shù)是:" + args);
System.out.println("目標(biāo)對象是:" + target);
}
}
第二個(gè)攔截器是方法調(diào)用后的攔截器,該攔截器將在方法調(diào)用結(jié)束后自動(dòng)被調(diào)用,攔截器代碼如下:
//調(diào)用目標(biāo)方法后的攔截器,該攔截器實(shí)現(xiàn)AfterReturningAdvice接口
public class MyAfterAdvice implements AfterReturningAdvice
{
//實(shí)現(xiàn)AfterReturningAdvice接口必須實(shí)現(xiàn)afterReturning方法,該方法將在目標(biāo)方法
//調(diào)用結(jié)束后,自動(dòng)被調(diào)用。
public void afterReturning(Object returnValue, Method m, Object[] args, Object target)throws Throwable
{
System.out.println("方法調(diào)用結(jié)束...");
System.out.println("目標(biāo)方法的返回值是 : " + returnValue);
System.out.println("目標(biāo)方法是 : " + m);
System.out.println("目標(biāo)方法的參數(shù)是 : " + args);
System.out.println("目標(biāo)對象是 : " + target);
}
}
第三個(gè)攔截器是是Around攔截器,該攔截器既可以在目標(biāo)方法之前調(diào)用,也可以在目標(biāo)方法調(diào)用之后被調(diào)用。下面是Around攔截器的代碼:
//Around攔截器實(shí)現(xiàn)MethodInterceptor接口
public class MyAroundInterceptor implements MethodInterceptor
{
//實(shí)現(xiàn)MethodInterceptor接口必須實(shí)現(xiàn)invoke方法
public Object invoke(MethodInvocation invocation) throws Throwable
{
//調(diào)用目標(biāo)方法之前執(zhí)行的動(dòng)作
System.out.println("調(diào)用方法之前: invocation對象:[" + invocation + "]");
//調(diào)用目標(biāo)方法
Object rval = invocation.proceed();
//調(diào)用目標(biāo)方法之后執(zhí)行的動(dòng)作
System.out.println("調(diào)用結(jié)束...");
return rval;
}
}
利用Spring AOP框架,實(shí)現(xiàn)之前的代理模式相當(dāng)簡單。只需要實(shí)現(xiàn)對應(yīng)的攔截器即可,無需創(chuàng)建自己的代理工廠,只需采用Spring容器作為代理工廠。下面在Spring配置文件中配置目標(biāo)bean,以及攔截器。
下面是Spring配置文件的代碼:
<?xml version="1.0" encoding="gb2312"?>
<!-- Spring配置文件的文件頭-->
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<!-- Spring配置文件的根元素-->
<beans>
<!-- 配置目標(biāo)對象-->
<bean id="personTarget" class="lee.PersonImpl">
<!-- 為目標(biāo)對象注入name屬性值-->
<property name="name">
<value>Wawa</value>
</property>
<!-- 為目標(biāo)對象注入age屬性值-->
<property name="age">
<value>51</value>
</property>
</bean>
<!-- 第一個(gè)攔截器-->
<bean id="myAdvice" class="lee.MyBeforeAdvice"/>
<!-- 第二個(gè)攔截器-->
<bean id="myAroundInterceptor" class="lee.MyAroundInterceptor"/>
<!-- 將攔截器包裝成Advisor,該對象還確定代理對怎樣的方法增加處理-->
<bean id="runAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!-- advice屬性確定處理bean-->
<property name="advice">
<!-- 此處的處理bean定義采用嵌套bean,也可引用容器的另一個(gè)bean-->
<bean class="lee.MyAfterAdvice"/>
</property>
<!-- patterns確定正則表達(dá)式模式-->
<property name="patterns">
<list>
<!-- 確定正則表達(dá)式列表-->
<value>.*run.*</value>
</list>
</property>
</bean>
<!-- 使用ProxyFactoryBean 產(chǎn)生代理對象-->
<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 代理對象所實(shí)現(xiàn)的接口-->
<property name="proxyInterfaces">
<value>lee.Person</value>
</property>
<!-- 設(shè)置目標(biāo)對象-->
<property name="target">
<ref local="personTarget"/>
</property>
<!-- 代理對象所使用的攔截器-->
<property name="interceptorNames">
<list>
<value>runAdvisor</value>
<value>myAdvice</value>
<value>myAroundInterceptor</value>
</list>
</property>
</bean>
</beans>
該配置文件使用ProxyFactoryBean來生成代理對象,配置ProxyFactoryBean工廠bean時(shí),指定了target屬性,該屬性值就是目標(biāo)對象,該屬性值為personTarget,指定代理的目標(biāo)對象為personTarget。通過interceptorNames屬性確定代理需要的攔截器,攔截器可以是普通的Advice,普通Advice將對目標(biāo)對象的所有方法起作用,攔截器也可以是Advisor,Advisor是Advice和切面的組合,用于確定目標(biāo)對象的哪些方法需要增加處理,以及怎樣的處理。在上面的配置文件中,使用了三個(gè)攔截器,其中myAdvice、myAroundInterceptor都是普通Advice,它們將對目標(biāo)對象的所有方法起作用。而runAdvisor則使用了正則表達(dá)式切面,匹配run方法,即該攔截器只對目標(biāo)對象的run方法起作用。
下面是測試代理的主程序:
public class BeanTest
{
public static void main(String[] args)throws Exception
{
//創(chuàng)建Spring容器
ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");
//獲取代理對象
Person p = (Person)ctx.getBean("person");
//執(zhí)行info方法
p.info();
System.out.println("===========================================");
//執(zhí)行run方法
p.run();
}
}
下面是程序的執(zhí)行結(jié)果:
方法調(diào)用之前...
下面是方法調(diào)用的信息:
所執(zhí)行的方法是:public abstract void lee.Person.info()
調(diào)用方法的參數(shù)是:null
目標(biāo)對象是:lee.PersonImpl@b23210
調(diào)用方法之前: invocation對象:[invocation: method 'info', arguments
[]; target is of class [lee.PersonImpl]]
我的名字是: Wawa , 今年年齡為: 51
調(diào)用結(jié)束...
===========================================
方法調(diào)用之前...
下面是方法調(diào)用的信息:
所執(zhí)行的方法是:public abstract void lee.Person.run()
調(diào)用方法的參數(shù)是:null
目標(biāo)對象是:lee.PersonImpl@b23210
調(diào)用方法之前: invocation對象:[invocation: method 'run', arguments [
]; target is of class [lee.PersonImpl]]
我年老體弱,只能慢跑...
調(diào)用結(jié)束...
方法調(diào)用結(jié)束...
目標(biāo)方法的返回值是 : null
目標(biāo)方法是 : public abstract void lee.Person.run()
目標(biāo)方法的參數(shù)是 : null
目標(biāo)對象是 : lee.PersonImpl@b23210
程序的執(zhí)行結(jié)果中一行“=”用于區(qū)分兩次調(diào)用的方法。在調(diào)用info方法時(shí),只有myAdvice和myAroundInterceptor兩個(gè)攔截器起作用,調(diào)用run方法時(shí)候,三個(gè)攔截器都起作用了。
通過上面的介紹,可看出Spring的AOP框架是對代理模式簡化,并拓展了代理模式的使用。
Spring AOP是Spring聲明式事務(wù)的基礎(chǔ)。了解Spring AOP對深入理解Spring的聲明式事務(wù)管理是非常有好處的。Spring AOP還可以完成很多功能,例如基于AOP的權(quán)限檢查。
posted @ 2007-11-16 14:06 wigalos 閱讀(40108) | 評論 (14) | 編輯 收藏