反射工具箱-工具类

ObjectFactory

创建对象使用的工厂接口

public interface ObjectFactory {

  /**
   * Sets configuration properties.
   * @param properties configuration properties
   */
  default void setProperties(Properties properties) {
    // NOP
    //No Operation Performed 无操作执行
  }

  /**
   * 使用默认构造方法创建对象
   * Creates a new object with default constructor.
   * @param type Object type
   * @return
   */
  <T> T create(Class<T> type);

  /**
   * 使用特定参数的构造方法创建对象
   * Creates a new object with the specified constructor and params.
   * @param type Object type
   * @param constructorArgTypes Constructor argument types
   * @param constructorArgs Constructor argument values
   * @return
   */
  <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);

  /**
   * 检测指定类型是否为集合类型,主妥处理 java.util.Collection 及其子类
   * Returns true if this object can have a set of other objects.
   * It's main purpose is to support non-java.util.Collection objects like Scala collections.
   *
   * @param type Object type
   * @return whether it is a collection or not
   * @since 3.1.0
   */
  <T> boolean isCollection(Class<T> type);

}

DefaultObjectFactory

默认创建对象的工厂实现,使用 Java 反射技术

public class DefaultObjectFactory implements ObjectFactory, Serializable {

  private static final long serialVersionUID = -8855120656740914948L;

  @Override
  public <T> T create(Class<T> type) {
    return create(type, null, null);
  }

  @SuppressWarnings("unchecked")
  @Override
  public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    // 解决集合接口,解决接口默认实现类
    Class<?> classToCreate = resolveInterface(type);
    // we know types are assignable
    return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
  }

  //创造对象
  private  <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    try {
      Constructor<T> constructor;
      //无参构造函数
      if (constructorArgTypes == null || constructorArgs == null) {
        constructor = type.getDeclaredConstructor();
        try {
          return constructor.newInstance();
        } catch (IllegalAccessException e) {
          //查看是否能控制成员的访问,能设置true,访问
          if (Reflector.canControlMemberAccessible()) {
            constructor.setAccessible(true);
            return constructor.newInstance();
          } else {
            throw e;
          }
        }
      }
      //根据参数得到对应的构造方法
      constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
      try {
        //构造对象实例
        return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
      } catch (IllegalAccessException e) {
        if (Reflector.canControlMemberAccessible()) {
          constructor.setAccessible(true);
          return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
        } else {
          throw e;
        }
      }
    } catch (Exception e) {
      String argTypes = Optional.ofNullable(constructorArgTypes).orElseGet(Collections::emptyList)
          .stream().map(Class::getSimpleName).collect(Collectors.joining(","));
      String argValues = Optional.ofNullable(constructorArgs).orElseGet(Collections::emptyList)
          .stream().map(String::valueOf).collect(Collectors.joining(","));
      throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
    }
  }
  /**
   * 解决集合接口,解决接口默认实现类
   */
  protected Class<?> resolveInterface(Class<?> type) {
    Class<?> classToCreate;
    if (type == List.class || type == Collection.class || type == Iterable.class) {
      classToCreate = ArrayList.class;
    } else if (type == Map.class) {
      classToCreate = HashMap.class;
    } else if (type == SortedSet.class) { // issue #510 Collections Support
      classToCreate = TreeSet.class;
    } else if (type == Set.class) {
      classToCreate = HashSet.class;
    } else {
      //first:TreeMap is this type;maybe mybatis is not support the type;(only my guess)
      //second: other original type:like java bean;String;
      classToCreate = type;
    }
    return classToCreate;
  }

  @Override
  public <T> boolean isCollection(Class<T> type) {
    return Collection.class.isAssignableFrom(type);
  }

}

ExampleObjectFactory

对象工厂的样例,样可以在 mybatis-config.xml 对象中指定创建对象的工厂。

public class ExampleObjectFactory extends DefaultObjectFactory {
  private Properties properties;

  @Override
  public <T> T create(Class<T> type) {
    return super.<T> create(type);
  }

  @Override
  public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    return super.<T> create(type, constructorArgTypes, constructorArgs);
  }

  @Override
  public void setProperties(Properties properties) {
    super.setProperties(properties);
    this.properties = properties;
  }

  public Properties getProperties() {
    return properties;
  }

}

Property 工具集

反射模块中使用到的三个属性工具类,分别是 PropertyTokenizer
PropertyNamer 和 PropertyCopier。

