動(dòng)態(tài)代理-Cglib實(shí)現(xiàn)原理

動(dòng)態(tài)代理-Cglib實(shí)現(xiàn)原理

Cglib提供了一種運(yùn)行時(shí)動(dòng)態(tài)增強(qiáng)類(lèi)的功能。基于ASM在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建class庆揩,暴露Callback接口用于對(duì)類(lèi)和方法進(jìn)行增強(qiáng)。通過(guò)Cglib不僅能夠?qū)崿F(xiàn)同JDK Proxy一樣的基于接口和反射調(diào)用的增強(qiáng)類(lèi)鸳碧,同時(shí)也可以基于實(shí)現(xiàn)類(lèi)對(duì)類(lèi)進(jìn)行增強(qiáng)盾鳞,并且可以避免使用反射調(diào)用,而且使用了FastClass模式瞻离,運(yùn)行效率要高于使用反射

知識(shí)導(dǎo)讀

  • cglib是在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建類(lèi)的一種實(shí)現(xiàn)腾仅,可以對(duì)目標(biāo)類(lèi)的行為進(jìn)行擴(kuò)展或者覆蓋,不要局限于代理
  • cglib對(duì)目標(biāo)類(lèi)的增強(qiáng)主要是在運(yùn)行時(shí)生成目標(biāo)類(lèi)的子類(lèi)實(shí)現(xiàn)的套利。調(diào)用的時(shí)候基于FastClass模式推励,避免反射鹤耍,運(yùn)行速度比JDK proxy生成的快
  • cglib代理會(huì)創(chuàng)建3個(gè)class,所以創(chuàng)建速度會(huì)比JDK proxy慢
  • cglib也可以同JDK proxy一樣,創(chuàng)建基于接口實(shí)現(xiàn)的增強(qiáng)類(lèi)验辞,調(diào)用基于反射
  • cglib動(dòng)態(tài)增強(qiáng)生成子類(lèi)的時(shí)候稿黄,目標(biāo)類(lèi)和目標(biāo)方法不能是final修飾的
  • 對(duì)方法的增強(qiáng)是通過(guò)Callback接口實(shí)現(xiàn)的,所以需要實(shí)現(xiàn)的邏輯都在這
  • 使用Callback+CallbackFilter實(shí)現(xiàn)對(duì)不同方法實(shí)現(xiàn)不同的增強(qiáng)
  • 最常用的Callback實(shí)現(xiàn)MethodInterceptor跌造,理解每個(gè)參數(shù)的含義
  • MethodProxy+FastClass實(shí)現(xiàn)原理

使用

創(chuàng)建一個(gè)非final的類(lèi)杆怕,用于被增強(qiáng)

public class MacBookSeller {

    private String name;

    public MacBookSeller(String name) {
        this.name = name;
    }
    public MacBookSeller() {
        this.name = "未知";
    }
    public void sellComputor(String brand) {
        System.out.println("sell the MacBook computor");
    }
    public String repairComputor(String brand) {
        System.out.println("repair the MacBook computor:" + name);
        return name;
    }
}

來(lái)看個(gè)使用cglib對(duì)MacBookSeller類(lèi)進(jìn)行增強(qiáng)的例子

public static void main(String[] args) {
    //生成cglib生成的類(lèi)
    System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, JdkProxy.class.getResource("/").getPath());
    //創(chuàng)建一個(gè)加強(qiáng)器 Enhancer對(duì)象
    Enhancer enhancer = new Enhancer();
    //設(shè)置要?jiǎng)?chuàng)建動(dòng)態(tài)代理的類(lèi),即父類(lèi)
    enhancer.setSuperclass(MacBookSeller.class);
    MacBookSeller macBookSeller = new MacBookSeller("蘋(píng)果專(zhuān)賣(mài)店");
    // 設(shè)置回調(diào),這里相當(dāng)于是對(duì)于目標(biāo)類(lèi)上所有方法的調(diào)用壳贪,都會(huì)調(diào)用CallBack陵珍,而Callback則需要實(shí)行intercept()方法進(jìn)行攔截
    enhancer.setCallback(new MethodInterceptor() {
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            if (method.getName().equalsIgnoreCase("repairComputor")) {
                System.out.println("開(kāi)始代理");
                System.out.println(String.format("method name:%s,args:%s", method.getName(), JSON.toJSONString(args)));
                //增強(qiáng)類(lèi)繼承的目標(biāo)類(lèi),調(diào)用父類(lèi)的原方法
                Object o = proxy.invokeSuper(obj, args);//通過(guò)增強(qiáng)類(lèi)調(diào)用目標(biāo)類(lèi)方法违施,注意obj是增強(qiáng)類(lèi)對(duì)象
                Object o1 = proxy.invoke(macBookSeller, args);//直接通過(guò)父類(lèi)對(duì)象調(diào)用
                System.out.println("通過(guò)增強(qiáng)類(lèi)對(duì)象調(diào)用父類(lèi)方法結(jié)果:" + o);//輸出的name是增強(qiáng)類(lèi)的name
                System.out.println("通過(guò)目標(biāo)類(lèi)對(duì)象直接調(diào)用目標(biāo)方法結(jié)果:" + o1);//輸出的name是父類(lèi)的name
                System.out.println("結(jié)束代理");
                return o;//調(diào)用增強(qiáng)類(lèi)對(duì)象方法的返回值
            }
            return null;
        }
    });
    //創(chuàng)建代理類(lèi)對(duì)象 指定構(gòu)造器
    MacBookSeller proxy = MacBookSeller.class.cast(enhancer.create(new Class[]{String.class}, new String[]{"proxy"}));
    System.out.println("proxy對(duì)象:" + proxy.getClass().getName());//cn.zlz.proxy.cglib.MacBookSeller$$EnhancerByCGLIB$$9c2b1abb
    String result = proxy.repairComputor("mac book pro");
    System.out.println("調(diào)用增強(qiáng)類(lèi)對(duì)象的repairComputor方法返回結(jié)果:" + result);
}

Enhancer類(lèi)中也提供了靜態(tài)方法可以直接創(chuàng)建增強(qiáng)類(lèi)對(duì)象

public static Object create(Class superclass, Class[] interfaces, CallbackFilter filter, Callback[] callbacks) {
    Enhancer e = new Enhancer();
    e.setSuperclass(superclass);
    e.setInterfaces(interfaces);
    e.setCallbackFilter(filter);
    e.setCallbacks(callbacks);
    return e.create();
}

當(dāng)要增強(qiáng)類(lèi)中的不同方法需要不同的增強(qiáng)處理互纯,可以指定多個(gè)Callback實(shí)現(xiàn),同時(shí)使用CallbackFilter來(lái)給不同的方法分配不同的Callback來(lái)進(jìn)行增強(qiáng)

public static void main(String[] args) {
    System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, JdkProxy.class.getResource("/").getPath());
    //創(chuàng)建一個(gè)加強(qiáng)器 Enhancer對(duì)象
    Enhancer enhancer = new Enhancer();
    //設(shè)置要?jiǎng)?chuàng)建動(dòng)態(tài)代理的類(lèi),即父類(lèi)
    enhancer.setSuperclass(MacBookSeller.class);
    MethodInterceptor methodInterceptor1 = new MethodInterceptor() {
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("開(kāi)始代理1");
            //代理類(lèi)是繼承的被代理類(lèi)磕蒲,調(diào)用父類(lèi)的原方法
            Object o = proxy.invokeSuper(obj, args);
            System.out.println(String.format("被代理方法返回值0:%s", o));
            System.out.println("結(jié)束代理1");
            return o;
        }
    };
    MethodInterceptor methodInterceptor2 = new MethodInterceptor() {
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("開(kāi)始代理2");
            //代理類(lèi)是繼承的被代理類(lèi)留潦,調(diào)用父類(lèi)的原方法
            Object o = proxy.invokeSuper(obj, args);
            System.out.println(String.format("被代理方法返回值0:%s", o));
            System.out.println("結(jié)束代理2");
            return o;
        }
    };

    // 設(shè)置回調(diào),這里相當(dāng)于是對(duì)于代理類(lèi)上所有方法的調(diào)用辣往,都會(huì)調(diào)用CallBack兔院,而Callback則需要實(shí)行intercept()方法進(jìn)行攔截
    Callback[] callbacks = {methodInterceptor1, methodInterceptor2, NoOp.INSTANCE};
    enhancer.setCallbacks(callbacks);
    //CallbackFilter對(duì)應(yīng)Callbacks中的,用于指定方法使用哪個(gè)Callback
    CallbackFilter callbackFilter = new CallbackFilter() {
        @Override
        public int accept(Method method) {
            if (method.getName().equalsIgnoreCase("repairComputor")) {
                return 0;//使用數(shù)組中的一個(gè) MethodInterceptor
            } else if (method.getName().equalsIgnoreCase("sellComputor")) {
                return 1;//使用Callback數(shù)組中的第二個(gè)  MethodInterceptor
            } else {
                return 2;//其他方法使用NoOp不進(jìn)行任何增強(qiáng)
            }
        }
    };
    enhancer.setCallbackFilter(callbackFilter);
    MacBookSeller proxy = MacBookSeller.class.cast(Enhancer.create(MacBookSeller.class, null, callbackFilter, callbacks));
    proxy.repairComputor("mac book pro");
    proxy.sellComputor("mac book pro");
}

Cglib不僅可以基于實(shí)現(xiàn)類(lèi)來(lái)進(jìn)行增強(qiáng)站削,同時(shí)也可以實(shí)現(xiàn)JDK的代理秆乳,在Cglib中提供了一個(gè)InvocationHandler接口實(shí)現(xiàn)了Callback接口,通過(guò)設(shè)置一個(gè)InvocationHandler實(shí)現(xiàn)可以創(chuàng)建一個(gè)和JDK代理實(shí)現(xiàn)方式一樣的增強(qiáng)類(lèi)钻哩,調(diào)用是基于反射來(lái)實(shí)現(xiàn)的,來(lái)看下面例子

public static void main(String[] args) {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, JdkProxy.class.getResource("/").getPath());
        //創(chuàng)建一個(gè)加強(qiáng)器 Enhancer對(duì)象
        Enhancer enhancer = new Enhancer();
        //設(shè)置要?jiǎng)?chuàng)建動(dòng)態(tài)代理接口
        enhancer.setInterfaces(new Class[]{IComputorService.class});
        Callback invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
                System.out.println(proxy.getClass().getName());
                System.out.println("method:" + method.getName());
