动态代理笔记

-----菜鸟一只,看了许多文章,自己综合的,所以会看到一样的.........

动态代理:

     就是在程序运行的过程中,动态的生成一个类(代理类),这个类要代理 目标业务对象(被代理类,也称为委托类) ,并且可以动态生成代理类的对象.

    作用:
        主要用来做方法的增强,让你可以在不修改源码的情况下,增强一些方法

    一.基于接口的动态代理(jdk官方的proxy)---被代理类需要实现接口


          (1).相关类:

                  调用处理器:invocationHandler ---方法:invoke()

                  动态代理类: proxy ---方法:newProxyInstance()

             

           (2).方法参数:

                     1.newProxyInstance():
                            第一个参数和第二个参数都是由被代理类获得
                            xxx.getClass().getClassLoader();
                            xxx.getInterfaces();

                    2.invoke(Object proxy,Method method,Object[] args):
                            proxy:为"代理类"对象
                            method:为"被代理类"的方法的Method对象
                            args:method方法的参数

           (3). 问题:  

                       当代理对象调用被代理对象的方法时,为什么其会自动的跳转到代理对象关联的                 InvocationHandler接   口对象的invoke方法来进行调用?

                    代码:

                           Proxy.newProxyInstance(loader,interfaces,new InvocationHandler(){

                                public Object invoke(Object proxy, Method method, Object[] args){

                                }

                            });

                           xxx.xxx();

                  原因:      

                        因为JDK生成的最终真正的代理类(starProxy),它继承自Proxy并实现了我们定义的Star接口,实                 现Star接口方法的内部,通过反射调用了handler的invoke方法.

                 代码:
                         public final String Say(String paramString){
                            try  {  
                               return (String)this.h.invoke(this, m4, new Object[] { paramString });  
                            }
        

        (4).代码过程

                    解析newProxyInstance()源码:

                        1.IvocationHandler handler = new MyInvocationHandler(...);
                           // 通过实现 InvocationHandler 接口创建自己的调用处理器;

                        2.Class<?> cl = getProxyClass0(loader, intfs);
                            //通过为 Proxy 类指定 ClassLoader 对象和一组 interface来创建 动态代理 ""

                        3.final Constructor<?> cons = cl.getConstructor(constructorParams);
                            //通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;

                        4.return cons.newInstance(new Object[]{h});
                            //通过构造函数创建动态代理类 "实例" ,构造时调用处理器对象作为参数被传入。

    二.基于子类的动态代理(cglib的enhancer)---被代理类不能被final修饰

        (0).原理:

                   利用了CGLIB,在运行时期生成被代理对象的子类,来作为代理对象,同时重写了被代理对象的方法.
        

        (1).相关类:

                    拦截器:MethodInterceptor---方法intercept()

                    字节码增强器:Enhancer(对想要处理的类进行扩展)---方法create()


        (2).方法参数:

                    1. intercept (Object obj,method m,Object[] args,MethodProxy proxy)
                        --obj:为"代理类"对象
                        --m:为"被代理类"的方法的Method对象
                        --args:method方法的参数
                        --proxy:"被代理对象方法" 的MethodProxy对象(生成的代理类对方法的代理引用--这句不懂)

                   2. proxy.invokeSuper(obj,args):调用代理类实例上的proxy方法 的 父类方法(即被代理类中对应             的方法)
                    或
                      m.invoke(new Target(),args)  //不建议使用,反射效率低----(不知道这个方法对不对,老师是这么               讲的)           

  

        (3).从其他文章看到的部分源码解析:

                    1.  代理类会为每个委托方法都生成两个方法,以xxx方法为例:(xxx方法为被代理类的方法)
            一个是重写的xxx方法;一个是CGLIB$xxx$0方法,该方法直接调用委托类的add方法.

               2. 当执行代理对象的xxx方法时,会先判断是否存在实现了MethodInterceptor接口的对象               cglib$CALLBACK_0, 如果存在,则调用MethodInterceptor对象的intercept方法(就是自己实现的                  intercept方法).----这里就解释了为何在执行代理对象的xxx方法时,intercept()会被调用.

                     3. Enhancer.create(Class type, Callback callback)的源码:

                          public static Object create(Class type, Callback callback) {

                                Enhancer e = new Enhancer();
                                e.setSuperclass(type); //首先将被代理类设置成父类
                                e.setCallback(callback);//然后设置拦截器MyInterceptor(实现MethodInterceptor)
                                return e.create();//最后执行enhancer.create()动态生成一个代理类

                           }


                    4. MethodProxy proxy

                         每个被代理的方法都对应一个MethodProxy对象,methodProxy.invokeSuper方法最终调用委                      托类的xxx方法

                       (1). invokeSuper()源码:  最终调用的是委托类的xxx()方法,下面说

                            public Object invokeSuper(Object obj, Object[] args) throws Throwable {  
                                    try {
                                            init();  //作用看下面的源码
                                            FastClassInfo fci = fastClassInfo;  
                                            return fci.f2.invoke(fci.i2, obj, args);  
                                      } catch (InvocationTargetException e) {  
                                            throw e.getTargetException();  
                                      }  

                               } 

                           (2).init()源码:实质上是生成一个FastClassInfo//作用看下面的源码

                             private void init() {

                                if (fastClassInfo == null){
                                        synchronized (initLock){
                                                if (fastClassInfo == null){
                                                        CreateInfo ci = createInfo;
                                                        FastClassInfo fci = new FastClassInfo();
                                                        fci.f1 = helper(ci, ci.c1);
                                                        fci.f2 = helper(ci, ci.c2);
                                                        fci.i1 = fci.f1.getIndex(sig1);
                                                        fci.i2 = fci.f2.getIndex(sig2);
                                                        fastClassInfo = fci;
                                                        createInfo = null;
                                                    }
                                            }
                                    }
                                }

                              (3).fastClassInfo源码:里面存放了两个FastClass   f1f2,还有两个方法索引的值i1和i2                         (f1和f2分别为委托类对象和代理类对象;i1i2分别为xxx()方法CGLIB$xxx$0方法在对象中索                         引位置(代理类会为每个委托方法都生成的两个方法)))
                                  private static class FastClassInfo {  
                                        FastClass f1;  
                                        FastClass f2;  
                                        int i1;  
                                        int i2;  
                                   }

    
                5.FastClass介绍:
                        fastClass机制就是对一个类的方法建立索引,通过索引来直接调用相应的方法
                下面通过一个例子了解一下FastClass的实现机制

                    目标类:
                        class Target {  
                                public void f(){  
                                    System.out.println("f method");  
                                }  
                      
                                public void g(){  
                                    System.out.println("g method");  
                                }  
                          }  

                    Fast类:
                            class FastTest {  
                                    public int getIndex(String signature){  
                                        switch(signature.hashCode()){  
                                                case xxxxx:  
                                                    return 1;  
                                                case xxxxx:  
                                                    return 2;  
                                           }  
                                        return -1;  
                                    }  
                      
                                    public Object invoke(int index, Object o, Object[] ol){  
                                        Target t = (Target) o;  
                                        switch(index){  
                                                    case 1:  
                                                        t.f();  
                                                         return null;  
                                                    case 2:  
                                                        t.g();  
                                                        return null;  
                                        }  
                                        return null;  
                                   }  
                        }  
                    测试类:
                         public static void main(String[] args){
                                Target target= new Target();
                                FastTest ft = new FastTest();
                                int index = ft.getIndex("f()V");
                                fc.invoke(index, target, null);//invokeSuper()源码中
                           }

                           在FastTest中有两个方法,getIndex中对Target类的每个方法根据hash建立索引,invoke根据指                      定的索引,直接调用目标方法-----------------所以当调用methodProxy.invokeSuper方法时,实际上                     是调用代理类的CGLIB$xxx$0方法,CGLIB$xxx$0直接调用了委托类的xxx方法.


              6.   proxy.invokeSuper(obj,args)是否可以改为proxy.invoke(obj,args)

                        不可以,原因是会栈溢出报错,OOM问题

           

               7.   jdk采用反射机制调用委托类的方法(反射的效率低),cglib采用类似索引的方式直接调用委托类方法



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值