先来一个InvocationHandler示例,InvocationHandler类的作用是:对原始对象的方法做一个拦截。

package com.zhang;

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

interface HelloSerivce {
    void sayHello();
    void sayHi();
}

interface FuckService {
    void fuck();
}

class HelloServiceImpl implements HelloSerivce {
    @Override
    public void sayHello() {
        System.out.println("hello zhang");
    }

    @Override
    public void sayHi() {
        System.out.println("hi zhang");
    }
} 

public class InvocationHandler_Test {
    public static void main(String[] args) {
        class MyInvocationHandler implements InvocationHandler {
            private Object obj;
            public MyInvocationHandler(Object obj) {
                this.obj = obj;
            }
            
            //拦截方法
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                if ("sayHello".equals(method.getName())) {
                    System.out.println("拦截sayHello");
                } else if("sayHi".equals(method.getName())) {
                    System.out.println("拦截sayHi");
                }
                //调用原始方法
                method.invoke(obj, args);  
                return null;
            }
            
            @Override
            public String toString() {
                return "MyInvocationHandler:" + System.currentTimeMillis();
            }
        } 
    
        HelloSerivce helloSerivceImpl = new HelloServiceImpl();
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(helloSerivceImpl);
        //生成代理
        Class<?>[] src = HelloServiceImpl.class.getInterfaces();
        Class<?>[] dest = new Class<?>[src.length + 1];
        System.arraycopy(src, 0, dest, 0, src.length);
        dest[src.length] = FuckService.class;
        
        HelloSerivce proxyInstance = (HelloSerivce)Proxy.newProxyInstance(HelloServiceImpl.class.getClassLoader(), 
                dest, myInvocationHandler);
        proxyInstance.sayHello();
        proxyInstance.sayHi();
        
        System.out.println(proxyInstance instanceof FuckService);
        FuckService fService = (FuckService)proxyInstance;
        //报错
        fService.fuck();
    }
}

dubbo consumer的InvokerInvocationHandler实现了InvocationHandler接口,拦截的是MockClusterInvoker对象的方法,这是jdk动态代理。

public class InvokerInvocationHandler implements InvocationHandler {
    private final Invoker<?> invoker;
    public InvokerInvocationHandler(Invoker<?> handler){
        this.invoker = handler;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        Class<?>[] parameterTypes = method.getParameterTypes();
        //如果是Object的方法,直接调用原生对象的方法
        if (method.getDeclaringClass() == Object.class) {
            return method.invoke(invoker, args);
        }
        //下面的判断其实是冗余的
        if ("toString".equals(methodName) && parameterTypes.length == 0) {
            return invoker.toString();
        }
        if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
            return invoker.hashCode();
        }
        if ("equals".equals(methodName) && parameterTypes.length == 1) {
            return invoker.equals(args[0]);
        }
        //剩下的就需要发送请求给provider了
        return invoker.invoke(new RpcInvocation(method, args)).recreate();
    }
}

比较一下jdk和javassist动态代理:

//JdkProxyFactory
@SuppressWarnings("unchecked")
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
    return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), 
interfaces, new InvokerInvocationHandler(invoker)); }

 

//JavassistProxyFactory
@SuppressWarnings("unchecked")
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
    return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
} 

存在HelloService接口:

public interface HelloService {
    String sayHello();
}

Javassist为它动态生成的类代码大致如下:

class com.alibaba.dubbo.common.bytecode.proxy0 implements
    com.alibaba.dubbo.rpc.service.EchoService, com.zhang.HelloService {
    public <init>(java.lang.reflect.InvocationHandler arg0){
        handler=$1;
    }
    public static java.lang.reflect.Method[] methods;
    private java.lang.reflect.InvocationHandler handler;
    
    public java.lang.String sayHello(){
        Object[] args = new Object[0];
        //handler是InvokerInvocationHandler对象
        Object ret = handler.invoke(this, methods[0], args);
        return (java.lang.String)ret;
    }
    public java.lang.Object $echo(java.lang.Object arg0){
        Object[] args = new Object[1];
        args[0] = ($w)$1;
        Object ret = handler.invoke(this, methods[1], args);
        return (java.lang.Object)ret;
    }
}

从上面能看出来:Javassist动态生成的类直接调用InvocationHandler,不是通过代理调用的。

posted on 2018-01-22 16:21  偶尔发呆  阅读(742)  评论(0编辑  收藏  举报