Quartz集群配置

quartz的介绍就不说了,这里主要说的是使用spring boot+?2.2.1搭建集群。

1.pom引入


2.在resources下新建quartz.properties文件,用于覆盖默认配置。

这里是集群配置文件

#quartz集群配置

# ===========================================================================

# Configure Main Scheduler Properties 调度器属性

# ===========================================================================

#调度标识名 集群中每一个实例都必须使用相同的名称

org.quartz.scheduler.instanceName=DefaultQuartzScheduler

#ID设置为自动获取 每一个必须不同

org.quartz.scheduler.instanceid=AUTO

#禁用quartz软件更新

org.quartz.scheduler.skipUpdateCheck=true

#============================================================================

# Configure ThreadPool

#============================================================================

#线程池的实现类(一般使用SimpleThreadPool即可满足几乎所有用户的需求)

org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool

#指定线程数,至少为1(无默认值)(一般设置为1-100直接的整数合适)

org.quartz.threadPool.threadCount=25

#设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5)

org.quartz.threadPool.threadPriority=5

#============================================================================

# Configure JobStore

#============================================================================

# 信息保存时间 默认值60秒

org.quartz.jobStore.misfireThreshold=60000

#数据保存方式为数据库持久化

org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX

#数据库代理类,一般org.quartz.impl.jdbcjobstore.StdJDBCDelegate可以满足大部分数据库

org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate

#JobDataMaps是否都为String类型

org.quartz.jobStore.useProperties=false

#数据库别名 随便取

org.quartz.jobStore.dataSource=myDS

#表的前缀,默认QRTZ_

org.quartz.jobStore.tablePrefix=QRTZ_

#是否加入集群

org.quartz.jobStore.isClustered=true

#调度实例失效的检查时间间隔

org.quartz.jobStore.clusterCheckinInterval=20000

#============================================================================

# Configure Datasources

#============================================================================

#数据库引擎

org.quartz.dataSource.myDS.driver=com.mysql.jdbc.Driver

#数据库连接

org.quartz.dataSource.myDS.URL=jdbc:mysql://127.0.0.1:3306/dbapp_dandan?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true

#数据库用户

org.quartz.dataSource.myDS.user=root

#数据库密码

org.quartz.dataSource.myDS.password=

#允许最大连接

org.quartz.dataSource.myDS.maxConnections=5

#验证查询sql,可以不设置

org.quartz.dataSource.myDS.validationQuery=select 0 from dual

3.运行数据库脚本

解压官网下载下来的包,如果你的数据库是mysql,用这个tables_mysql_innodb.sql,里面有11个表



4下面是集群两种使用实现方式

第一种?

1.添加任务注入的工厂类,否则任务注入会出错:

/**

* Created by Administrator on 2018\6\9 0009.

*/

public class DetailQuartzJobBeanextends QuartzJobBean {

protected final Loglogger = LogFactory.getLog(getClass());

private StringtargetObject;

private StringtargetMethod;

private ApplicationContextctx;

@Override

? ? protected void executeInternal(JobExecutionContext context)throws JobExecutionException {

try {

Object otargetObject =ctx.getBean(targetObject);

Method m =null;

try {

m = otargetObject.getClass().getMethod(targetMethod,new Class[] { JobExecutionContext.class });

m.invoke(otargetObject,new Object[] { context });

}catch (SecurityException e) {

logger.error(e);

}catch (NoSuchMethodException e) {

logger.error(e);

}

}catch (Exception e) {

throw new JobExecutionException(e);

}

}

public void setApplicationContext(ApplicationContext applicationContext) {

this.ctx = applicationContext;

}

public void setTargetObject(String targetObject) {

this.targetObject = targetObject;

}

public void setTargetMethod(String targetMethod) {

this.targetMethod = targetMethod;

}

}


2.配置quartz


@Configuration

public class QuartzConfig {

// 配置文件路径

? ? static final StringQUARTZ_CONFIG ="/quartz.properties";

/**

* Description: 定义调用对象和调用对象的方法

*

? ? * @param

? ? * @return

? ? * @see

? ? */

? ? @Bean(name ="initJobDetail")

public JobDetailFactoryBean enjoyQuartzJobTask()

{

//集群模式下必须使用JobDetailFactoryBean, MethodInvokingJobDetailFactoryBean 类中的 methodInvoking 方法,是不支持序列化的

? ? ? ? JobDetailFactoryBean bean =new JobDetailFactoryBean();

bean.setName("enjoyQuartzJob");// 设置任务的名字

? ? ? ? bean.setGroup("enjoyQuartzJobGroup");// 设置任务的分组,这些属性都可以存储在数据库中,在多任务的时候使用

? ? ? ? bean.setDurability(true);

bean.setRequestsRecovery(true);

bean.setJobClass(DetailQuartzJobBean.class);

Map map =new HashMap<>();

map.put("targetObject","initBjLu28Session");//任务所在的类

? ? ? ? map.put("targetMethod","task");//具体执行任务的方法

? ? ? ? bean.setJobDataAsMap(map);

return bean;

}

// 配置触发器2

? ? @Bean(name ="initJobTrigger")

public CronTriggerFactoryBean secondTrigger(JobDetail initJobDetail) {

CronTriggerFactoryBean trigger =new CronTriggerFactoryBean();

trigger.setJobDetail(initJobDetail);

// cron表达式

? ? ? ? trigger.setCronExpression("0 0/1 * * * ?");

return trigger;

}

// 配置定时任务3

? ? @Bean(name ="fetResultJobDetail")

public MethodInvokingJobDetailFactoryBean thirdJobDetail(FetchResult fetResultJob) {

MethodInvokingJobDetailFactoryBean jobDetail =new MethodInvokingJobDetailFactoryBean();

// 是否并发执行

? ? ? ? jobDetail.setConcurrent(false);

// 为需要执行的实体类对应的对象

? ? ? ? jobDetail.setTargetObject(fetResultJob);

// 需要执行的方法

? ? ? ? jobDetail.setTargetMethod("task");

return jobDetail;

}

// 配置触发器2

? ? @Bean(name ="fetResultJobTrigger")

public CronTriggerFactoryBean thirdTrigger(JobDetail fetResultJobDetail) {

CronTriggerFactoryBean trigger =new CronTriggerFactoryBean();

trigger.setJobDetail(fetResultJobDetail);

// cron表达式

? ? ? ? trigger.setCronExpression("5 0/5 9-23 * * ?");

return trigger;

}

// 配置Scheduler

? ? @Bean(name ="scheduler")

public SchedulerFactoryBean schedulerFactory(Trigger initJobTrigger) {

SchedulerFactoryBean bean =new SchedulerFactoryBean();

//? ? public SchedulerFactoryBean schedulerFactory(Trigger initJobTrigger, Trigger fetResultJobTrigger) {

//? ? ? ? SchedulerFactoryBean bean = new SchedulerFactoryBean();

// 延时启动,应用启动1秒后

? ? ? ? bean.setStartupDelay(10);

//用于quartz集群,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了

? ? ? ? bean.setOverwriteExistingJobs(true);

//用于quartz集群,加载quartz数据源

//? ? ? ? bean.setDataSource(dataSource);

//用于quartz集群,加载quartz数据源配置

//? ? ? ? bean.setQuartzProperties(quartzProperties());

//直接使用配置文件

? ? ? ? bean.setConfigLocation(new ClassPathResource(QUARTZ_CONFIG));

//? ? ? ? bean.setConfigLocation(new FileSystemResource(this.getClass().getResource("/quartz.properties").getPath()));

? ? ? ? bean.setApplicationContextSchedulerContextKey("applicationContext");

// 注册触发器

? ? ? ? bean.setTriggers(initJobTrigger);

//? ? ? ? bean.setTriggers(initJobTrigger,fetResultJobTrigger);

? ? ? ? return bean;

}

}


3.JOB任务:

@Configuration

@Component("initBjSession")

@EnableScheduling

public class InitBSessionimplements Serializable {

@Autowired

? ? private BjServiceImpl bjService;

//? ? public void task() {

? ? public void task(JobExecutionContext context) {

? ? ? ? System.out.println("-----"+ DateTimeUtil.getDateTime());

? ? }

}


第二种实现方式,更加简洁好用:

?*?文件名:QuartzConfig.java?版权:Copyright?by?www.poly.com?描述:?修改人:gogym?修改时间:2017年11月9日?跟踪单号:?修改单号:

?*?修改内容:

?*/??


package?com.poly.pay.configuration;??



import?java.io.IOException;??

import?java.text.ParseException;??

import?java.util.ArrayList;??

import?java.util.HashMap;??

import?java.util.List;??

import?java.util.Map;??

import?java.util.Set;??


import?org.quartz.JobDetail;??

import?org.quartz.JobKey;??

import?org.quartz.Scheduler;??

import?org.quartz.SchedulerException;??

import?org.quartz.Trigger;??

import?org.quartz.TriggerKey;??

import?org.quartz.impl.matchers.GroupMatcher;??

import?org.quartz.impl.triggers.CronTriggerImpl;??

import?org.springframework.beans.factory.annotation.Qualifier;??

import?org.springframework.context.annotation.Bean;??

import?org.springframework.context.annotation.Configuration;??

import?org.springframework.core.io.ClassPathResource;??

import?org.springframework.scheduling.quartz.CronTriggerFactoryBean;??

import?org.springframework.scheduling.quartz.JobDetailFactoryBean;??

import?org.springframework.scheduling.quartz.SchedulerFactoryBean;??


import?com.poly.pay.schedule.JobRefundWeichartBean;??



@Configuration??

public?class?QuartzConfig??

{??


//?配置文件路径??

static?final?String?QUARTZ_CONFIG?=?"properties/quartz.properties";??


//?定时任务组名称??

public?static?final?String?Quartz_Group_Name?=?"enjoyQuartzJobGroup";??

//定时任务方法后缀??

public?static?final?String?Quartz_Job_Suffix?=?"_job";??

//定时任务触发器后缀??

public?static?final?String?Quartz_Trigger_Suffix?=?"_trigger";??



@Bean(name?=?"triggers")??

public?CronTriggerImpl[]?createTriggers()??

throws?ParseException??

????{??

List?l?=new?ArrayList();??

l.add(createTrigger(JobRefundWeichartBean.class,?"0/20?*?*?*?*??"));??

//l.add(createTrigger(JobRefundWeichartBean.class,?"0/20?*?*?*?*??"));??

//按你的需要添加多个任务:任务所在类.class???cron表达式??


return?l.toArray(new?CronTriggerImpl[l.size()]);??

????}??


private?JobDetail?create(Class?c)??

????{??

JobDetailFactoryBean?d?=new?JobDetailFactoryBean();??

d.setDurability(true);??

d.setRequestsRecovery(true);??

????????d.setJobClass(c);??

????????d.setName(c.getSimpleName()?+?Quartz_Job_Suffix);??

????????d.setGroup(Quartz_Group_Name);??

????????d.afterPropertiesSet();??

??????JobDetail?jd=?d.getObject();??

//jd.getJobDataMap().put("key",?123);//如果想通过jobDataMap传递值,在这里添加??

return?jd;??

}??

private?CronTriggerImpl?createTrigger(Class?t,?String?cronExpression)?throws?ParseException?{???

CronTriggerFactoryBean?c?=new?CronTriggerFactoryBean();???

c.setJobDetail(create(t));???

c.setCronExpression(cronExpression);???

c.setName(t.getSimpleName()?+?Quartz_Trigger_Suffix);???

c.setGroup(Quartz_Group_Name);?c.afterPropertiesSet();???

return?(CronTriggerImpl)c.getObject();???

}???

@Bean(name?=?"schedulerFactoryBean")??

public?SchedulerFactoryBean?schedulerFactoryBean(@Qualifier("triggers")?CronTriggerImpl[]?triggers)??

throws?IOException,?ParseException,?SchedulerException??

????{??

SchedulerFactoryBean?factory?=new?SchedulerFactoryBean();??

//?用于quartz集群,QuartzScheduler,启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了??

factory.setOverwriteExistingJobs(true);??

//?QuartzScheduler?延时启动,应用启动完10秒后?QuartzScheduler?再启动??

factory.setStartupDelay(10);??

//?直接使用配置文件,用于quartz集群,加载quartz数据源配置??

factory.setConfigLocation(new?ClassPathResource(QUARTZ_CONFIG));??

factory.setAutoStartup(true);??

//?集群需要通过QuartzJobBean注入,需要设置上下文??

factory.setApplicationContextSchedulerContextKey("applicationContext");??

//?注册触发器??

//?factory.getScheduler().pauseAll();??

factory.setTriggers(createTriggers());//?直接使用配置文件??

//?factory.setConfigLocation(new??

//?FileSystemResource(this.getClass().getResource("/quartz.properties").getPath()));??

return?factory;??

????}??


/**

?????*?添加该方法的目的在于一个使用场景。如果代码中删除了不需要的定时任务,但是数据库中不会删除掉,会导致之前

?????*?的定时任务一直在运行,如果把定时任务依赖的类删除了,就会导致报错,找不到目标。所以配置动态删除任务

?????*/??

@Bean??

public?String?fulsh(@Qualifier("schedulerFactoryBean")?SchedulerFactoryBean?schedulerFactoryBean,??

@Qualifier("triggers")?CronTriggerImpl[]?triggers)??

throws?SchedulerException??

????{??

try??

????????{??

????????????Scheduler?s?=?schedulerFactoryBean.getScheduler();??

if?(null?==?s)??

????????????{??

return?"Scheduler?is?null";??

????????????}??


//?最新配置的任务??

List?newTriNames?=new?ArrayList();??

if?(null?!=?triggers)??

????????????{??

for?(CronTriggerImpl?cronTriggerImpl?:?triggers)??

????????????????{??

????????????????????newTriNames.add(cronTriggerImpl.getName());??

????????????????}??

????????????}??


//?现有数据库中已有的任务??

????????????Set?myGroupTriggers?=?s.getTriggerKeys(GroupMatcher.triggerGroupEquals(Quartz_Group_Name));??

if?(null?==?myGroupTriggers?||?myGroupTriggers.size()?==?0)??

????????????{??

return?"myGroupTriggers?is?null";??

????????????}??


if?(newTriNames?!=?null?&&?newTriNames.size()?>?0)??

????????????{??

for?(TriggerKey?triggerKey?:?myGroupTriggers)??

????????????????{??

????????????????????String?dbTriggerName?=?triggerKey.getName();??

if?(!newTriNames.contains(dbTriggerName))??

????????????????????{??

//?暂停?触发器??

????????????????????????s.pauseTrigger(triggerKey);??

????????????????????????Trigger?g?=?s.getTrigger(triggerKey);??

JobKey?jk?=null;??

if?(null?!=?g)??

????????????????????????{??

????????????????????????????jk?=?g.getJobKey();??

????????????????????????}??

//?停止触发器??

????????????????????????s.pauseTrigger(triggerKey);??

//?注销?触发器??

????????????????????????s.unscheduleJob(triggerKey);??

if?(null?!=?jk)??

????????????????????????{??

//?暂停任务??

????????????????????????????s.pauseJob(jk);??

//?删除任务??

????????????????????????????s.deleteJob(jk);??

????????????????????????}??

????????????????????}??

????????????????}??

????????????}??

//?重要,如果不恢复所有,会导致无法使用??

????????????s.resumeAll();??

????????}??

catch?(Exception?e)??

????????{??

????????????e.printStackTrace();??

return?"Exception:"?+?e.getMessage();??

????????}??

return?"success";??

????}??

}??

