Dashboard > OpenSource Project > ... > Spring > 入門 41 - 第一個Spring AOP程式
OpenSource Project Log In   View a printable version of the current page.
入門 41 - 第一個Spring AOP程式
Added by cheetah, last edited by cheetah on Apr 09, 2005  (view change)
Labels: 
(None)

  來使用Spring的AOP框架來重新撰寫之前「從代理機制初探AOP」主題中的程式,首先,Spring AOP預設使用動態代理來實作AOP,動態代理必須宣告被代理物件的介面:

 代碼:

IHello.java
package onlyfun.caterpillar; 

public interface IHello { 
    public void hello(String name); 
    public void morning(String name); 
}

  實作IHello介面的HelloSpeaker則如下:

 代碼:

HelloSpeaker.java
package onlyfun.caterpillar; 

public class HelloSpeaker implements IHello { 
    public void hello(String name) { 
        System.out.println("Hello, " + name); 
    } 

    public void morning(String name) { 
        System.out.println("Morning, " + name); 
    } 
}

  我們希望在方法執行前後進行記錄的動作,在AOP中這需要Around類型的Advice,通常的,實作Around類型的策略是使用Interceptor。

  Interceptor的一個例子是Servlet中的Filter機制,在Filter機制下,當請求來臨時,會被Filter先攔截並進行處理,之後傳給下一個Filter,最後才是真正處理請求的Servlet。實作AOP時所使用的Interceptor策略與Filter類似,所不同的是Filter被綁定於Servlet API,且只適用於請求階段。

  您可以將一連串的Interceptor想成是堆疊結構,在Spring中,在真正執行某個方法前,會先插入Interceptor,每個Interceptor會執行自己的處理,然後再執行proceed,這將執行流程轉給下一個Interceptor,如果沒有下一個Interceptor了,就執行真正呼叫的方法,方法執行過後,再一層一層返回Interceptor堆疊,最後離開堆疊,如下圖,流程先是紅色,方法執行後的流程是藍色:

 代碼:

<-- --> interceptor1 <-- --> interceptor2 <-- --> ..... <-- --> Invoked method

  Spring在實作Interceptor時,是實作org.aopalliance.intercept.MethodInterceptor,AOP Alliance(http://www.sourceforge.net/projects/aopalliance)的目標是制定AOP功能的標準介面,目前只提供一部份的子集合,子集包括了Interceptor,Spring實作MethodInterceptor,以求將來Interceptor的可移植性。

  我們實作LogInterceptor如下:

 代碼:

LogInterceptor.java
package onlyfun.caterpillar; 

import org.aopalliance.intercept.MethodInterceptor; 
import org.aopalliance.intercept.MethodInvocation; 
import java.util.logging.*; 

public class LogInterceptor implements MethodInterceptor { 
    private Logger logger = Logger.getLogger(this.getClass().getName()); 
    
   public Object invoke(MethodInvocation methodInvocation) throws Throwable { 
        logger.log(Level.INFO, "method starts..." + methodInvocation.getMethod()); 
        try { 
          Object result = methodInvocation.proceed(); 
          return result; 
        } 
        finally { 
            logger.log(Level.INFO, "method ends..." + methodInvocation.getMethod() + "\n"); 
        }        
   } 
}

  invoke()中的MethodInvocation參數包括了下一個Interceptor的資訊、被執行的方法、以及方法所需的參數,其返回值是被呼叫方法的返回值。

  我們還需要一個代理物件,這可以使用org.springframework.aop.framework.ProxyFactoryBean,它需要知道代理的介面與物件,以及所要介入的Interceptor,如下:

 代碼:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd"> 
<beans> 
    <bean id="logInterceptor" class="onlyfun.caterpillar.LogInterceptor"/> 

    <bean id="helloSpeaker" class="onlyfun.caterpillar.HelloSpeaker"/> 
    
    <bean id="helloProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> 
        <property name="proxyInterfaces"> 
            <value>onlyfun.caterpillar.IHello</value> 
        </property> 
        <property name="target"> 
            <ref bean="helloSpeaker"/> 
        </property> 
        <property name="interceptorNames"> 
            <list> 
                <value>logInterceptor</value> 
            </list> 
        </property> 
    </bean> 
</beans>

  Interceptor執行的順序是interceptorNames中設定的順序,最後是target目標物件,使用下面的程式來測試一下:

 代碼:

SpringTest.java
package onlyfun.caterpillar; 

import org.springframework.context.*; 
import org.springframework.context.support.*; 

public class SpringTest { 
   public static void main(String[] args) { 
        ApplicationContext context = new FileSystemXmlApplicationContext("bean.xml"); 
        IHello helloProxy = (IHello) context.getBean("helloProxy"); 
        helloProxy.hello("Justin"); 
        helloProxy.morning("momor"); 
    } 
}

  執行結果如下:

 代碼:

2004/11/26 上午 11:59:09 onlyfun.caterpillar.LogInterceptor invoke 
資訊: method starts...public abstract void onlyfun.caterpillar.IHello.hello(java.lang.String) 
Hello, Justin 
2004/11/26 上午 11:59:09 onlyfun.caterpillar.LogInterceptor invoke 
資訊: method ends...public abstract void onlyfun.caterpillar.IHello.hello(java.lang.String) 

2004/11/26 上午 11:59:09 onlyfun.caterpillar.LogInterceptor invoke 
資訊: method starts...public abstract void onlyfun.caterpillar.IHello.morning(java.lang.String) 
Morning, momor 
2004/11/26 上午 11:59:09 onlyfun.caterpillar.LogInterceptor invoke 
資訊: method ends...public abstract void onlyfun.caterpillar.IHello.morning(java.lang.String)

  完成了第一個Spring AOP程式了,不過這當中還有許多細節可以說明,下一個主題再繼續。

Site powered by a free Open Source Project / Non-profit License (more) of Confluence - the Enterprise wiki.
Learn more or evaluate Confluence for your organisation.
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.1.5a Build:#411 Mar 16, 2006) - Bug/feature request - Contact Administrators