(轉(zhuǎn)載)Java設(shè)計模式之代理模式

volatile_logo

設(shè)計模式是語言的表達方式挎狸,它能讓語言輕便而富有內(nèi)涵部翘、易讀卻功能強大搂根。代理模式在Java中十分常見珍促,有為擴展某些類的功能而使用靜態(tài)代理,也有如Spring實現(xiàn)AOP而使用動態(tài)代理兄墅,更有RPC實現(xiàn)中使用的調(diào)用端調(diào)用的代理服務(wù)踢星。代理模型除了是一種設(shè)計模式之外,它更是一種思維隙咸,所以探討并深入理解這種模型是非常有必要的沐悦。


本文轉(zhuǎn)載自

  • Java的三種代理模式

  • 淺析JAVA設(shè)計模式之代理模式(七)

    代理(Proxy)是一種設(shè)計模式,提供了對目標對象另外的訪問方式;即通過代理對象訪問目標對象.這樣做的好處是:可以在目標對象實現(xiàn)的基礎(chǔ)上,增強額外的功能操作,即擴展目標對象的功能.這里使用到編程中的一個思想:不要隨意去修改別人已經(jīng)寫好的代碼或者方法,如果需改修改,可以通過代理的方式來擴展該方法。

    代理模式的關(guān)鍵點是:代理對象與目標對象.代理對象是對目標對象的擴展,并會調(diào)用目標對象

    代理的實現(xiàn)可以分為靜態(tài)代理和動態(tài)代理五督,動態(tài)代理又分為JDK動態(tài)代理和CGlib動態(tài)代理藏否,下面我們依次來說明一下這三種方式:

一、靜態(tài)代理

靜態(tài)代理在使用時,需要定義接口或者父類,被代理對象與代理對象一起實現(xiàn)相同的接口或者是繼承相同父類.

下面舉個案例來解釋:
模擬保存動作,定義一個保存動作的接口:IUserDao.java,然后目標對象實現(xiàn)這個接口的方法UserDao.java,此時如果使用靜態(tài)代理方式,就需要在代理對象(UserDaoProxy.java)中也實現(xiàn)IUserDao接口.調(diào)用的時候通過調(diào)用代理對象的方法來調(diào)用目標對象.
需要注意的是,代理對象與目標對象要實現(xiàn)相同的接口,然后通過調(diào)用相同的方法來調(diào)用目標對象的方法.
代碼示例:
接口:IUserDao.java

/**
 * 接口
 */
public interface IUserDao {

    void save();
}

目標對象:UserDao.java

/**
 * 接口實現(xiàn)
 * 目標對象
 */
public class UserDao implements IUserDao {
    public void save() {
        System.out.println("----已經(jīng)保存數(shù)據(jù)!----");
    }
}

代理對象:UserDaoProxy.java

/**
 * 代理對象,靜態(tài)代理
 */
public class UserDaoProxy implements IUserDao{
    //接收保存目標對象
    private IUserDao target;
    public UserDaoProxy(IUserDao target){
        this.target=target;
    }

    public void save() {
        System.out.println("開始事務(wù)...");
        target.save();//執(zhí)行目標對象的方法
        System.out.println("提交事務(wù)...");
    }
}

測試類:App.java

/**
 * 測試類
 */
public class App {
    public static void main(String[] args) {
        //目標對象
        UserDao target = new UserDao();

        //代理對象,把目標對象傳給代理對象,建立代理關(guān)系
        UserDaoProxy proxy = new UserDaoProxy(target);

        proxy.save();//執(zhí)行的是代理的方法
    }
}

靜態(tài)代理總結(jié):
1.可以做到在不修改目標對象的功能前提下,對目標功能擴展.
2.缺點:
因為代理對象需要與目標對象實現(xiàn)一樣的接口,所以會有很多代理類,類太多.同時,一旦接口增加方法,目標對象與代理對象都要維護.

如何解決靜態(tài)代理中的缺點呢?答案是可以使用動態(tài)代理方式.

二充包、JDK動態(tài)代理

動態(tài)代理有以下特點:
1.代理對象,不需要實現(xiàn)接口
2.代理對象的生成,是利用JDK的API,動態(tài)的在內(nèi)存中構(gòu)建代理對象(需要我們指定創(chuàng)建代理對象/目標對象實現(xiàn)的接口的類型)
3.動態(tài)代理也叫做:JDK代理,接口代理

JDK中生成代理對象的API
代理類所在包:java.lang.reflect.Proxy
JDK實現(xiàn)代理只需要使用newProxyInstance方法,但是該方法需要接收三個參數(shù),完整的寫法是:

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )

注意該方法是在Proxy類中是靜態(tài)方法,且接收的三個參數(shù)依次為:

  • ClassLoader loader,:指定當前目標對象使用類加載器,獲取加載器的方法是固定的
  • Class<?>[] interfaces,:目標對象實現(xiàn)的接口的類型,使用泛型方式確認類型
  • InvocationHandler h:事件處理,執(zhí)行目標對象的方法時,會觸發(fā)事件處理器的方法,會把當前執(zhí)行目標對象的方法作為參數(shù)傳入
    代碼示例:
    接口類IUserDao.java以及接口實現(xiàn)類,目標對象UserDao是一樣的,沒有做修改.在這個基礎(chǔ)上,增加一個代理工廠類(ProxyFactory.java),將代理類寫在這個地方,然后在測試類(需要使用到代理的代碼)中先建立目標對象和代理對象的聯(lián)系,然后代用代理對象的中同名方法

代理工廠類:ProxyFactory.java

/**
 * 創(chuàng)建動態(tài)代理對象
 * 動態(tài)代理不需要實現(xiàn)接口,但是需要指定接口類型
 */
public class ProxyFactory{

    //維護一個目標對象
    private Object target;
    public ProxyFactory(Object target){
        this.target=target;
    }

   //給目標對象生成代理對象
    public Object getProxyInstance(){
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("開始事務(wù)2");
                        //執(zhí)行目標對象方法
                        Object returnValue = method.invoke(target, args);
                        System.out.println("提交事務(wù)2");
                        return returnValue;
                    }
                }
        );
    }

}

測試類:App.java

/**
 * 測試類
 */
public class App {
    public static void main(String[] args) {
        // 目標對象
        IUserDao target = new UserDao();
        // 【原始的類型 class cn.itcast.b_dynamic.UserDao】
        System.out.println(target.getClass());

        // 給目標對象副签,創(chuàng)建代理對象
        IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
        // class $Proxy0   內(nèi)存中動態(tài)生成的代理對象
        System.out.println(proxy.getClass());

        // 執(zhí)行方法   【代理對象】
        proxy.save();
    }
}

總結(jié):
代理對象不需要實現(xiàn)接口,但是目標對象一定要實現(xiàn)接口,否則不能用動態(tài)代理

二、CGLIB代理

CGLIB概述

上面的靜態(tài)代理和動態(tài)代理模式都是要求目標對象是實現(xiàn)一個接口的目標對象,但是有時候目標對象只是一個單獨的對象,并沒有實現(xiàn)任何的接口,這個時候就可以使用以目標對象子類的方式類實現(xiàn)代理,這種方法就叫做:Cglib代理

CGLIB也提供了一個處理器接口(這里成為回調(diào)接口)net.sf.cglib.proxy.MethodInterceptor(相當于JDK代理的InvocationHandler接口)基矮,它自定義了一個intercept方法(相當于JDK代理的invoke方法)淆储,用于集中處理在動態(tài)代理類對象上的方法調(diào)用,通常在該方法中實現(xiàn)對委托類的代理訪問家浇。

        // 該方法負責(zé)集中處理動態(tài)代理類上的所有方法調(diào)用本砰。第一個參數(shù)是代理類對象,第二個參數(shù)是委托類被調(diào)用的方法的類對象
       // 第三個是該方法的參數(shù)钢悲,第四個是生成在代理類里面点额,除了方法名不同,其他都和被代理方法一樣的(參數(shù)莺琳,方法體里面的東西)一個方法的類對象还棱。
       public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodproxy) throws Throwable

然后CGLIB也提供了一個生成代理類的類net.sf.cglib.proxy.Enhancer(相當于JDK代理的java.lang.reflect.Proxy),它提供了一組靜態(tài)方法來為一組接口動態(tài)地生成代理類及其對象惭等。本文創(chuàng)建代理用到的Enhancer的靜態(tài)方法如下:

public Object intercept(Object proxy,Method method, Object[] args,  MethodProxy methodproxy) throws Throwable
       //為指定類裝載器珍手、接口及調(diào)用處理器生成動態(tài)代理類實例
       public static  Object create(Class class ,Callback callback h){}
       public static  Object create(Class class,Class[] interfaces,Callback h){}
       public static Object create(Classclass, Class[] interfaces, CallbackFilter filter, Callback[] hs)
       public Object create(Class[] argumentTypes, Object[] arguments){}