//                return method.invoke(proxy, args);
                boolean enhanced = Enhancer.isEnhanced(proxy.getClass());
                System.out.println("是否增強(qiáng):"+enhanced);
                return null;
            }
        };
        enhancer.setCallbacks(new Callback[]{invocationHandler, NoOp.INSTANCE});
        enhancer.setCallbackFilter(new CallbackFilter() {
            @Override
            public int accept(Method method) {
                //invocationHandler只攔截repairComputor和sellComputor兩個(gè)方法
                if(method.getName().equalsIgnoreCase("repairComputor") ||method.getName().equalsIgnoreCase("sellComputor")) {
                    return 0;
                }else {//使用NoOp不對(duì)其他方法進(jìn)行增強(qiáng)
                    return 1;
                }
            }
        });
        //創(chuàng)建代理類(lèi)對(duì)象
        IComputorService proxy = IComputorService.class.cast(enhancer.create());
        proxy.repairComputor("mac book pro");
    }

原理

cglib基于繼承目標(biāo)類(lèi)創(chuàng)建子類(lèi)進(jìn)行增強(qiáng)的時(shí)候肛冶,會(huì)動(dòng)態(tài)創(chuàng)建3個(gè)類(lèi)街氢,一個(gè)是通過(guò)Enhancer創(chuàng)建一個(gè)目標(biāo)類(lèi)的實(shí)現(xiàn)類(lèi),另外兩個(gè)是通過(guò)MethodProxy創(chuàng)建的FastClass睦袖,分別對(duì)應(yīng)增強(qiáng)前的目標(biāo)類(lèi)的FastClass和增強(qiáng)類(lèi)的FastClass珊肃,F(xiàn)astClass用于基于索引訪問(wèn)對(duì)象的方法。首先來(lái)看動(dòng)態(tài)生成的增強(qiáng)類(lèi)

public class MacBookSeller$$EnhancerByCGLIB$$b857906a extends MacBookSeller implements Factory {
    private boolean CGLIB$BOUND;
    //用于存儲(chǔ)和線程綁定 Callback
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    //Callback 用于對(duì)方法進(jìn)行增強(qiáng)
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    //因?yàn)樵谏傻臅r(shí)候傳遞了3個(gè)Callback馅笙,所有會(huì)有3個(gè)
    private MethodInterceptor CGLIB$CALLBACK_0;
    private MethodInterceptor CGLIB$CALLBACK_1;
    private NoOp CGLIB$CALLBACK_2;
    private static final Method CGLIB$repairComputor$0$Method;
    //對(duì)應(yīng) repairComputor 的MethodProxy
    private static final MethodProxy CGLIB$repairComputor$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$sellComputor$1$Method;
     //對(duì)應(yīng) sellComputor 的MethodProxy
    private static final MethodProxy CGLIB$sellComputor$1$Proxy;

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        Class var0;
        ClassLoader var10000 = (var0 = Class.forName("cn.zlz.proxy.cglib.MacBookSeller$$EnhancerByCGLIB$$b857906a")).getClassLoader();
        CGLIB$emptyArgs = new Object[0];
        //創(chuàng)建MethodProxy
        CGLIB$repairComputor$0$Proxy = MethodProxy.create(var10000, (CGLIB$repairComputor$0$Method = Class.forName("cn.zlz.proxy.cglib.MacBookSeller").getDeclaredMethod("repairComputor", Class.forName("java.lang.String"))).getDeclaringClass(), var0, "(Ljava/lang/String;)Ljava/lang/String;", "repairComputor", "CGLIB$repairComputor$0");
       //創(chuàng)建MethodProxy
        CGLIB$sellComputor$1$Proxy = MethodProxy.create(var10000, (CGLIB$sellComputor$1$Method = Class.forName("cn.zlz.proxy.cglib.MacBookSeller").getDeclaredMethod("sellComputor", Class.forName("java.lang.String"))).getDeclaringClass(), var0, "(Ljava/lang/String;)V", "sellComputor", "CGLIB$sellComputor$1");
    }

    final String CGLIB$repairComputor$0(String var1) {
        //使用子類(lèi)對(duì)象調(diào)用父類(lèi)方法
        return super.repairComputor(var1);
    }

    //調(diào)用增強(qiáng)后的方法
    public final String repairComputor(String var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
        //調(diào)用Callback的實(shí)現(xiàn)類(lèi)實(shí)現(xiàn)
        return var10000 != null ? (String)var10000.intercept(this, CGLIB$repairComputor$0$Method, new Object[]{var1}, CGLIB$repairComputor$0$Proxy) : super.repairComputor(var1);
    }

    final void CGLIB$sellComputor$1(String var1) {
        super.sellComputor(var1);
    }

    public final void sellComputor(String var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_1;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_1;
        }

        if (var10000 != null) {
            var10000.intercept(this, CGLIB$sellComputor$1$Method, new Object[]{var1}, CGLIB$sellComputor$1$Proxy);
        } else {
            super.sellComputor(var1);
        }
    }

    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
        case -819357441:
            if (var10000.equals("repairComputor(Ljava/lang/String;)Ljava/lang/String;")) {
                return CGLIB$repairComputor$0$Proxy;
            }
            break;
        case 667760668:
            if (var10000.equals("sellComputor(Ljava/lang/String;)V")) {
                return CGLIB$sellComputor$1$Proxy;
            }
        }
        return null;
    }

    public MacBookSeller$$EnhancerByCGLIB$$b857906a(String var1) {
        super(var1);
        CGLIB$BIND_CALLBACKS(this);
    }

    public MacBookSeller$$EnhancerByCGLIB$$b857906a() {
        CGLIB$BIND_CALLBACKS(this);
    }

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
        CGLIB$THREAD_CALLBACKS.set(var0);
    }

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
        CGLIB$STATIC_CALLBACKS = var0;
    }

    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        MacBookSeller$$EnhancerByCGLIB$$b857906a var1 = (MacBookSeller$$EnhancerByCGLIB$$b857906a)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }

            Callback[] var10001 = (Callback[])var10000;
            var1.CGLIB$CALLBACK_2 = (NoOp)((Callback[])var10000)[2];
            var1.CGLIB$CALLBACK_1 = (MethodInterceptor)var10001[1];
            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)var10001[0];
        }

    }

    public Object newInstance(Callback[] var1) {
        CGLIB$SET_THREAD_CALLBACKS(var1);
        MacBookSeller$$EnhancerByCGLIB$$b857906a var10000 = new MacBookSeller$$EnhancerByCGLIB$$b857906a();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Callback var1) {
        throw new IllegalStateException("More than one callback object required");
    }
    //創(chuàng)建對(duì)象的時(shí)候要傳入 Callback
    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        MacBookSeller$$EnhancerByCGLIB$$b857906a var10000 = new MacBookSeller$$EnhancerByCGLIB$$b857906a;
        //基于CallbackFilter配置來(lái)生成的不同方法設(shè)置不同的Callback
        switch(var1.length) {
        case 0:
            var10000.<init>();
            break;
        case 1:
            if (var1[0].getName().equals("java.lang.String")) {
                var10000.<init>((String)var2[0]);
                break;
            }

            throw new IllegalArgumentException("Constructor not found");
        default:
            throw new IllegalArgumentException("Constructor not found");
        }

        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Callback getCallback(int var1) {
        CGLIB$BIND_CALLBACKS(this);
        Object var10000;
        //基于CallbackFilter配置來(lái)生成的不同方法設(shè)置不同的Callback
        switch(var1) {
        case 0:
            var10000 = this.CGLIB$CALLBACK_0;
            break;
        case 1:
            var10000 = this.CGLIB$CALLBACK_1;
            break;
        case 2:
            var10000 = this.CGLIB$CALLBACK_2;
            break;
        default:
            var10000 = null;
        }

        return (Callback)var10000;
    }

    public void setCallback(int var1, Callback var2) {
        switch(var1) {
        case 0:
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
            break;
        case 1:
            this.CGLIB$CALLBACK_1 = (MethodInterceptor)var2;
            break;
        case 2:
            this.CGLIB$CALLBACK_2 = (NoOp)var2;
        }

    }

    public Callback[] getCallbacks() {
        CGLIB$BIND_CALLBACKS(this);
        return new Callback[]{this.CGLIB$CALLBACK_0, this.CGLIB$CALLBACK_1, this.CGLIB$CALLBACK_2};
    }

    public void setCallbacks(Callback[] var1) {
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
        this.CGLIB$CALLBACK_1 = (MethodInterceptor)var1[1];
        this.CGLIB$CALLBACK_2 = (NoOp)var1[2];
    }

    static {
        CGLIB$STATICHOOK1();
    }
}