任务类:

[java]?view plain?copy

/*

?*?文件名:JobRefundWeichartBean.java?版权:Copyright?by?www.poly.com?描述:?修改人:gogym?修改时间:2017年12月28日?跟踪单号:

?*?修改单号:?修改内容:

?*/??

package?com.poly.pay.schedule;??


import?org.quartz.DisallowConcurrentExecution;??

import?org.quartz.JobExecutionContext;??

import?org.quartz.JobExecutionException;??

import?org.quartz.PersistJobDataAfterExecution;??


import?org.springframework.scheduling.quartz.QuartzJobBean;??



//?1.修改数据,防止并发,2不允许并发执行??

@PersistJobDataAfterExecution??

@DisallowConcurrentExecution??

//@Component??

public?class?JobRefundWeichartBean?extends?QuartzJobBean?{??

//需要注入的类,如redis代理??

private?IRedisProxy?redisProxy;??


@Override??

protected?void?executeInternal(JobExecutionContext?arg0)??

throws?JobExecutionException?{??

//System.out.println("打印通过jobDataMap传递的值:"+arg0.getJobDetail().getJobDataMap().get("qqq"));??

//需要使用的时候,通过SpringContextUtil获取spring托管的实例注入即可??

redisProxy?=?SpringContextUtil.getBean(IRedisProxy.class);??

System.out.println("执行方法");??

????}??

}??

注意:在任务类里面注入,不能通过@Autowired注解直接注入。因为任务类本身并没有被spring托管,所以注入是null??梢哉庋饩?/p>

1、加入@Component类注解,让spring托管。但这种方法某些环境下不一定能使用,不推荐

2、通过自定义SpringContextUtil类来注入问题:

SpringContextUtil工具类:(注意,这个类要@Component注册到spring(前提是这个类要能被spring 扫描到)。也可以通过代码注册,在@Configuration类里面加入@Bean即可,这样可以手动注册。二者选其一就行)

[plain]?view plain?copy

import?org.springframework.beans.BeansException;??

import?org.springframework.beans.factory.NoSuchBeanDefinitionException;??

import?org.springframework.context.ApplicationContext;??

import?org.springframework.context.ApplicationContextAware;??

import?org.springframework.stereotype.Component;??



/**??

?*?这个类是为了解决在普通类调用service的问题??

?*???

?*?@ClassName?SpringContextUtil??

?*?@Description??

?*?@author?gogym?189155278@qq.com??

?*?@date?2016-6-12??

?*?@content?OfflineMessageService?offlineMessageService?=?(OfflineMessageService)?SpringContextUtil??

?*??????????.getBean("offlineMessageService");??

?*/??

@Component??

public?class?SpringContextUtil?implements?ApplicationContextAware??

{??

????private?static?ApplicationContext?applicationContext;?//?Spring应用上下文??


????//?下面的这个方法上加了@Override注解,原因是继承ApplicationContextAware接口是必须实现的方法??

????@Override??

????public?void?setApplicationContext(ApplicationContext?applicationContext)??

????????throws?BeansException??

????{??

????????SpringContextUtil.applicationContext?=?applicationContext;??

????}??


????public?static?ApplicationContext?getApplicationContext()??

????{??

????????return?applicationContext;??

????}??


????public?static?Object?getBean(String?name)??

????????throws?BeansException??

????{??

????????return?applicationContext.getBean(name);??

????}??


????public?static?Object?getBean(String?name,?Class?requiredType)??

????????throws?BeansException??

????{??


????????return?applicationContext.getBean(name,?requiredType);??

????}??


????public?static??T?getBean(Class?clazz)??

????????throws?BeansException??

????{??

????????return?applicationContext.getBean(clazz);??

????}??


????public?static?boolean?containsBean(String?name)??

????{??

????????return?applicationContext.containsBean(name);??

????}??


????public?static?boolean?isSingleton(String?name)??

????????throws?NoSuchBeanDefinitionException??

????{??

????????return?applicationContext.isSingleton(name);??

????}??


????public?static?Class?getType(String?name)??

????????throws?NoSuchBeanDefinitionException??

????{??

????????return?applicationContext.getType(name);??

????}??


????public?static?String[]?getAliases(String?name)??

????????throws?NoSuchBeanDefinitionException??

????{??

????????return?applicationContext.getAliases(name);??

????}??

}??

启动即可看到数据库插入了任务相关的信息。集群完成。

需要注意的是:

当你运行水平集群时,时钟应当要同步,以免出现离奇且不可预知的行为。假如时钟没能够同步,Scheduler 实例将对其他节点的状态产生混乱。有几种简单的方法来保证时钟何持同步,而且也没有理由不这么做。最简单的同步计算机时钟的方式是使用某一个 Internet 时间服务器(Internet Time Server ITS)。

常用解决方案:

服务器中配置时间同步只要一台服务器同步互联网的时钟服务器,其它的服务以这台为时钟服务器!

Linux配置(局域网的客户端)


1、安装

???yum?install?ntp?? (centos的安装方法)

2、先运行?#?ntpdate?192.168.1.33?同步一次.

3、然后通过crontab计时器配置一个定时同步的任务,例如每月一号零点零分同步一次.代码如下:

#?crontab?-e??//添下面一行,新建的定时任务文件保存在/var/spool/cron/下,以创建人的用户名命名

0 0 1 * * /etc/ntp/ntprsync.sh//每小时同步一次。


4、创建文件


# vi ntprsync.sh//内容如下#!/bin/sh/usr/sbin/ntpdate 192.168.1.33//时钟服务器的IP/sbin/hwclock –w


5、设置权限?chmod?777?ntprsync.sh

6、注意防火墙的设置.

7、成功。

8、服务启动。


/sbin/service?crond?start?//启动服务/sbin/service?crond?stop?//关闭服务/sbin/service?crond?restart?//重启服务/sbin/service?crond?reload?//重新载入配置?



转载自https://blog.csdn.net/KokJuis/article/details/78526709

最后编辑于
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,100评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,308评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,718评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,275评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,376评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,454评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,464评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,248评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,686评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,974评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,150评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,817评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,484评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,140评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,374评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,012评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,041评论 2 351

推荐阅读更多精彩内容