豆沙包

…… …… 所学 所写 所想 所做 所悟…… ……

应用Java Dynamic Proxy 实现类方法的拦截(AOP)

Java Dynamic Proxy 可以对类的指定方法实现拦截,但要求此类要实现某个Interface,拦截的方法出自此Interfacle。基于此,我们可以实现简单的AOP,要完成方法的拦截,只需要一个InvocationHandler,这个InvocationHandler即是拦截逻辑所在,实现了对目标object指定方法的筛选及调用。

比如我们现有一对Interface/Implemention:Speakable/Translater。
Speakable接口指明了可以sayEnglish(),sayChinese()。我们目前的translater实现了这两个方法。现在我们在此基础上,增加对translater的方法的logging功能。

在以前,我们可以:

1.直接改写原代码,增加logging功能。(ugly)
2.增加一个LoggingTranlater实现Speakable,采用delegation(Design Pattern),对方法进行增强。对此类proxy可以参考jive,其中遍布proxy 。缺点就是每一个要增加的类都要实现一个代理类,可以想象,代码量急剧膨胀。

现在让我们来看看Java Dynamic Proxy是如何达到这一点的,声明我给出的代理是示例性的,比较简陋,主要是给出一个实现方法,加以改进,即可形成一个比较通用的工具。

先来看看我们的Interface/Implemention对:

package reflection.example;

public interface Speakable {
    
void sayEnglish();

    
void sayChinese();
}


package reflection.example;

public class Translater implements Speakable {

    
public void sayEnglish() {
        System.
out.println("Hello,i am robbie");

    }


    
public void sayChinese() {
        System.
out.println("你好,我是饺子");

    }


}


现在我们要进行logging功能了,记住,我们只需提供一个InvocationHandler:

package reflection.example;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class LoggingInvoktionHandler implements InvocationHandler {
    
private Object target = null;

    
public LoggingInvoktionHandler(Object target) {
        
this.target = target;
    }


    
public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable 
{
        logging(method);
        
return method.invoke(target, args);
    }


    
private void logging(Method method) {
        
if ("sayChinese".equals(method.getName())) {
            System.
out.println("翻译开始");
        }


        
if ("sayEnglish".equals(method.getName())) {
            System.
out.println("Tranlation beginning");
        }

    }


}


这个LoggingInvocationHandler实现了InvocationHandler接中。方法的代理调用在invoke(……)中,可以如我添加logging()功能一样,加入其它的任何想要的功能,然后再进行 real target的方法调用。

如果将logging(Method method)中的逻辑抽出来,放到外部文件(XML)中进行配置读取。再对方法名采用正则表达式。是不是更为通用了呢?

下面是客户端调用:

package reflection.example;

import java.lang.reflect.Proxy;

public class Main {

    
/**
     * @param args
     
*/

    
public static void main(String[] args) {
        Speakable speaker 
= new Translater();

        Speakable loggingSpeaker 
= (Speakable) Proxy.newProxyInstance(
                speaker.getClass().getClassLoader(),
                
new Class[] { Speakable.class },
                
new LoggingInvoktionHandler(speaker));

        loggingSpeaker.sayChinese();
        loggingSpeaker.sayEnglish();
    }

}



是不是非常简单呢?:)

如果到此为止,还是看不出Dynamic在哪儿的,想想我这儿给出的示例与spring的AOP的不同,呵呵,区别在于我这儿给出的Main亦是spring AOP的一部分,在spring里, 对某个Interface的target的代理,采用了Reflection,以达到普遍适用的,不用象我这样直接显式地给出类名而已。若我把Main做成一个Helper类,同时,把配置接口及他的实现类都放到外部XML中配置,是不是就有点象一个超级简化的spring AOP了?

当然spring不是完全用Java Dynamic Proxy的,因为Java Dynamic Proxy的前提——针对接口编程!,针对普通的类的AOP,Spring采用了字节码增强来实现。


posted on 2005-03-04 10:37 carob 阅读(2588) 评论(0)  编辑  收藏 所属分类: Reflection


只有注册用户登录后才能发表评论。


网站导航: