• javassist和jdk动态代理


    先来一个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,不是通过代理调用的。

  • 相关阅读:
    19 SSM整合,SSM框架快速搭建
    18 MyBatis——多表查询
    17 MyBatis——ResultMap的使用、字段名冲突问题
    97 Eclipse的tomcat修改代码自动重启服务器功能的关闭
    27 Maven报错解决
    16 MyBatis——缓存
    Linux VPS搭建蚂蚁笔记Leanote私有云笔记存储平台
    CentOS7 安装记录
    Linux学习笔记之一
    mr-robot靶机练习
  • 原文地址:https://www.cnblogs.com/allenwas3/p/8329599.html
Copyright © 2020-2023  润新知