Spring注解之五AOP

個人專題目錄


1.5. AOP

  • 核心業(yè)務(wù)功能和切面功能分別獨立進行開發(fā) ,然后把切面功能和核心業(yè)務(wù)功能 "編織" 在一起茄螃,這就叫AOP
  • 讓關(guān)注點代碼與業(yè)務(wù)代碼分離
  • 面向切面編程就是指: 對很多功能都有的重復(fù)的代碼抽取缝驳,再在運行的時候往業(yè)務(wù)方法上動態(tài)植入“切面類代碼”。
  • 應(yīng)用場景:日志归苍,事務(wù)管理用狱,權(quán)限控制AOP注解使用

代理分類

  • jdk動態(tài)代理
    • 主要通過Proxy.newProxyInstance()和InvocationHandler這兩個類和方法實現(xiàn)
    • 創(chuàng)建代理類proxy實現(xiàn)Invocation接口,重寫invoke()方法
      • 調(diào)用被代理類方法時默認調(diào)用此方法
    • 將被代理類作為構(gòu)造函數(shù)的參數(shù)傳入代理類proxy
    • 調(diào)用Proxy.newProxyInsatnce(classloader,interfaces,handler)方法生成代理類
      • 生成的代理類
        • $Proxy0 extends Proxy implements Person
        • 類型為$Proxy0
        • 因為已經(jīng)繼承了Proxy,所以java動態(tài)代理只能對接口進行代理
      • 代理對象會實現(xiàn)用戶提供的這組接口霜医,因此可以將這個代理對象強制類型轉(zhuǎn)化為這組接口中的任意一個
      • 通過反射生成對象
    • 總結(jié): 代理類調(diào)用自己方法時齿拂,通過自身持有的中介類對象來調(diào)用中介類對象的invoke方法,從而達到代理執(zhí)行被代理對象的方法肴敛。
  • cglib
    • 生成對象類型為Enhancer
    • 實現(xiàn)原理類似于 jdk 動態(tài)代理署海,只是他在運行期間生成的代理對象是針
      對目標(biāo)類擴展的子類
  • 靜態(tài)代理
    • 缺點
      • 如果要代理一個接口的多個實現(xiàn)的話需要定義不同的代理類
      • 代理類 和 被代理類 必須實現(xiàn)同樣的接口,萬一接口有變動医男,代理砸狞、被代理類都得修改
    • 在編譯的時候就直接生成代理類
  • JDK動態(tài)代理和cglib的對比
    • CGLib所創(chuàng)建的動態(tài)代理對象在實際運行時候的性能要比JDK動態(tài)代理高
      • 1.6和1.7的時候,CGLib更快
      • 1.8的時候镀梭,jdk更快
    • CGLib在創(chuàng)建對象的時候所花費的時間卻比JDK動態(tài)代理多
    • singleton的代理對象或者具有實例池的代理刀森,因為無需頻繁的創(chuàng)建代理對象,所以比較適合采用CGLib動態(tài)代理报账,反之研底,則適合用JDK動態(tài)代理
    • JDK動態(tài)代理是面向接口的,CGLib動態(tài)代理是通過字節(jié)碼底層繼承代理類來實現(xiàn)(如果被代理類被final關(guān)鍵字所修飾透罢,那么會失敯窕蕖)
    • JDK生成的代理類類型是Proxy(因為繼承的是Proxy),CGLIB生成的代理類類型是Enhancer類型
    • 如果要被代理的對象是個實現(xiàn)類羽圃,那么Spring會使用JDK動態(tài)代理來完成操作(Spirng默認采用JDK動態(tài)代理實現(xiàn)機制)乾胶;
      如果要被代理的對象不是實現(xiàn)類,那么Spring會強制使用CGLib來實現(xiàn)動態(tài)代理朽寞。

AOP注解使用

  • AOP:【動態(tài)代理】
    • 指在程序運行期間動態(tài)的將某段代碼切入到指定方法指定位置進行運行的編程方式识窿;
  1. 導(dǎo)入aop模塊;Spring AOP:(spring-aspects)
  2. 定義一個業(yè)務(wù)邏輯類(MathCalculator)脑融;在業(yè)務(wù)邏輯運行的時候?qū)⑷罩具M行打佑髌怠(方法之前、方法運行結(jié)束吨掌、方法出現(xiàn)異常半抱,xxx)
  3. 定義一個日志切面類(LogAspects):切面類里面的方法需要動態(tài)感知MathCalculator.div運行到哪里然后執(zhí)行脓恕;
    1. 通知方法:
      1. 前置通知(@Before):logStart:在目標(biāo)方法(div)運行之前運行
      2. 后置通知(@After):logEnd:在目標(biāo)方法(div)運行結(jié)束之后運行(無論方法正常結(jié)束還是異常結(jié)束)
      3. 返回通知(@AfterReturning):logReturn:在目標(biāo)方法(div)正常返回之后運行
      4. 異常通知(@AfterThrowing):logException:在目標(biāo)方法(div)出現(xiàn)異常以后運行
      5. 環(huán)繞通知(@Around):動態(tài)代理,手動推進目標(biāo)方法運行(joinPoint.procced())
  4. 給切面類的目標(biāo)方法標(biāo)注何時何地運行(通知注解)窿侈;
  5. 將切面類和業(yè)務(wù)邏輯類(目標(biāo)方法所在類)都加入到容器中;
  6. 必須告訴Spring哪個類是切面類(給切面類上加一個注解:@Aspect)
  7. 給配置類中加 @EnableAspectJAutoProxy 【開啟基于注解的aop模式】炼幔,在Spring中很多的 @EnableXXX;
public class MathCalculator {

    public int div(int i, int j) {
        System.out.println("MathCalculator...div...");
        return i / j;
    }
}
/**
 * 切面類
 *
 * @author xubh
 * @Aspect: 告訴Spring當(dāng)前類是一個切面類
 */
@Aspect
public class LogAspects {

    //抽取公共的切入點表達式
    //1、本類引用
    //2史简、其他的切面引用
    @Pointcut("execution(public int com.xubh.aop.MathCalculator.*(..))")
    public void pointCut() {
    }

    ;

    //@Before在目標(biāo)方法之前切入乃秀;切入點表達式(指定在哪個方法切入)
    @Before("pointCut()")
    public void logStart(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        System.out.println("" + joinPoint.getSignature().getName() + "運行。圆兵。跺讯。@Before:參數(shù)列表是:{" + Arrays.asList(args) + "}");
    }

    @After("com.xubh.aop.LogAspects.pointCut()")
    public void logEnd(JoinPoint joinPoint) {
        System.out.println("" + joinPoint.getSignature().getName() + "結(jié)束。殉农。刀脏。@After");
    }

    //JoinPoint一定要出現(xiàn)在參數(shù)表的第一位
    @AfterReturning(value = "pointCut()", returning = "result")
    public void logReturn(JoinPoint joinPoint, Object result) {
        System.out.println("" + joinPoint.getSignature().getName() + "正常返回。超凳。愈污。@AfterReturning:運行結(jié)果:{" + result + "}");
    }

    @AfterThrowing(value = "pointCut()", throwing = "exception")
    public void logException(JoinPoint joinPoint, Exception exception) {
        System.out.println("" + joinPoint.getSignature().getName() + "異常。轮傍。暂雹。異常信息:{" + exception + "}");
    }

}
/**
 * AOP:【動態(tài)代理】
 * 三步:
 * 1)、將業(yè)務(wù)邏輯組件和切面類都加入到容器中创夜;告訴Spring哪個是切面類(@Aspect)
 * 2)杭跪、在切面類上的每一個通知方法上標(biāo)注通知注解,告訴Spring何時何地運行(切入點表達式)
 * 3)驰吓、開啟基于注解的aop模式涧尿;@EnableAspectJAutoProxy
 */
@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {

    //業(yè)務(wù)邏輯類加入容器中
    @Bean
    public MathCalculator calculator() {
        return new MathCalculator();
    }

    //切面類加入到容器中
    @Bean
    public LogAspects logAspects() {
        return new LogAspects();
    }
}
public class IOCTest_AOP {

    @Test
    public void test01(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);

        //1、不要自己創(chuàng)建對象
//      MathCalculator mathCalculator = new MathCalculator();
//      mathCalculator.div(1, 1);
        MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);

        mathCalculator.div(1, 0);

        applicationContext.close();
    }

}