PropertyTokenizer

PropertyTokenizer是分词器,编译器,解析这样的 orders[0].items[0].name 表达式,实现了Iterator,具有迭代功能

public class PropertyTokenizer implements Iterator<PropertyTokenizer> {
//  orders[0].items[0].name 第一次迭代
  private String name; //当前表达式的名称 orders
  private final String indexedName; //当前表达式的索引名  orders[0]
  private String index; //索引下标 0
  private final String children; //子表达式 items[0].name

  public PropertyTokenizer(String fullname) {
    int delim = fullname.indexOf('.');
    if (delim > -1) {
      name = fullname.substring(0, delim);
      children = fullname.substring(delim + 1);
    } else {
      name = fullname;
      children = null;
    }
    indexedName = name;
    delim = name.indexOf('[');
    if (delim > -1) {
      index = name.substring(delim + 1, name.length() - 1);
      name = name.substring(0, delim);
    }
  }

  public String getName() {
    return name;
  }

  public String getIndex() {
    return index;
  }

  public String getIndexedName() {
    return indexedName;
  }

  public String getChildren() {
    return children;
  }

  @Override
  public boolean hasNext() {
    return children != null;
  }

  @Override
  public PropertyTokenizer next() {
    return new PropertyTokenizer(children);
  }

  @Override
  public void remove() {
    throw new UnsupportedOperationException("Remove is not supported, as it has no meaning in the context of properties.");
  }
}

用例

PropertyTokenizer 继承了 Iterator 接口,它可以法代处理嵌套多层表达式。PropertyTokenizer.next() 方法中会创建新的 PropertyTokenize 对象并解析 children 宇段记录的子表达式。为了便于读者理解,这里继续使用前面的订单示例进行说明,描述解析属性表达式
orders[O].items[O].name 的迭代过程。


image.png

PropertyNamer

获取类的 getter、setter 方法 对应的属性名称。
工具类 getter 和 setter 属性的处理方法;

public final class PropertyNamer {

  private PropertyNamer() {
    // Prevent Instantiation of Static Class
  }
  //getId -> id;根据get和set方法;返回属性
  public static String methodToProperty(String name) {
    if (name.startsWith("is")) {
      name = name.substring(2);
    } else if (name.startsWith("get") || name.startsWith("set")) {
      name = name.substring(3);
    } else {
      throw new ReflectionException("Error parsing property name '" + name + "'.  Didn't start with 'is', 'get' or 'set'.");
    }
    //作用 Id --> id;
    if (name.length() == 1 || (name.length() > 1 && !Character.isUpperCase(name.charAt(1)))) {
      name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
    }

    return name;
  }
  // 是否是一个类的 getter 和 setter 方法
  public static boolean isProperty(String name) {
    return isGetter(name) || isSetter(name);
  }
  //是否包含 get方法 和 is方法
  public static boolean isGetter(String name) {
    return (name.startsWith("get") && name.length() > 3) || (name.startsWith("is") && name.length() > 2);
  }
  //是否包含 set方法
  public static boolean isSetter(String name) {
    return name.startsWith("set") && name.length() > 3;
  }

}

PropertyCopier

PropertyCopier 一个属性拷贝的工具类,主要处理相同类型的两个对象之间的属性拷贝。

public final class PropertyCopier {

  private PropertyCopier() {
    // Prevent Instantiation of Static Class
  }

  /**
   * 主要处理相同类型的两个对象之间的属性拷贝
   * @param type
   * @param sourceBean 原对象
   * @param destinationBean 目标对象
   */
  public static void copyBeanProperties(Class<?> type, Object sourceBean, Object destinationBean) {
    Class<?> parent = type;
    while (parent != null) {
      final Field[] fields = parent.getDeclaredFields();
      for (Field field : fields) {
        try {
          try {
            field.set(destinationBean, field.get(sourceBean));
          } catch (IllegalAccessException e) {
            if (Reflector.canControlMemberAccessible()) {
              field.setAccessible(true);
              field.set(destinationBean, field.get(sourceBean));
            } else {
              throw e;
            }
          }
        } catch (Exception e) {
          // Nothing useful to do, will only fail on final fields, which will be ignored.
        }
      }
      parent = parent.getSuperclass();
    }
  }

}

MetaClass