這個create方法相當于JDK代理的newProxyInstance方法,該方法的參數(shù)具體含義如下:

  • Class class:指定一個被代理類的類對象。
  • Class[]interfaces:如果要代理接口琳要,指定一組被代理類實現(xiàn)的所有接口的類對象料扰。
  • Callback h:指定一個實現(xiàn)了處理器接口(這里稱回調(diào)接口)的對象。
  • CallbackFilter filter:指定一個方法過濾器焙蹭。
  • Callback[]hs:指定一組實現(xiàn)了處理器接口的對象。
  • Class[] argumentTypes:指定某個構(gòu)造器的參數(shù)類型
  • Object[] arguments:指定某個gouz

如何使用嫂伞?

  1. 通過實現(xiàn) MethodInterceptor接口創(chuàng)建自己的處理器孔厉;
  2. 通過給Enhancer類的create()方法傳進被代理類的類對象、實現(xiàn)了MethodInterceptor接口的處理器對象帖努,得到一個代理類對 象撰豺。
  3. 其中Enhancer類通過反射機制獲得代理類的構(gòu)造函數(shù),有一個參數(shù)類型是處理器接口類型拼余。
  4. Enhancer類再通過構(gòu)造函數(shù)對象創(chuàng)建動態(tài)代理類實例污桦,構(gòu)造時處理器對象作為參數(shù)被傳入。
  5. 當客戶端調(diào)用了代理類的方法時匙监,該方法調(diào)用了處理器的intercept()方法并給intercept()方法傳進委托類方法的類對象凡橱,intercept方法再調(diào)用委托類的真實方法。
    (1)建一個reallyCglibProxy包亭姥,所有程序都放在該包下稼钩,我在Spring的包庫里面找到兩個包:asm.jar和cblib-2.1.3.jar,最好在Spring里面同時拷貝這兩個包到項目的類庫下达罗,不要分別從網(wǎng)上下載坝撑,可能會沖突。
    (2)建一個被代理類(RealSubject.java)粮揉。
package reallyCglibProxy;
//被代理類
public class RealSubject {
    public void print() {
        System.out.println("被代理的人郭襄");
    }
}

(3)建一個用戶自定義的處理器類LogHandler.java巡李,需要實現(xiàn)處理接口,在intercept()方法里寫上被代理類的方法調(diào)用前后要進行的動作扶认。這個intercept()方法我們不用直接調(diào)用侨拦,是讓將來自動生成的代理類去調(diào)用的。

package reallyCglibProxy;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import jdkDynamicProxy.LonHanderReflectTool;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
 
//相當于實現(xiàn)jdk的InvocationHandler接口
public class LogHandler implements MethodInterceptor{
    private Object delegate; //被代理類的對象
    //綁定被代理類的對象
    public Object bind(Object delegate)throws Exception{
        this.delegate=delegate;
    return Enhancer.create(delegate.getClass(),this);
    }  
    //相當于InvocationHandler接口里面的invoke()方法
    @Override
    public Object intercept(Object proxy, Method method, Object[] args,
            MethodProxy methodproxy) throws Throwable {
        Object result=null;
        System.out.println("我是代理人郭靖蝠引,開始代理");
        
        //method.invoke()或者methodproxy.invoke()都可以
        result=method.invoke(delegate,args);
        //result=methodproxy.invoke(delegate,args);
        System.out.println("我是代理人郭靖阳谍,代理完畢");
 
        //調(diào)用工具類反射jdk的Proxy生成的代理類,可參考《五》中這個工具類
        LonHanderReflectTool.ReflectClass(proxy.getClass().getName());
        return result;
    }
}

(4)編寫測試客戶端(TestReallyCglibProxy.java)螃概。

package reallyCglibProxy;
public class TestReallyCglibProxy {
    public static void main(String[] args)throws Exception {
        RealSubject sub1=new RealSubject();
        LogHandler hander=new LogHandler();
        RealSubject sub2=(RealSubject)hander.bind(sub1);
        sub2.print();
    }
}

輸出結(jié)果:

我是代理人郭靖矫夯,開始代理

被代理的人郭襄

我是代理人郭靖,代理完畢

