Java 里通过动态代理来实现 PHP 里的魔术方法 __call

梦康 2015-12-02 00:00:00 592

要在 Java 里实现这一功能的原因是因为我想在本地调用一个不存在的方法的时候触发调用远程服务器上的一个方法。而直接调用不存在的方法肯定是编译不通过的,所以记录了这篇学习笔记。

关键字Java 动态代理,下面是一个简单实现

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

/**
 * Created by zhoumengkang on 5/12/15.
 */

/**
 * 点赞的积分服务接口
 */
interface RewardScoreService{
    String support(int uid,int feedId);
}

public class SupportService {

    public static void main(String[] args) {
        add(1,2);
    }

    /**
     * uid 给 feedId 点赞
     * @param uid
     * @param feedId
     * @return
     */
    public static String add(int uid, int feedId){
        YarClient yarClient = new YarClient();
        RewardScoreService rewardScoreService = (RewardScoreService) yarClient.proxy(RewardScoreService.class);
        return rewardScoreService.support(uid, feedId);
    }

}

class YarClient {

    public final Object proxy(Class type) {
        YarClientInvocationHandler handler = new YarClientInvocationHandler();
        return Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, handler);
    }
}

final class YarClientInvocationHandler implements InvocationHandler {

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("这里的动态调用实现了 php 的 __call 方法");

        System.out.println("method : " + method.getName());
        for (int i = 0; i < args.length; i++) {
            System.out.println("args["+ i +"] : " + args[i]);
        }
        
        return null;
    }
}

编译输出结果

这里的动态调用实现了 php 的 __call 方法
method : support
args[0] : 1
args[1] : 2

这样就实现了 java 的动态代理,而实际上面的RewardScoreServicesupport的方法并没有被实现,但我们却实际调用了该support方法。

使用场景:

例如在 RPC 中,该方法就是在本地不存在,通过在动态代理绑定的handler里面的invoke方法里通过 method 的值和各个参数的值,做网络请求,把请求的结果拿回到本地使用。

参考链接 

http://stackoverflow.com/questions/2050470/php-call-equivalent-for-java

http://www.cnblogs.com/xiaoluo501395377/p/3383130.html