通過(guò)生成的增強(qiáng)類(lèi)可以分析以下幾點(diǎn)

  • 分清增強(qiáng)類(lèi)和增強(qiáng)類(lèi)對(duì)象伦乔,基于增強(qiáng)類(lèi)可以創(chuàng)建很多對(duì)象,每個(gè)對(duì)象可以設(shè)置不同的Callback實(shí)現(xiàn)
  • 在創(chuàng)建增強(qiáng)類(lèi)對(duì)象的時(shí)候董习,一定要傳遞Callback實(shí)現(xiàn)烈和,用于對(duì)方法進(jìn)行增強(qiáng)
  • 在增強(qiáng)類(lèi)對(duì)象中可以使用增強(qiáng)類(lèi)對(duì)象調(diào)用目標(biāo)類(lèi)對(duì)象
  • 對(duì)方法的增強(qiáng)其實(shí)就是調(diào)用Callback實(shí)現(xiàn)類(lèi)的方法,所以要對(duì)方法進(jìn)行增強(qiáng)皿淋,就是在Callback實(shí)現(xiàn)類(lèi)中寫(xiě)增強(qiáng)邏輯
  • 對(duì)于每個(gè)要增強(qiáng)的方法都創(chuàng)建了一個(gè)MethodProxy對(duì)象招刹,在調(diào)用Callback的實(shí)現(xiàn)的增強(qiáng)方法時(shí)將這個(gè)方法的MethodProxy對(duì)象傳遞過(guò)去恬试,對(duì)于FastClass模式調(diào)用就是基于MethodProxy實(shí)現(xiàn)的

接下來(lái)看生成的FastClass,我們只看一個(gè)對(duì)應(yīng)目標(biāo)類(lèi)的FastClass就可以疯暑,對(duì)應(yīng)增強(qiáng)類(lèi)的FastClass實(shí)現(xiàn)是類(lèi)似的