從結(jié)果可以看出吊洼,成功自動生成了代理類RealSubjectEnhancerByCGLIB48574fb2训貌,并成功實現(xiàn)了代理的效果,而且還代理了RealSubject類從父類繼承的finalize、equals递沪、toString豺鼻、hashCode、clone這幾個方法款慨。

CBLIB方法過濾器

如果現(xiàn)在有個要求儒飒,被代理類的print方法不用處理。當最簡單的方式是修改方法攔截器(即intercept方法)檩奠,在里面進行判斷桩了,如果是print()方法就不做任何邏輯處理,直接調(diào)用埠戳,這樣子使得編寫攔截器(相當于JDK代理里的處理器)邏輯變復(fù)雜井誉,不易維護。我們可以使用CGLIB提供的方法過濾器(CallbackFilter)整胃,使得被代理類中不同的方法颗圣,根據(jù)我們的邏輯要求,調(diào)用不同的處理器屁使,從而使用不同的攔截方法(處理器方法)在岂。
基本步驟如下:
(1)修改一下被代理類(RealSubject.java),增加一個方法print2屋灌。

package reallyCglibProxy;
//被代理類
public class RealSubject {
    public void print() {
        System.out.println("被代理的人郭襄");
    }
    public void print2() {
        System.out.println("我是print2方法哦");
    }
}

(2)新建一個用戶自定義的方法過濾器類MyProxyFilter.java洁段。

package reallyCglibProxy;
 
import java.lang.reflect.Method;
 
import net.sf.cglib.proxy.Callback;
 
import net.sf.cglib.proxy.CallbackFilter;
 
import net.sf.cglib.proxy.NoOp;
 
//自定義方法過濾器類
 
public class MyProxyFilterimplements CallbackFilter {
 
    public int accept(Method method) {
 
    /**
    *這句話可發(fā)現(xiàn),所有被代理的方法都會被過濾一次共郭。Enhancer的源代碼中看到下面一段代碼
    while(it1.hasNext()){
    MethodInfomethod=(MethodInfo)it1.next();
    MethodactualMethod=(it2!=null)?(Method)it2.next():null;
    intindex=filter.accept(actualMethod);
    if(index>=callbackTypes.length){
    thrownewIllegalArgumentException("Callbackfilterreturnedanindexthatistoolarge:"+index);
    }
    上段代碼可以看到所有的被代理的方法祠丝,本例子中就是print、print2除嘹、從父類繼承的finalize写半、equals、toString尉咕、
    hashCode叠蝇、clone這幾個方法)都被調(diào)用accept方法進行過濾,給每個方法返回一個整數(shù)年缎,
    本例子是0或者1悔捶,從而選擇不同的處理器。
    */
 
System.out.println(method.getDeclaringClass()+"類的"+method.getName()+"方法被檢查過濾单芜!");
 
    /* 
    如果調(diào)用是print方法蜕该,則要調(diào)用0號位的攔截器去處理
         */
 
    if("print".equals(method.getName()))   
 
    //0號位即LogHandler里面 new Callback[]{this,NoOp.INSTANCE}中的this,它在這個數(shù)組第0位置
 
return 1; 
 
    /*     
      1號位即LogHandler里面 new Callback[]{this,NoOp.INSTANCE}中的NoOp.INSTANCE洲鸠,它在這個數(shù)組第1位置堂淡。
    NoOp.INSTANCE是指不做任何事情的攔截器馋缅。
在這里就是任何人都有權(quán)限訪問print方法,即這個方法沒有代理绢淀,直接調(diào)用
     */
 
return 0;   
 
    }
 
}

(3)修改一下用戶自定義的處理器類LogHandler.java

package reallyCglibProxy;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import jdkDynamicProxy.LonHanderReflectTool;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.NoOp;
//相當于實現(xiàn)jdk的InvocationHandler接口
public class LogHandler implements MethodInterceptor{
    private Object delegate; //被代理類的對象
    //綁定被代理類的對象
    public Object bind(Object delegate)throws Exception{
        this.delegate=delegate;
    /**
     *傳進不同的攔截器(相當于JDK代理里面的處理器),NoOp.INSTANCE是cglib已經(jīng)寫好的不做任何事情的攔截器萤悴,傳進去的new Callback[]是一個數(shù)組,現(xiàn)在數(shù)組有兩個攔截器對象皆的,分別是this,和NoOp.INSTANCE覆履,它們分別在數(shù)組的第0位和第一位對應(yīng)著自定義過濾器MyProxyFilter里的accept方法返回的整數(shù),如果是0就調(diào)用this攔截器费薄,如果是1就調(diào)用NoOp.INSTANCE所以自定義過濾器MyProxyFilter里的accept方法返回的整數(shù)最大就是攔截器數(shù)組的長度内狗,比如本例子當中,只能是0或者1义锥,不能是2,因為這個數(shù)組只有兩個元素岩灭,最大位置就是1號位拌倍。
     */
    return Enhancer.create(delegate.getClass(), null, new MyProxyFilter(), new Callback[]{this,NoOp.INSTANCE}); 
    }  
    //相當于InvocationHandler接口里面的invoke()方法
    