AOP原理-@EnableAspectJAutoProxy

  • AOP原理:【看給容器中注冊了什么組件檬贰,這個組件什么時候工作现斋,這個組件的功能是什么?】@EnableAspectJAutoProxy偎蘸;
  1. @EnableAspectJAutoProxy是什么?

    @Import(AspectJAutoProxyRegistrar.class):給容器中導(dǎo)入AspectJAutoProxyRegistrar

         利用AspectJAutoProxyRegistrar自定義給容器中注冊bean瞬内;BeanDefinetion
    
         internalAutoProxyCreator=AnnotationAwareAspectJAutoProxyCreator
    
    給容器中注冊一個AnnotationAwareAspectJAutoProxyCreator迷雪;
    
  2. AnnotationAwareAspectJAutoProxyCreator:

    AnnotationAwareAspectJAutoProxyCreator

     ->AspectJAwareAdvisorAutoProxyCreator
    
          ->AbstractAdvisorAutoProxyCreator
    
                 ->AbstractAutoProxyCreator
    
                         implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
    
                 關(guān)注后置處理器(在bean初始化完成前后做事情)、自動裝配BeanFactory
    

AOP原理-AnnotationAwareAspectJAutoProxyCreator分析

AbstractAutoProxyCreator.setBeanFactory()
  AbstractAutoProxyCreator.有后置處理器的邏輯虫蝶;
  
  AbstractAdvisorAutoProxyCreator.setBeanFactory()->initBeanFactory()
 
  AnnotationAwareAspectJAutoProxyCreator.initBeanFactory()

AOP原理-注冊AnnotationAwareAspectJAutoProxyCreator

流程:

  1. 傳入配置類章咧,創(chuàng)建ioc容器

  2. 注冊配置類,調(diào)用refresh()刷新容器能真;

  3. registerBeanPostProcessors(beanFactory);注冊bean的后置處理器來方便攔截bean的創(chuàng)建赁严;

    1. 先獲取ioc容器已經(jīng)定義了的需要創(chuàng)建對象的所有BeanPostProcessor
    2. 給容器中加別的BeanPostProcessor
    3. 優(yōu)先注冊實現(xiàn)了PriorityOrdered接口的BeanPostProcessor扰柠;
    4. 再給容器中注冊實現(xiàn)了Ordered接口的BeanPostProcessor;
    5. 注冊沒實現(xiàn)優(yōu)先級接口的BeanPostProcessor疼约;
    6. 注冊BeanPostProcessor卤档,實際上就是創(chuàng)建BeanPostProcessor對象,保存在容器中程剥; 創(chuàng)建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】
      1. 創(chuàng)建Bean的實例
      2. populateBean劝枣;給bean的各種屬性賦值
      3. initializeBean:初始化bean;
        1. invokeAwareMethods():處理Aware接口的方法回調(diào)
        2. applyBeanPostProcessorsBeforeInitialization():應(yīng)用后置處理器的postProcessBeforeInitialization()
        3. invokeInitMethods()织鲸;執(zhí)行自定義的初始化方法
        4. applyBeanPostProcessorsAfterInitialization()舔腾;執(zhí)行后置處理器的postProcessAfterInitialization();
      4. BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)創(chuàng)建成功搂擦; -->aspectJAdvisorsBuilder
    7. 把BeanPostProcessor注冊到BeanFactory中;beanFactory.addBeanPostProcessor(postProcessor);

    =======以上是創(chuàng)建和注冊AnnotationAwareAspectJAutoProxyCreator的過程========

    AOP原理-AnnotationAwareAspectJAutoProxyCreator執(zhí)行時機

  4. finishBeanFactoryInitialization(beanFactory);完成BeanFactory初始化工作稳诚;創(chuàng)建剩下的單實例bean

    1. 遍歷獲取容器中所有的Bean,依次創(chuàng)建對象getBean(beanName);

      1. getBean->doGetBean()->getSingleton()->
    2. 創(chuàng)建bean瀑踢,【AnnotationAwareAspectJAutoProxyCreator在所有bean創(chuàng)建之前會有一個攔截扳还,InstantiationAwareBeanPostProcessor,會調(diào)用postProcessBeforeInstantiation()】

      1. 先從緩存中獲取當(dāng)前bean丘损,如果能獲取到普办,說明bean是之前被創(chuàng)建過的,直接使用徘钥,否則再創(chuàng)建衔蹲;只要創(chuàng)建好的Bean都會被緩存起來

      2. createBean();創(chuàng)建bean;AnnotationAwareAspectJAutoProxyCreator 會在任何bean創(chuàng)建之前先嘗試返回bean的實例呈础;【BeanPostProcessor是在Bean對象創(chuàng)建完成初始化前后調(diào)用的】【InstantiationAwareBeanPostProcessor是在創(chuàng)建Bean實例之前先嘗試用后置處理器返回對象的】

        1. resolveBeforeInstantiation(beanName, mbdToUse);解析BeforeInstantiation舆驶;希望后置處理器在此能返回一個代理對象;如果能返回代理對象就使用而钞,如果不能就繼續(xù)

          1. 后置處理器先嘗試返回對象沙廉;
          bean = applyBeanPostProcessorsBeforeInstantiation():
          拿到所有后置處理器,如果是InstantiationAwareBeanPostProcessor;
          就執(zhí)行postProcessBeforeInstantiation
          if (bean != null) {
              bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
          }
          
        2. doCreateBean(beanName, mbdToUse, args);真正的去創(chuàng)建一個bean實例臼节;和3.6流程一樣撬陵;