public class MacBookSeller$$FastClassByCGLIB$$f1fe2621 extends FastClass {
    public MacBookSeller$$FastClassByCGLIB$$f1fe2621(Class var1) {
        super(var1);
    }

    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case -1725733088:
            if (var10000.equals("getClass()Ljava/lang/Class;")) {
                return 8;
            }
            break;
        case -1026001249:
            if (var10000.equals("wait(JI)V")) {
                return 3;
            }
            break;
        case -819357441:
            if (var10000.equals("repairComputor(Ljava/lang/String;)Ljava/lang/String;")) {
                return 0;
            }
            break;
        case 243996900:
            if (var10000.equals("wait(J)V")) {
                return 4;
            }
            break;
        case 667760668:
            if (var10000.equals("sellComputor(Ljava/lang/String;)V")) {
                return 1;
            }
            break;
        case 946854621:
            if (var10000.equals("notifyAll()V")) {
                return 10;
            }
            break;
        case 1116248544:
            if (var10000.equals("wait()V")) {
                return 2;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return 5;
            }
            break;
        case 1902039948:
            if (var10000.equals("notify()V")) {
                return 9;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return 6;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return 7;
            }
        }

        return -1;
    }

    public int getIndex(String var1, Class[] var2) {
        switch(var1.hashCode()) {
        case -1886247170:
            if (var1.equals("repairComputor")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("java.lang.String")) {
                        return 0;
                    }
                }
            }
            break;
        case -1776922004:
            if (var1.equals("toString")) {
                switch(var2.length) {
                case 0:
                    return 6;
                }
            }
            break;
        case -1358544445:
            if (var1.equals("sellComputor")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("java.lang.String")) {
                        return 1;
                    }
                }
            }
            break;
        case -1295482945:
            if (var1.equals("equals")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("java.lang.Object")) {
                        return 5;
                    }
                }
            }
            break;
        case -1039689911:
            if (var1.equals("notify")) {
                switch(var2.length) {
                case 0:
                    return 9;
                }
            }
            break;
        case 3641717:
            if (var1.equals("wait")) {
                switch(var2.length) {
                case 0:
                    return 2;
                case 1:
                    if (var2[0].getName().equals("long")) {
                        return 4;
                    }
                    break;
                case 2:
                    if (var2[0].getName().equals("long") && var2[1].getName().equals("int")) {
                        return 3;
                    }
                }
            }
            break;
        case 147696667:
            if (var1.equals("hashCode")) {
                switch(var2.length) {
                case 0:
                    return 7;
                }
            }
            break;
        case 1902066072:
            if (var1.equals("notifyAll")) {
                switch(var2.length) {
                case 0:
                    return 10;
                }
            }
            break;
        case 1950568386:
            if (var1.equals("getClass")) {
                switch(var2.length) {
                case 0:
                    return 8;
                }
            }
        }

        return -1;
    }

    public int getIndex(Class[] var1) {
        switch(var1.length) {
        case 0:
            return 1;
        case 1:
            if (var1[0].getName().equals("java.lang.String")) {
                return 0;
            }
        default:
            return -1;
        }
    }
    //通過(guò)不同的索引index來(lái)找到具體哪個(gè)方法的調(diào)用训柴,避免了反射調(diào)用
    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        MacBookSeller var10000 = (MacBookSeller)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
            case 0:
                return var10000.repairComputor((String)var3[0]);
            case 1:
                var10000.sellComputor((String)var3[0]);
                return null;
            case 2:
                var10000.wait();
                return null;
            case 3:
                var10000.wait(((Number)var3[0]).longValue(), ((Number)var3[1]).intValue());
                return null;
            case 4:
                var10000.wait(((Number)var3[0]).longValue());
                return null;
            case 5:
                return new Boolean(var10000.equals(var3[0]));
            case 6:
                return var10000.toString();
            case 7:
                return new Integer(var10000.hashCode());
            case 8:
                return var10000.getClass();
            case 9:
                var10000.notify();
                return null;
            case 10:
                var10000.notifyAll();
                return null;
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
        MacBookSeller var10000 = new MacBookSeller;
        MacBookSeller var10001 = var10000;
        int var10002 = var1;

        try {
            switch(var10002) {
            case 0:
                var10001.<init>((String)var2[0]);
                return var10000;
            case 1:
                var10001.<init>();
                return var10000;
            }
        } catch (Throwable var3) {
            throw new InvocationTargetException(var3);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public int getMaxIndex() {
        return 10;
    }
}

主要來(lái)看invoke方法,在該方法中建立了目標(biāo)類(lèi)方法和index的對(duì)應(yīng)關(guān)系妇拯。這樣在調(diào)用的時(shí)候直接使用index就可以查找到調(diào)用哪個(gè)方法幻馁,避免了反射調(diào)用。

再來(lái)看下是在哪使用FastClass的invoke方法的越锈,來(lái)看下MethodProxy的實(shí)現(xiàn)仗嗦,每個(gè)方法都會(huì)創(chuàng)建一個(gè)MethodProxy對(duì)象,在MethodProxy對(duì)象中會(huì)分別保存對(duì)應(yīng)目標(biāo)類(lèi)的FastClass對(duì)象和該方法對(duì)應(yīng)的index瞪浸,和對(duì)應(yīng)增強(qiáng)類(lèi)的FastClass對(duì)象和該方法對(duì)應(yīng)的index儒将,通過(guò)調(diào)用FastClass的invoke方法實(shí)現(xiàn)對(duì)方法的調(diào)用