MetaClass 是对 Reflector 的封装,是类层次的信息封装。
MetaClass 通过 Reflector 和 PropertyTokenizer 组合使用, 实现了对复杂的属性表达式的解析,并实现了获取指定属性描述信息的功能。
主要实现了 1.检测是否包含这个复杂的属性表达式,2.属性表达式的返回数据类型 3.返回 Reflector 对象的集合信息们。

public class MetaClass {
  //ReflectorFactory 对象,用于缓存 Reflector 对象
  private final ReflectorFactory reflectorFactory;
  //在创建 MetaClass 时会指定一个类,该 Reflector 对象会用于记录该类相关 的元信息
  private final Reflector reflector;

  private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
    this.reflectorFactory = reflectorFactory;
    this.reflector = reflectorFactory.findForClass(type);
  }

  public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) {
    return new MetaClass(type, reflectorFactory);
  }
  /**
   * 根据属性名字,创建这个属性 数据类型的 MetaClass 对象
   */
  public MetaClass metaClassForProperty(String name) {
    Class<?> propType = reflector.getGetterType(name);
    return MetaClass.forClass(propType, reflectorFactory);
  }

  /**
   * 查找是否有相应的 name(user.address.country) 复杂属性表达式,并返回;只进行了 . 这样复杂属性的导航,并没有对下表进行解析
   * @param name
   * @return
   */
  public String findProperty(String name) {
    // 构建的属性信息 user.address.country
    StringBuilder prop = buildProperty(name, new StringBuilder());
    return prop.length() > 0 ? prop.toString() : null;
  }

  /**
   * 查找是否有相应的 name 属性表达式,并返回
   * @param name
   * @param useCamelCaseMapping 第二个参数表示是否忽略属性表达式中的下画线
   * @return
   */
  public String findProperty(String name, boolean useCamelCaseMapping) {
    if (useCamelCaseMapping) {
      name = name.replace("_", "");
    }
    return findProperty(name);
  }

  /**
   * 获取类的可读属性们
   * @return
   */
  public String[] getGetterNames() {
    return reflector.getGetablePropertyNames();
  }
  /**
   * 获取类的可写属性们
   * @return
   */
  public String[] getSetterNames() {
    return reflector.getSetablePropertyNames();
  }

  /**
   * 获取属性表达式的数据类型
   * @param name
   * @return
   */
  public Class<?> getSetterType(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      MetaClass metaProp = metaClassForProperty(prop.getName());
      return metaProp.getSetterType(prop.getChildren());
    } else {
      return reflector.getSetterType(prop.getName());
    }
  }

  /**
   * 获取类字段 get 方法的返回值类型
   * @param name
   * @return
   */
  public Class<?> getGetterType(String name) {
    // 新建属性表达式解析器
    PropertyTokenizer prop = new PropertyTokenizer(name);
    // 是否有孩子节点
    if (prop.hasNext()) {
      //
      MetaClass metaProp = metaClassForProperty(prop);
      return metaProp.getGetterType(prop.getChildren());
    }
    // issue #506. Resolve the type inside a Collection Object
    return getGetterType(prop);
  }

  /**
   * 根据包含属性表达式的 PropertyTokenizer 解析器,创建属性的 MetaClass 对象
   * @param prop
   * @return
   */
  private MetaClass metaClassForProperty(PropertyTokenizer prop) {
    Class<?> propType = getGetterType(prop);
    return MetaClass.forClass(propType, reflectorFactory);
  }

  /**
   * 根据包含属性的 PropertyTokenizer 对象,返回属性表达式对应的数据类型
   * @param prop
   * @return
   */
  private Class<?> getGetterType(PropertyTokenizer prop) {
    // 返回属性数据类型
    Class<?> type = reflector.getGetterType(prop.getName());
    // 该表达式中是否使用 [] 下表,且是 Collection 子类
    if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) {
      // 通过 TypeParameterResolver 工具类解析属性的类
      Type returnType = getGenericGetterType(prop.getName());
      // 针对 ParameterizedType 进行处理,即针对泛型集合类型进行处理
      if (returnType instanceof ParameterizedType) {
        // 获取实际的参数类型
        Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments();
        if (actualTypeArguments != null && actualTypeArguments.length == 1) {
          // 泛型的类型
          returnType = actualTypeArguments[0];
          if (returnType instanceof Class) {
            type = (Class<?>) returnType;
          } else if (returnType instanceof ParameterizedType) {
            type = (Class<?>) ((ParameterizedType) returnType).getRawType();
          }
        }
      }
    }
    return type;
  }

  /**
   *
   * @param propertyName
   * @return
   */
  private Type getGenericGetterType(String propertyName) {
    try {
      // 根据 Reflector.getMethods 集合中记录的 Invoker 实现类的类型,决定解析 getter 方法返回值类型,还是解析字段类型
      Invoker invoker = reflector.getGetInvoker(propertyName);
      if (invoker instanceof MethodInvoker) {
        Field _method = MethodInvoker.class.getDeclaredField("method");
        _method.setAccessible(true);
        Method method = (Method) _method.get(invoker);
        return TypeParameterResolver.resolveReturnType(method, reflector.getType());
      } else if (invoker instanceof GetFieldInvoker) {
        Field _field = GetFieldInvoker.class.getDeclaredField("field");
        _field.setAccessible(true);
        Field field = (Field) _field.get(invoker);
        return TypeParameterResolver.resolveFieldType(field, reflector.getType());
      }
    } catch (NoSuchFieldException | IllegalAccessException ignored) {
    }
    return null;
  }

  /**
   * 检查被包装类的属性表达式值是否有Setter()方法
   * @param name
   * @return
   */
  public boolean hasSetter(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      if (reflector.hasSetter(prop.getName())) {
        MetaClass metaProp = metaClassForProperty(prop.getName());
        return metaProp.hasSetter(prop.getChildren());
      } else {
        return false;
      }
    } else {
      return reflector.hasSetter(prop.getName());
    }
  }
  /**
   * 检查被包装类的属性表达式值是否有 Getter()方法,比如 orders[0].id 属性表达式
   * @param name
   * @return
   */
  public boolean hasGetter(String name) {
    // 解析属性表达式
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) { // 存在子表达式
      if (reflector.hasGetter(prop.getName())) {
        // 创建 属性的 MetaClass 对象,递归处理
        MetaClass metaProp = metaClassForProperty(prop);
        return metaProp.hasGetter(prop.getChildren());
      } else {
        return false;
      }
    } else {
      return reflector.hasGetter(prop.getName());
    }
  }

  /**
   * 获取 get 字段 封装的 Invoker 对象
   * @param name
   * @return
   */
  public Invoker getGetInvoker(String name) {
    return reflector.getGetInvoker(name);
  }

  /**
   * 获取 set 字段 封装的 Invoker 对象
   * @param name
   * @return
   */
  public Invoker getSetInvoker(String name) {
    return reflector.getSetInvoker(name);
  }

  /**
   * 构建多个属性信息
   * 根据属性表达式名称,比如:user.address.country,解析递归,查找在多个类中的多个属性信息,然后拼接属性信息,返回 StringBuilder 对象
   * @param name
   * @param builder
   * @return
   */
  private StringBuilder buildProperty(String name, StringBuilder builder) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    // 判断 name 属性是否 包含 . ,即是否包含子节点
    if (prop.hasNext()) {
      // 如果包含子节点,获取父节点的属性名称
      String propertyName = reflector.findPropertyName(prop.getName());
      if (propertyName != null) {
        // 添加到 builder 中
        builder.append(propertyName);
        builder.append(".");
        // 创建这个属性数据类型的的 MetaClass 对象
        MetaClass metaProp = metaClassForProperty(propertyName);
        // 然后根据父节点的 MetaClass 对象,查找子节点的属性,进行递归查询
        metaProp.buildProperty(prop.getChildren(), builder);
      }
    } else {
      // 不包含,然后获取属性名称
      String propertyName = reflector.findPropertyName(name);
      if (propertyName != null) {
        builder.append(propertyName);
      }
    }
    return builder;
  }
  // 是否有默认的构造方法
  public boolean hasDefaultConstructor() {
    return reflector.hasDefaultConstructor();
  }

}