AOP原理-AnnotationAwareAspectJAutoProxyCreator執(zhí)行時機

 參考上面步驟4

AOP原理-創(chuàng)建AOP代理

  • AnnotationAwareAspectJAutoProxyCreator【InstantiationAwareBeanPostProcessor】 的作用:
  1. 每一個bean創(chuàng)建之前,調(diào)用postProcessBeforeInstantiation(); 關(guān)心MathCalculator和LogAspect的創(chuàng)建
    1. 判斷當(dāng)前bean是否在advisedBeans中(保存了所有需要增強bean)
    2. 判斷當(dāng)前bean是否是基礎(chǔ)類型的Advice网缝、Pointcut巨税、Advisor、AopInfrastructureBean粉臊,或者是否是切面(@Aspect)
    3. 是否需要跳過
      1. 獲取候選的增強器(切面里面的通知方法)【List<Advisor> candidateAdvisors】每一個封裝的通知方法的增強器是 InstantiationModelAwarePointcutAdvisor草添;判斷每一個增強器是否是 AspectJPointcutAdvisor 類型的;返回true
      2. 永遠返回false
  2. 創(chuàng)建對象,postProcessAfterInitialization扼仲;return wrapIfNecessary(bean, beanName, cacheKey);//包裝如果需要的情況下
    1. 獲取當(dāng)前bean的所有增強器(通知方法) Object[] specificInterceptors
      1. 找到候選的所有的增強器(找哪些通知方法是需要切入當(dāng)前bean方法的)
      2. 獲取到能在bean使用的增強器远寸。
      3. 給增強器排序
    2. 保存當(dāng)前bean在advisedBeans中抄淑;
    3. 如果當(dāng)前bean需要增強,創(chuàng)建當(dāng)前bean的代理對象驰后;
      1. 獲取所有增強器(通知方法)
      2. 保存到proxyFactory
      3. 創(chuàng)建代理對象:Spring自動決定肆资;JdkDynamicAopProxy(config);jdk動態(tài)代理;ObjenesisCglibAopProxy(config);cglib的動態(tài)代理倡怎;
    4. 給容器中返回當(dāng)前組件使用cglib增強了的代理對象迅耘;
    5. 以后容器中獲取到的就是這個組件的代理對象,執(zhí)行目標(biāo)方法的時候监署,代理對象就會執(zhí)行通知方法的流程颤专;

AOP原理-獲取攔截器鏈-MethodInterceptor

  1. 目標(biāo)方法執(zhí)行;容器中保存了組件的代理對象(cglib增強后的對象)钠乏,這個對象里面保存了詳細信息(比如增強器栖秕,目標(biāo)對象,xxx)晓避;
    1. CglibAopProxy.intercept();攔截目標(biāo)方法的執(zhí)行
    2. 根據(jù)ProxyFactory對象獲取將要執(zhí)行的目標(biāo)方法攔截器鏈簇捍;List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      1. List<Object> interceptorList保存所有攔截器 5;一個默認的ExposeInvocationInterceptor 和 4個增強器俏拱;
      2. 遍歷所有的增強器暑塑,將其轉(zhuǎn)為Interceptor;registry.getInterceptors(advisor);
      3. 將增強器轉(zhuǎn)為List<MethodInterceptor>锅必;如果是MethodInterceptor事格,直接加入到集合中;如果不是搞隐,使用AdvisorAdapter將增強器轉(zhuǎn)為MethodInterceptor驹愚;轉(zhuǎn)換完成返回MethodInterceptor數(shù)組;
    3. 如果沒有攔截器鏈劣纲,直接執(zhí)行目標(biāo)方法;攔截器鏈(每一個通知方法又被包裝為方法攔截器逢捺,利用MethodInterceptor機制)
    4. 如果有攔截器鏈,把需要執(zhí)行的目標(biāo)對象癞季,目標(biāo)方法劫瞳,攔截器鏈等信息傳入創(chuàng)建一個 CglibMethodInvocation 對象,并調(diào)用 Object retVal = mi.proceed();
    5. 攔截器鏈的觸發(fā)過程;
      1. 如果沒有攔截器執(zhí)行執(zhí)行目標(biāo)方法绷柒,或者攔截器的索引和攔截器數(shù)組-1大小一樣(指定到了最后一個攔截器)執(zhí)行目標(biāo)方法柠新;
      2. 鏈?zhǔn)将@取每一個攔截器,攔截器執(zhí)行invoke方法辉巡,每一個攔截器等待下一個攔截器執(zhí)行完成返回以后再來執(zhí)行;攔截器鏈的機制蕊退,保證通知方法與目標(biāo)方法的執(zhí)行順序郊楣;

AOP原理-鏈?zhǔn)秸{(diào)用通知方法及總結(jié)

  1. @EnableAspectJAutoProxy 開啟AOP功能
  2. @EnableAspectJAutoProxy 會給容器中注冊一個組件 AnnotationAwareAspectJAutoProxyCreator
  3. AnnotationAwareAspectJAutoProxyCreator是一個后置處理器憔恳;
  4. 容器的創(chuàng)建流程:
    1. registerBeanPostProcessors()注冊后置處理器;創(chuàng)建AnnotationAwareAspectJAutoProxyCreator對象
    2. finishBeanFactoryInitialization()初始化剩下的單實例bean
      1. 創(chuàng)建業(yè)務(wù)邏輯組件和切面組件
      2. AnnotationAwareAspectJAutoProxyCreator攔截組件的創(chuàng)建過程
      3. 組件創(chuàng)建完之后净蚤,判斷組件是否需要增強钥组;是:切面的通知方法,包裝成增強器(Advisor);給業(yè)務(wù)邏輯組件創(chuàng)建一個代理對象(cglib)今瀑;
  5. 執(zhí)行目標(biāo)方法:
    1. 代理對象執(zhí)行目標(biāo)方法
    2. CglibAopProxy.intercept()程梦;
      1. 得到目標(biāo)方法的攔截器鏈(增強器包裝成攔截器MethodInterceptor)
      2. 利用攔截器的鏈?zhǔn)綑C制,依次進入每一個攔截器進行執(zhí)行橘荠;
      3. 效果:
        1. 正常執(zhí)行:前置通知-》目標(biāo)方法-》后置通知-》返回通知
        2. 出現(xiàn)異常:前置通知-》目標(biāo)方法-》后置通知-》異常通知
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末屿附,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子哥童,更是在濱河造成了極大的恐慌挺份,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贮懈,死亡現(xiàn)場離奇詭異匀泊,居然都是意外死亡,警方通過查閱死者的電腦和手機朵你,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門各聘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人抡医,你說我怎么就攤上這事躲因。” “怎么了魂拦?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵毛仪,是天一觀的道長。 經(jīng)常有香客問我芯勘,道長箱靴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任荷愕,我火速辦了婚禮衡怀,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘安疗。我一直安慰自己抛杨,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布荐类。 她就那樣靜靜地躺著怖现,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上屈嗤,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天潘拨,我揣著相機與錄音,去河邊找鬼饶号。 笑死铁追,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的茫船。 我是一名探鬼主播琅束,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼算谈!你這毒婦竟也來了涩禀?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤濒生,失蹤者是張志新(化名)和其女友劉穎埋泵,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體罪治,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡丽声,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了觉义。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雁社。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖晒骇,靈堂內(nèi)的尸體忽然破棺而出霉撵,到底是詐尸還是另有隱情,我是刑警寧澤洪囤,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布徒坡,位于F島的核電站,受9級特大地震影響瘤缩,放射性物質(zhì)發(fā)生泄漏喇完。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一剥啤、第九天 我趴在偏房一處隱蔽的房頂上張望锦溪。 院中可真熱鬧,春花似錦府怯、人聲如沸刻诊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽则涯。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間粟判,已是汗流浹背肖揣。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留浮入,地道東北人。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓羊异,卻偏偏與公主長得像事秀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子野舶,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,440評論 2 359

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