public class MethodProxy {
    private Signature sig;
    private String superName;//父類(lèi)名稱,也就是增強(qiáng)前類(lèi)的名稱
    private FastClass f1;//增強(qiáng)前類(lèi)對(duì)應(yīng)生成的FastClass對(duì)象
    private FastClass f2;//增強(qiáng)后類(lèi)對(duì)應(yīng)生成的FastClass對(duì)象
    private int i1;//增強(qiáng)前類(lèi)的某方法在FastIndex中的索引
    private int i2;//增強(qiáng)后類(lèi)的某方法在FastIndex中的索引

//CGLIB$repairComputor$0$Proxy = MethodProxy.create(var10000, Class.forName("cn.zlz.proxy.cglib.MacBookSeller"),  Class.forName("cn.zlz.proxy.cglib.MacBookSeller$$EnhancerByCGLIB$$4780b236"), "(Ljava/lang/String;)Ljava/lang/String;", "repairComputor", "CGLIB$repairComputor$0");

    public static MethodProxy create(ClassLoader loader, Class c1, Class c2, String desc, String name1, String name2) {
        final Signature sig1 = new Signature(name1, desc);
        Signature sig2 = new Signature(name2, desc);
        FastClass f1 = helper(loader, c1);//生成增強(qiáng)前類(lèi)的FastClass并創(chuàng)建對(duì)象
        FastClass f2 = helper(loader, c2);//生成增強(qiáng)后類(lèi)的FastClass并創(chuàng)建對(duì)象
        int i1 = f1.getIndex(sig1);//獲取增強(qiáng)前方法的索引
        int i2 = f2.getIndex(sig2);//獲取增強(qiáng)后方法的索引
        MethodProxy proxy;
        if (i1 < 0) {
            proxy = new MethodProxy() {
                public Object invoke(Object obj, Object[] args) throws Throwable {
                    throw new IllegalArgumentException("Protected method: " + sig1);
                }
            };
        } else {
            proxy = new MethodProxy();
        }
        proxy.f1 = f1;
        proxy.f2 = f2;
        proxy.i1 = i1;
        proxy.i2 = i2;
        proxy.sig = sig1;
        proxy.superName = name2;
        return proxy;
    }
}

使用MethodProxy的invoke方法調(diào)用目標(biāo)類(lèi)的方法,在該方法中會(huì)調(diào)用目標(biāo)類(lèi)對(duì)應(yīng)的FastClass對(duì)象的invoke方法对蒲,通過(guò)索引找到目標(biāo)對(duì)象的具體方法钩蚊,避免反射

public Object invoke(Object obj, Object[] args) throws Throwable {
    try {
        return f1.invoke(i1, obj, args);
    } catch (InvocationTargetException e) {
        throw e.getTargetException();
    }
}

使用MethodProxy的invokeSuper方法調(diào)用增強(qiáng)類(lèi)的方法,在該方法中調(diào)用增強(qiáng)類(lèi)對(duì)象的FastClass對(duì)象的invoke方法,通過(guò)索引找到具體的方法蹈矮,避免反射

public Object invokeSuper(Object obj, Object[] args) throws Throwable {
    try {
        return f2.invoke(i2, obj, args);
    } catch (InvocationTargetException e) {
        throw e.getTargetException();
    }
}

源碼

簡(jiǎn)單了解下cglib增強(qiáng)類(lèi)的實(shí)現(xiàn)

Callback接口

  • 首先認(rèn)識(shí)一下Callback接口砰逻,這是cglib中很重要的一個(gè)接口,用于實(shí)現(xiàn)對(duì)方法增強(qiáng)的攔截接口泛鸟。在增強(qiáng)的時(shí)候可以傳遞多個(gè)Callback實(shí)現(xiàn)類(lèi)對(duì)象蝠咆,不過(guò)一個(gè)方法最多應(yīng)用一個(gè)Callback進(jìn)行增強(qiáng)。不同的方法可以使用不同的Callback實(shí)現(xiàn)類(lèi)來(lái)進(jìn)行增強(qiáng)北滥,這個(gè)要結(jié)合CallbackFilter來(lái)實(shí)現(xiàn)

     /** @see MethodInterceptor NoOp LazyLoader Dispatcher InvocationHandler FixedValue*/  
    public interface Callback{}
    
  • 來(lái)看Callback的一個(gè)實(shí)現(xiàn)接口MethodInterceptor,也是最常用的刚操。

    public interface MethodInterceptor extends Callback { 
        /**
        * @param obj "this":增強(qiáng)后的類(lèi)對(duì)象
        * @param method: 被攔截的方法,增強(qiáng)前的對(duì)象的方法再芋,通過(guò)這個(gè)method可以用反射調(diào)用原方法
        * @param args: 調(diào)用方法時(shí)傳遞的參數(shù)
        * @param proxy: 可以用來(lái)調(diào)用原方法菊霜,也可以調(diào)用增強(qiáng)后的方法,使用fastClass模式調(diào)用(更快)
        */
        public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
                                   MethodProxy proxy) throws Throwable;
    }
    
    • 當(dāng)調(diào)用增強(qiáng)類(lèi)方法的時(shí)候會(huì)轉(zhuǎn)來(lái)調(diào)用intercept方法济赎,在該方法中可以調(diào)用目標(biāo)類(lèi)(父類(lèi))的方法鉴逞,也可以重寫(xiě)邏輯
    • 通過(guò)method可以用反射的方法調(diào)用增強(qiáng)類(lèi)的方法,然后間接調(diào)用目標(biāo)類(lèi)的方法司训,不過(guò)這種方式不推薦构捡,可以使用 proxy.invokeSuper(),避免反射。
  • cglib也可以實(shí)現(xiàn)基于jdk的代理壳猜,通過(guò)實(shí)現(xiàn)cglib中的InvocationHandler勾徽。實(shí)現(xiàn)方式與JDK的proxy一樣,都是基于Method反射做的

    public interface InvocationHandler extends Callback{
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
    }
    
  • 如果對(duì)方法不做任何攔截蓖谢, cglib提供了 一個(gè) NoOp的實(shí)現(xiàn)類(lèi)

    public interface NoOp extends Callback
    {
        public static final NoOp INSTANCE = new NoOp() { };
    }
    