MetaObject

MetaObject 是对象层级的包装,对象的 getter、setter、filed、和他们的数据类型的方法。

MetaObject 是 Mybatis 提供的一个用于方便、优雅访问对象属性的对象,通过它可以简化代码、不需要 try/catch 各种 reflect 异常,同时它支持对 JavaBean、Collection、Map 三种类型对象的操作。

MetaObject 包装了 objectWrapper,从而提供了对 对象属性 的操作。

反射包的大部分类都是为 MetaObject 服务的,这个是对外暴露的对象原信息操作的接口。

服务类包括:Reflector、ReflectorFactory、MetaClass、ObjectFactory 接口和实现、Invoker 接口和实现、ObjectWrapper 接口和实现、Property 属性工具类。

包装关系:MetaObject -> ObjectWrapper -> MetaClass -> Reflector -> 元类的基础信息(filed、getter、setter 方法、读写属性、成员的数据类型、方法的调用)。

应用场景

  • 将对象中的值(parameterType所指定的对象)映射到具体的sql中
<insert id="insertAuthor" parameterType="domain.blog.Author">
  insert into Author (id,username,password,email,bio)
  values (#{id},#{username},#{password},#{email},#{bio})
</insert>
  • 将查询出来的结果填充到具体的对象属性中(由resultMap/resultType指定)
<select id="selectPerson" parameterType="int" resultType="hashmap">
  SELECT * FROM PERSON WHERE ID = #{id}
</select>
MetaObject
public class MetaObject {

  private final Object originalObject;  //原始JavaBean对象
  private final ObjectWrapper objectWrapper; //其中封装了originalObject对象
  private final ObjectFactory objectFactory; //创建对象的工厂
  private final ObjectWrapperFactory objectWrapperFactory; //创建封装对象的工厂
  private final ReflectorFactory reflectorFactory; //反射工厂

  private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
    this.originalObject = object;
    this.objectFactory = objectFactory;
    this.objectWrapperFactory = objectWrapperFactory;
    this.reflectorFactory = reflectorFactory;
    //赋值给objectWrapper
    if (object instanceof ObjectWrapper) {
      this.objectWrapper = (ObjectWrapper) object;
    } else if (objectWrapperFactory.hasWrapperFor(object)) {
      this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
    } else if (object instanceof Map) {
      this.objectWrapper = new MapWrapper(this, (Map) object);
    } else if (object instanceof Collection) {
      this.objectWrapper = new CollectionWrapper(this, (Collection) object);
    } else {
      this.objectWrapper = new BeanWrapper(this, object);
    }
  }

  public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
    if (object == null) {
      //系统初始化,默认的对象
      return SystemMetaObject.NULL_META_OBJECT;
    } else {
      return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
    }
  }

  public ObjectFactory getObjectFactory() {
    return objectFactory;
  }

  public ObjectWrapperFactory getObjectWrapperFactory() {
    return objectWrapperFactory;
  }

  public ReflectorFactory getReflectorFactory() {
    return reflectorFactory;
  }

  public Object getOriginalObject() {
    return originalObject;
  }

  public String findProperty(String propName, boolean useCamelCaseMapping) {
    return objectWrapper.findProperty(propName, useCamelCaseMapping);
  }

  public String[] getGetterNames() {
    return objectWrapper.getGetterNames();
  }

  public String[] getSetterNames() {
    return objectWrapper.getSetterNames();
  }

  public Class<?> getSetterType(String name) {
    return objectWrapper.getSetterType(name);
  }

  public Class<?> getGetterType(String name) {
    return objectWrapper.getGetterType(name);
  }

  //判断属性表达式指定属性是 否有 setter 方法
  public boolean hasSetter(String name) {
    return objectWrapper.hasSetter(name);
  }
  //判断属性表达式指定属性是 否有 getter 方法
  public boolean hasGetter(String name) {
    return objectWrapper.hasGetter(name);
  }
  //获取对象属性
  public Object getValue(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        return null;
      } else {
        return metaValue.getValue(prop.getChildren());
      }
    } else {
      return objectWrapper.get(prop);
    }
  }
  //设置对象属性
  public void setValue(String name, Object value) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        if (value == null) {
          // don't instantiate child path if value is null
          return;
        } else {
          // 为属性表达式指定的属性创建相应的MetaObject对象
          metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
        }
      }
      metaValue.setValue(prop.getChildren(), value);
    } else {
      objectWrapper.set(prop, value);
    }
  }
  //根据属性名称获得MetaObject对象
  public MetaObject metaObjectForProperty(String name) {
    Object value = getValue(name);
    return MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
  }

  public ObjectWrapper getObjectWrapper() {
    return objectWrapper;
  }

  /**
   * 是否是集合
   * @return
   */
  public boolean isCollection() {
    return objectWrapper.isCollection();
  }

  /**
   * 向集合中添加元素
   * @param element
   */
  public void add(Object element) {
    objectWrapper.add(element);
  }

  /**
   * 向集合中添加多个元素
   * @param list
   * @param <E>
   */
  public <E> void addAll(List<E> list) {
    objectWrapper.addAll(list);
  }

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