    public Object intercept(Object proxy, Method method, Object[] args,
            MethodProxy methodproxy) throws Throwable {
        Object result=null;
        System.out.println("我是代理人郭靖,開始代理");
        
        //method.invoke()或者methodproxy.invoke()都可以
        result=method.invoke(delegate,args);
        //result=methodproxy.invoke(delegate,args);
        System.out.println("我是代理人郭靖噪径,代理完畢");
 
        //調(diào)用工具類反射jdk的Proxy生成的代理類柱恤,可參考《五》中這個工具類
        //LonHanderReflectTool.ReflectClass(proxy.getClass().getName());
        return result;
    }
}

(4) 修改測試客戶端(TestReallyCglibProxy.java)。

package reallyCglibProxy;
publicclass TestReallyCglibProxy {
    publicstaticvoid main(String[] args)throws Exception {
        RealSubject sub1=new RealSubject();
        LogHandler hander=new LogHandler();
        RealSubject sub2=(RealSubject)hander.bind(sub1);
        sub2.print();
        sub2.print2();
    }
}

輸出結(jié)果:

class reallyCglibProxy.RealSubject類的print2方法被檢查過濾找爱!

class reallyCglibProxy.RealSubject類的print方法被檢查過濾梗顺!

class java.lang.Object類的finalize方法被檢查過濾!

class java.lang.Object類的equals方法被檢查過濾车摄!

class java.lang.Object類的toString方法被檢查過濾寺谤!

class java.lang.Object類的hashCode方法被檢查過濾!

class java.lang.Object類的clone方法被檢查過濾吮播!

被代理的人郭襄

我是代理人郭靖变屁,開始代理

我是print2方法哦

我是代理人郭靖,代理完畢
   從結(jié)果可以看出意狠,print方法沒有被代理粟关,print2方法被代理了,有了方法過濾器环戈,被代理類被代理的方法(本文例子中就是print闷板、print2、從父類繼承的finalize院塞、equals遮晚、toString、hashCode迫悠、clone這幾個方法)都被調(diào)用accept方法進行過濾鹏漆,給每個方法返回一個整數(shù),本例子是0或者1,從而選擇不同的處理器艺玲。

參考文章


本文作者: catalinaLi
本文鏈接: http://catalinali.top/2018/proxyPattern/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末括蝠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子饭聚,更是在濱河造成了極大的恐慌忌警,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秒梳,死亡現(xiàn)場離奇詭異法绵,居然都是意外死亡,警方通過查閱死者的電腦和手機酪碘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門朋譬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人兴垦,你說我怎么就攤上這事徙赢。” “怎么了探越?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵狡赐,是天一觀的道長。 經(jīng)常有香客問我钦幔,道長枕屉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任鲤氢,我火速辦了婚禮搀擂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘卷玉。我一直安慰自己哥倔,他們只是感情好,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布揍庄。 她就那樣靜靜地躺著咆蒿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蚂子。 梳的紋絲不亂的頭發(fā)上沃测,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機與錄音食茎,去河邊找鬼蒂破。 笑死,一個胖子當著我的面吹牛别渔,可吹牛的內(nèi)容都是我干的附迷。 我是一名探鬼主播惧互,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼喇伯!你這毒婦竟也來了喊儡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤稻据,失蹤者是張志新(化名)和其女友劉穎艾猜,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捻悯,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡匆赃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了今缚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片算柳。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖姓言,靈堂內(nèi)的尸體忽然破棺而出埠居,到底是詐尸還是另有隱情,我是刑警寧澤事期,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站纸颜,受9級特大地震影響兽泣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜胁孙,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一唠倦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧涮较,春花似錦稠鼻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至闺属,卻和暖如春慌盯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掂器。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工亚皂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人国瓮。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓灭必,卻偏偏與公主長得像狞谱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子禁漓,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容