CallbackFilter接口

  • 一個(gè)Callback會(huì)作用到類(lèi)的所有方法捂蕴,有時(shí)候不同的方法使用不同的增強(qiáng)Callback譬涡,這時(shí)就可以使用CallbackFilter來(lái)控制。在accept方法中返回的數(shù)字要嚴(yán)格對(duì)應(yīng)Callback[]數(shù)組中對(duì)應(yīng)下標(biāo)的Callback實(shí)現(xiàn)類(lèi)對(duì)象啥辨。

    enhancer.setCallbacks(new Callback[]{methodInterceptor1, methodInterceptor2, NoOp.INSTANCE});
    CallbackFilter callbackFilter = new CallbackFilter() {
        @Override
        public int accept(Method method) {
            //嚴(yán)格對(duì)應(yīng)Callbacks數(shù)組中的下標(biāo)Callback
            if(method.getName().equalsIgnoreCase("repairComputor")) {
                return 0;//使用數(shù)組中的一個(gè) MethodInterceptor
            }else if(method.getName().equalsIgnoreCase("sellComputor")){
                return 1;
            }else{
                return 2;
            }
        }
    };
    enhancer.setCallbackFilter(callbackFilter);
    

Factory接口

  • cglib生成的增強(qiáng)類(lèi)都實(shí)現(xiàn)了Factory接口涡匀,通過(guò)接口中的newInstance方法創(chuàng)建對(duì)象會(huì)比較快,不需要反射溉知。通過(guò)接口提供的方法可以看出要?jiǎng)?chuàng)建一個(gè)增強(qiáng)類(lèi)對(duì)象必須要傳遞Callback對(duì)象作為參數(shù),用于對(duì)方法進(jìn)行增強(qiáng)

    public interface Factory {
        Object newInstance(Callback callback);    
        Object newInstance(Callback[] callbacks);
        Object newInstance(Class[] types, Object[] args, Callback[] callbacks);
        Callback getCallback(int index);
        void setCallback(int index, Callback callback);
        void setCallbacks(Callback[] callbacks);  
        Callback[] getCallbacks();
    }
    

Enhancer類(lèi)

Enhancer類(lèi)是cglib提供增強(qiáng)功能的入口類(lèi)陨瘩,通過(guò)該類(lèi)可以在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建增強(qiáng)類(lèi)或者增強(qiáng)類(lèi)對(duì)象

  • 判斷類(lèi)是否是用Cglib增強(qiáng)后的類(lèi),注意级乍,由于cglib也可增強(qiáng)基于接口實(shí)現(xiàn)的類(lèi)舌劳,所以如果使用cglib的invocationHandler增強(qiáng)后的類(lèi)通過(guò)isEnhanced返回的也是true

    public static boolean isEnhanced(Class type) {
        try {
            getCallbacksSetter(type, SET_THREAD_CALLBACKS_NAME);
            return true;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }
    
  • 調(diào)用create方法進(jìn)入增強(qiáng)類(lèi)對(duì)象的創(chuàng)建流程,在該方法中調(diào)用createHelper方法

    //基于無(wú)參構(gòu)造器創(chuàng)建增強(qiáng)類(lèi)對(duì)象
    public Object create() {
        classOnly = false;
        argumentTypes = null;
        return createHelper();
    }
    //基于有參構(gòu)造器創(chuàng)建增強(qiáng)類(lèi)對(duì)象
    public Object create(Class[] argumentTypes, Object[] arguments) {
            classOnly = false;
            if (argumentTypes == null || arguments == null || argumentTypes.length != arguments.length) {
                throw new IllegalArgumentException("Arguments must be non-null and of equal length");
            }
            this.argumentTypes = argumentTypes;
            this.arguments = arguments;
            return createHelper();
        }
    
  • 在createHelper方法中進(jìn)行了參數(shù)校驗(yàn)玫荣,然后設(shè)置包名甚淡,然后調(diào)用父類(lèi)的create的方法創(chuàng)建增強(qiáng)類(lèi)對(duì)象,注意傳入了一個(gè)cacheKey捅厂,用于避免重復(fù)創(chuàng)建class贯卦,當(dāng)cacheKey一樣的時(shí)候,直接取緩存中的增強(qiáng)類(lèi)來(lái)創(chuàng)建對(duì)象

    private Object createHelper() {
        validate();
        if (superclass != null) {//包名
            setNamePrefix(superclass.getName());
        } else if (interfaces != null) {
            setNamePrefix(interfaces[ReflectUtils.findPackageProtected(interfaces)].getName());
        }
        return super.create(KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null, ReflectUtils.getNames(interfaces),filter,callbackTypes,useFactory,
    interceptDuringConstruction, serialVersionUID));
    }
    
  • 在父類(lèi)的create方法中完成了增強(qiáng)類(lèi)對(duì)象焙贷。為了避免重復(fù)創(chuàng)建相同的增強(qiáng)類(lèi)撵割,使用到了緩存。使用strategy生成增強(qiáng)類(lèi)字節(jié)碼辙芍,使用的是ASM實(shí)現(xiàn)的啡彬,這里就不詳細(xì)展示生成過(guò)程了。

    protected Object create(Object key) {
        try {
           Class gen = null;
           
            synchronized (source) {
                ClassLoader loader = getClassLoader();
                Map cache2 = null;
                cache2 = (Map)source.cache.get(loader);
                if (cache2 == null) {
                    cache2 = new HashMap();
                    cache2.put(NAME_KEY, new HashSet());
                    source.cache.put(loader, cache2);
                } else if (useCache) {
                    //從緩存中獲取增強(qiáng)類(lèi)
                    Reference ref = (Reference)cache2.get(key);
                    gen = (Class) (( ref == null ) ? null : ref.get()); 
                }
                if (gen == null) {
                    Object save = CURRENT.get();
                    CURRENT.set(this);
                    try {
                        this.key = key;
                        
                        if (attemptLoad) {
                            try {//用類(lèi)加載嘗試從虛擬機(jī)中加載增強(qiáng)類(lèi)字節(jié)碼故硅,如果生成過(guò)就不用再創(chuàng)建
                                gen = loader.loadClass(getClassName());
                            } catch (ClassNotFoundException e) {
                                // ignore
                            }
                        }
                        if (gen == null) {
                            //調(diào)用strategy生成字節(jié)碼
                            byte[] b = strategy.generate(this);
                            String className = ClassNameReader.getClassName(new ClassReader(b));
                            getClassNameCache(loader).add(className);
                            gen = ReflectUtils.defineClass(className, b, loader);
                        }
                       
                        if (useCache) {
                            //將生成的增強(qiáng)類(lèi)添加到緩存中
                            cache2.put(key, new WeakReference(gen));
                        }
                        //創(chuàng)建增強(qiáng)類(lèi)對(duì)象
                        return firstInstance(gen);
                    } finally {
                        CURRENT.set(save);
                    }
                }
            }
            return firstInstance(gen);
        } catch (RuntimeException e) {
            throw e;
        } catch (Error e) {
            throw e;
        } catch (Exception e) {
            throw new CodeGenerationException(e);
        }
    }
    
  • 在創(chuàng)建完增強(qiáng)類(lèi)之后庶灿,就是創(chuàng)建對(duì)象的過(guò)程,設(shè)置classOnly=true可以只生成增強(qiáng)類(lèi)而不生成對(duì)象

    protected Object firstInstance(Class type) throws Exception {
        if (classOnly) {
            return type;
        } else {
            return createUsingReflection(type);
        }
    }
    
  • 反射創(chuàng)建增強(qiáng)類(lèi)對(duì)象吃衅,然后給對(duì)象的Callbacks參數(shù)賦值跳仿,通過(guò)Callback實(shí)現(xiàn)對(duì)方法的增強(qiáng)或者覆蓋

    private Object createUsingReflection(Class type) {
        setThreadCallbacks(type, callbacks);//設(shè)置Callback
        try{
            if (argumentTypes != null) {//創(chuàng)建對(duì)象
                return ReflectUtils.newInstance(type, argumentTypes, arguments);
            } else {//創(chuàng)建對(duì)象
                return ReflectUtils.newInstance(type);
            }
        }finally{
         // clear thread callbacks to allow them to be gc'd
         setThreadCallbacks(type, null);
        }
    }
    
  • 通過(guò)反射將Callback參數(shù)賦值到增強(qiáng)類(lèi)對(duì)象中

    private static void setCallbacksHelper(Class type, Callback[] callbacks, String methodName) {
        // TODO: optimize
        try {
            Method setter = getCallbacksSetter(type, methodName);
            setter.invoke(null, new Object[]{ callbacks });
        } catch (NoSuchMethodException e) {
         //...
        }
    }
    
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市捐晶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌妄辩,老刑警劉巖惑灵,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異眼耀,居然都是意外死亡英支,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)哮伟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)干花,“玉大人妄帘,你說(shuō)我怎么就攤上這事〕仄啵” “怎么了抡驼?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)肿仑。 經(jīng)常有香客問(wèn)我致盟,道長(zhǎng),這世上最難降的妖魔是什么尤慰? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任馏锡,我火速辦了婚禮,結(jié)果婚禮上伟端,老公的妹妹穿的比我還像新娘杯道。我一直安慰自己,他們只是感情好责蝠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布党巾。 她就那樣靜靜地躺著,像睡著了一般玛歌。 火紅的嫁衣襯著肌膚如雪昧港。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,165評(píng)論 1 299
  • 那天支子,我揣著相機(jī)與錄音创肥,去河邊找鬼。 笑死值朋,一個(gè)胖子當(dāng)著我的面吹牛叹侄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播昨登,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼趾代,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了丰辣?” 一聲冷哼從身側(cè)響起撒强,我...
    開(kāi)封第一講書(shū)人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎笙什,沒(méi)想到半個(gè)月后飘哨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡琐凭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年芽隆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡胚吁,死狀恐怖牙躺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情腕扶,我是刑警寧澤孽拷,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站蕉毯,受9級(jí)特大地震影響乓搬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜代虾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一进肯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧棉磨,春花似錦江掩、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至衙傀,卻和暖如春抬吟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背统抬。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工火本, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人聪建。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓钙畔,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親金麸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子擎析,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353