02_Spring

今天内容介绍

  1. Spring框架的IOC基于注解的方式
  • 注解类型
  • 注解生命周期
  1. Spring框架整合JUnit单元测试
  2. AOP的概述
  3. AOP的底层实现原理(了解)
  4. 动态代理
  • JDK实现的动态代理
  • CGLIB实现的动态代理
  • AspectJ的配置文件方式

技术分析之Spring框架的IOC功能之注解的方式


Spring框架的IOC之注解方式的快速入门
1, 步骤一:导入注解开发所有需要的jar包

  • 引入IOC容器必须的6个jar包
  • 多引入一个:Spring框架的AOP的jar包,spring-aop的jar包

2, 步骤二:创建对应的包结构,编写Java的类

  • UserService -- 接口
  • UserServiceImpl -- 具体的实现类
package com.huachao.demo1;
public interface UserService {
    public void sayHello();
}
package com.huachao.demo1;
import org.springframework.stereotype.Component;
/**
 * 组件注解,标记类@Component(value="userService")等价于
 * <bean id="userService" class="com.huachao.demo1.UserServiceImp"/>
 */
@Component(value="userService")
public class UserServiceImp implements UserService {
    @Override
    public void sayHello() {
        System.out.println("Spring Hello!!");
    }
}

3, 步骤三:在src的目录下,创建applicationContext.xml的配置文件,然后引入约束。注意:因为现在想使用注解的方式,那么引入的约束发生了变化

  • 需要引入context的约束,参考spring-framework-4.2.4.RELEASE/docs/spring-framework-reference/html/xsd-configuration.html40.2.8 the context schema
 <beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->
 
 </beans>

4, 步骤四:在applicationContext.xml配置文件中开启组件扫描

  • Spring的注解开发:组件扫描
    <context:component-scan base-package="com.huachao.demo1"/>

  • 注意:可以采用如下配置
    <context:component-scan base-package="com.huachao"/> 这样是扫描com.huachao包下所有的内容

  • applicationContext.xml完整代码如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->
    <!-- 开启注解扫描 -->
    <context:component-scan base-package="com.huachao.demo1"/>
    <!-- 也可以<context:component-scan base-package="com.huachao"/> -->
</beans>

5, 步骤五:在UserServiceImpl的实现类上添加注解

  • @Component(value="userService") -- 相当于在XML的配置方式中 <bean id="userService" class="...">

6, 步骤六:编写测试代码

@Test
    public void Run1()
    {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService us = (UserService) ac.getBean("userService");
        us.sayHello();
    }

<font color=red>注意:</font>
1,在资料/applicationContext.xml文件中,提供了spring中所有的约束


Spring框架中Bean管理的常用注解
1, @Component:组件.(作用在类上)

2, Spring中提供@Component的三个衍生注解:(功能目前来讲是一致的)

  • @Controller    -- 作用在WEB层

  • @Service     -- 作用在业务层

  • @Repository    -- 作用在持久层

  • 说明:这三个注解是为了让标注类本身的用途清晰,Spring在后续版本会对其增强

3, 属性注入的注解(说明:使用注解注入的方式,可以不用提供set方法)

  • 如果是注入的普通类型,可以使用value注解

  • @Value -- 用于注入普通类型

  • 如果注入的是对象类型,使用如下注解

  • @Autowired -- 默认按类型进行自动装配
      - 如果想按名称注入
      - @Qualifier -- 强制使用名称注入

  • @Resource -- 相当于@Autowired和@Qualifier一起使用
      -强调:Java提供的注解
      - 属性使用name属性


    @Value("美美")
    private String name;
    //@Autowired会自动寻找UserDao或其实现类注入
    @Autowired
    //Qualifier按名次注入
    @Qualifier(value="userDao")
    private UserDao userDao;

    //这是Java注解,Spring框架也提供支持
    @Resource(name="userDao")
    private UserDao userDao;

Bean的作用范围和生命周期的注解
1, Bean的作用范围注解

  • 注解为@Scope(value="prototype"),作用在类上。值如下:
  • singleton   -- 单例,默认值
  • prototype   -- 多例

2, Bean的生命周期的配置(了解)

  • 注解如下:
  • @PostConstruct  -- 相当于init-method
  • @PreDestroy   -- 相当于destroy-method

Spring框架整合JUnit单元测试
1, 为了简化了JUnit的测试,使用Spring框架也可以整合测试
2, 具体步骤

  • 要求:必须先有JUnit的环境(即已经导入了JUnit4的开发环境)!!
  • 步骤一:在程序中引入:spring-test.jar(Spring提供,在 spring-framework-4.2.4.RELEASE\libs\spring-test-4.2.4.RELEASE.jar)
  • 步骤二:在具体的测试类上添加注解
package com.huachao.demo1;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo1 {
    @Resource(name="userService")
    private UserService userService;
    @Test
    public void Run1()
    {
        userService.sayHello();
    }
}

需求分析

  • 使用AOP技术对DAO层操作进行增强功能

技术分析之Spring框架的核心功能之AOP技术


AOP的概述

  1. 什么是AOP的技术?
  • 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程
  • AOP是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构
  • AOP最早由AOP联盟的组织提出的,制定了一套规范.Spring将AOP思想引入到框架中,必须遵守AOP联盟的规范
  • 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
  • AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型
  • 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
  1. AOP:面向切面编程.(思想.---解决OOP遇到一些问题)

  2. AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)

  3. 为什么要学习AOP

  • 可以在不修改源代码的前提下,对程序进行增强!!

Spring框架的AOP的底层实现
1, Srping框架的AOP技术底层也是采用的代理技术,代理的方式提供了两种

  • 基于JDK的动态代理
  • 必须是面向接口的,只有实现了具体接口的类才能生成代理对象

2, 基于CGLIB动态代理

  • 对于没有实现了接口的类,也可以产生代理,产生这个类的子类的方式

3, Spring的传统AOP中根据类是否实现接口,来采用不同的代理方式

  • 如果实现类接口,使用JDK动态代理完成AOP
  • 如果没有实现接口,采用CGLIB动态代理完成AOP

JDK的动态代理(代码了解,理解原理)

  • 使用Proxy类来生成代理对象的一些代码如下:
 /**
  * 使用JDK的方式生成代理对象
  * @author Administrator
  */
 public class MyProxyUtils {
 public static UserDao getProxy(final UserDao dao) {
 // 使用Proxy类生成代理对象
 UserDao proxy = (UserDao) Proxy.newProxyInstance(dao.getClass().getClassLoader(),
 dao.getClass().getInterfaces(), new InvocationHandler() {
 
 // 代理对象方法一直线,invoke方法就会执行一次
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 if("save".equals(method.getName())){
 System.out.println("记录日志...");
 // 开启事务
 }
 // 提交事务
 // 让dao类的save或者update方法正常的执行下去
 return method.invoke(dao, args);
 }
 });
 // 返回代理对象
 return proxy;
 }
 }

例:JDK的动态代理的使用
UserDao接口

package com.huachao.demo2;
public interface UserDao {
    public void save();
    public void update();
}

接口实现类

package com.huachao.demo2;
public class UserDaoImp implements UserDao {
    @Override
    public void save() {
        System.out.println("保存...");
    }
    @Override
    public void update() {
        System.out.println("更新...");
    }
}

动态代理的工具类

package com.huachao.demo2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyProxyUtil {
    public static UserDao getProxy(final UserDao dao){
        UserDao proxy =(UserDao) Proxy.newProxyInstance(dao.getClass().getClassLoader(), 
                dao.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if("save".equals(method.getName()))
                        {
                            System.out.println("记录日志");
                        }
                        return method.invoke(dao, args);
                    }
                });
        return proxy;
    }
}

测试代码

    @Test
    public void Run1()
    {
        UserDao dao = new UserDaoImp();
        
        UserDao proxy = MyProxyUtil.getProxy(dao);
        proxy.save();
        proxy.update();
    }

CGLIB的代理技术(代码了解)

  1. 引入CBLIB的开发包
  • 如果想使用CGLIB的技术来生成代理对象,那么需要引入CGLIB的开发的jar包,在Spring框架核心包中已经引入了CGLIB的开发包了。所以直接引入Spring核心开发包即可!
  1. 编写相关的代码
 public static OrderDaoImpl getProxy(){
 // 创建CGLIB核心的类
 Enhancer enhancer = new Enhancer();
 // 设置父类
 enhancer.setSuperclass(OrderDaoImpl.class);
 // 设置回调函数
 enhancer.setCallback(new MethodInterceptor() {
 @Override
 public Object intercept(Object obj, Method method, Object[] args,
 MethodProxy methodProxy) throws Throwable {
 if("save".equals(method.getName())){
 // 记录日志
 System.out.println("记录日志了...");
 }
 return methodProxy.invokeSuper(obj, args);
 }
 });
 // 生成代理对象
 OrderDaoImpl proxy = (OrderDaoImpl) enhancer.create();
 return proxy;
 }

例:使用Spring核心包提供的CGLib动态代理技术
继续使用上例的接口和实现类
CGLib的工具类

package com.huachao.demo2;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class MyCGLibUtils {
    public static UserDao getProxy(){
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(UserDaoImp.class);
        //设置回调函数
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                if("save".equals(method.getName()))
                {
                    System.out.println("记录日志");
                }
                //让方法正常执行
                return methodProxy.invokeSuper(obj, args);
            }
        });
        
        UserDao dao = (UserDao) enhancer.create();
        return dao;
    }
}

测试代码


    @Test
    public void Run2()
    {
        UserDao proxy = MyCGLibUtils.getProxy();
        proxy.save();
        proxy.update();
    }

注意:上例不使用接口也能生成动态代理对象


Spring基于AspectJ的AOP的开发


技术分析之AOP的相关术语

  1. Joinpoint(连接点)  -- 所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
  2. Pointcut(切入点)   -- 所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
  3. Advice(通知/增强)  -- 所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
  4. Introduction(引介)  -- 引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field
  5. Target(目标对象)   -- 代理的目标对象
  6. Weaving(织入)   -- 是指把增强应用到目标对象来创建新的代理对象的过程
  7. Proxy(代理)   -- 一个类被AOP织入增强后,就产生一个结果代理类
  8. Aspect(切面)    -- 是切入点和通知的结合,以后咱们自己来编写和配置的

技术分析之AspectJ的XML方式完成AOP的开发
1, 步骤一:创建JavaWEB项目,引入具体的开发的jar包

  • 先引入Spring框架开发的基本开发包

  • 再引入Spring框架的AOP的开发包

  • spring的传统AOP的开发的包
      -spring-aop-4.2.4.RELEASE.jar(Spring的AOP包)
      - com.springsource.org.aopalliance-1.0.0.jar(AOP联盟的规范包)

  • aspectJ的开发包
      -com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar(aspectJ的包)
      -spring-aspects-4.2.4.RELEASE.jar(Spring整合aspectJ的包)

2, 步骤二:创建Spring的配置文件,引入具体的AOP的schema约束
参考spring-framework-4.2.4.RELEASE/docs/spring-framework-reference/html/xsd-configuration.html中的40.2.7 the aop schema


 <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="
 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

3, 步骤三:创建包结构,编写具体的接口和实现类

  • com.itheima.demo1
  • CustomerDao -- 接口
  • CustomerDaoImpl -- 实现类

4, 步骤四:将目标类配置到Spring中
  <bean id="customerDao" class="com.itheima.demo3.CustomerDaoImpl"/>

5, 步骤五:定义切面类


 public class MyAspectXml {
 // 定义通知
 public void log(){
 System.out.println("记录日志...");
 }
 }

6, 步骤六:在配置文件中定义切面类
  <bean id="myAspectXml" class="com.itheima.demo3.MyAspectXml"/>

7, 步骤七:在配置文件中完成aop的配置

 <aop:config>
 <!-- 引入切面类 -->
 <aop:aspect ref="myAspectXml">
 <!-- 定义通知类型:切面类的方法和切入点的表达式 -->
 <aop:before method="log" pointcut="execution(public * com.itheima.demo3.CustomerDaoImpl.save(..))"/>
 </aop:aspect>
 </aop:config>

8, 完成测试


 @RunWith(SpringJUnit4ClassRunner.class)
 @ContextConfiguration("classpath:applicationContext.xml")
 public class Demo3 {
 @Resource(name="customerDao")
 private CustomerDao customerDao;
 @Test
 public void run1(){
 customerDao.save();
 customerDao.update();
 customerDao.delete();
 }
 }

例:使用aspectJ实现动态代理

  1. 新建项目,本例命名为day36_aop

  2. 导包,参考上面的步骤,本例导入的所有包如下:
    com.springsource.org.aopalliance-1.0.0.jar com.springsource.org.apache.commons.logging-1.1.1.jar com.springsource.org.apache.log4j-1.2.15.jar com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar spring-aop-4.2.4.RELEASE.jar spring-aspects-4.2.4.RELEASE.jar spring-beans-4.2.4.RELEASE.jar spring-context-4.2.4.RELEASE.jar spring-core-4.2.4.RELEASE.jar spring-expression-4.2.4.RELEASE.jar spring-test-4.2.4.RELEASE.jar

  3. 导入log4j.properties到src目录下

  4. 在src目录下,新建applicationContext.xml,约束参考上面步骤

  5. 编写接口和显示类

package com.huachao.demo1;
public interface CustomerDao {
    public void save();
    public void update();
}
package com.huachao.demo1;
public class CustomerDaoImp implements CustomerDao {
    @Override
    public void save() {
        System.out.println("save");
    }
    @Override
    public void update() {
        System.out.println("update");
    }
}

定义切面类

package com.huachao.demo1;

public class MyAspectJXml {
    public void log()
    {
        System.out.println("记录日志...");
    }
}

applicationContext.xml完整代码

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->
    
    <bean id="customerDao" class="com.huachao.demo1.CustomerDaoImp"/>
    <bean id="myAspectJXml" class="com.huachao.demo1.MyAspectJXml"/>
    
    <aop:config>
        <!-- 引入切面 -->
        <aop:aspect ref="myAspectJXml">
            <!-- 定义通知类型:切面类的方法和切入点的表达式 -->
            <!-- 切入点的表达式 
                1. execution()    固定的,不能不写
                2. public 可以省略不写
                3. void,返回值可以出现 * 表示任意的返回值,返回值类型不能不写
                4. 可以使用 * 代替的,不能不编写的,简写方式:*..*方法
                5. *DaoImpl
                6. 方法 save*
                7. 方法的参数:
            -->
            <!-- <aop:before method="log" pointcut="execution(* com.huachao.demo1.CustomerDaoImp.save(..))"/> -->
            <aop:before method="log" pointcut="execution(public * com.huachao.demo1.CustomerDaoImp.save())"/>
        </aop:aspect>
    </aop:config>
</beans>

测试代码

package com.huachao.demo1;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo1 {
    @Resource(name="customerDao")
    private CustomerDao customerDao;
    
    @Test
    public void Run1()
    {
        customerDao.save();
        customerDao.update();
    }
}

切入点的表达式
1,再配置切入点的时候,需要定义表达式,重点的格式如下:execution(public * *(..)),具体展开如下:

  • 切入点表达式的格式如下:

  • execution([修饰符] 返回值类型 包名.类名.方法名(参数))

  • 修饰符可以省略不写,不是必须要出现的。

  • 返回值类型是不能省略不写的,根据你的方法来编写返回值。可以使用 * 代替。

  • 包名例如:com.itheima.demo3.BookDaoImpl

  • 首先com是不能省略不写的,但是可以使用 * 代替

  • 中间的包名可以使用 * 号代替

  • 如果想省略中间的包名可以使用 ..

  • 类名也可以使用 * 号代替,也有类似的写法:*DaoImpl

  • 方法也可以使用 * 号代替

  • 参数如果是一个参数可以使用 * 号代替,如果想代表任意参数使用 ..

例:切点的几种写法
切入点的表达式:

  1. execution() 固定的,不能不写
  2. public 可以省略不写
  3. void,返回值可以出现 * 表示任意的返回值,返回值类型不能不写
  4. 包名:可以使用 * 代替的,不能不编写的,可以简写方式:..方法
  5. 类名:*DaoImpl
  6. 方法 save*
  7. 方法的参数:一个*表示一个参数,..表示任意的参数,相当于可变参数

            <!-- <aop:before method="log" pointcut="execution(public void com.huachao.demo1.CustomerDaoImp.save())"/> -->
            <!-- <aop:before method="log" pointcut="execution(void com.huachao.demo1.CustomerDaoImp.save())"/> -->
            <!-- <aop:before method="log" pointcut="execution(* com.huachao.demo1.CustomerDaoImp.save())"/> -->
            <!-- <aop:before method="log" pointcut="execution(* com.huachao.*.CustomerDaoImp.save())"/> -->
            <!-- <aop:before method="log" pointcut="execution(* *..*.CustomerDaoImp.save())"/> -->
            <!-- <aop:before method="log" pointcut="execution(* com.huachao.demo1.*DaoImp.save())"/> -->
            <!-- <aop:before method="log" pointcut="execution(* com.huachao.demo1.CustomerDaoImp.save*())"/> -->
            <!-- <aop:before method="log" pointcut="execution(* com.huachao.demo1.CustomerDaoImp.*())"/> -->
            <!-- <aop:before method="log" pointcut="execution(* com.huachao.demo1.CustomerDaoImp.save(..))"/> -->

AOP的通知类型
1, 前置通知

  • 在目标类的方法执行之前执行。
  • 配置文件信息:<aop:after method="before" pointcut-ref="myPointcut3"/>
  • 应用:可以对方法的参数来做校验

2, 最终通知

  • 在目标类的方法执行之后执行,如果程序出现了异常,最终通知也会执行。
  • 在配置文件中编写具体的配置:<aop:after method="after" pointcut-ref="myPointcut3"/>
  • 应用:例如像释放资源

3, 后置通知

  • 方法正常执行后的通知。
  • 在配置文件中编写具体的配置:<aop:after-returning method="afterReturning" pointcut-ref="myPointcut2"/>
  • 应用:可以修改方法的返回值

4, 异常抛出通知

  • 在抛出异常后通知
  • 在配置文件中编写具体的配置:<aop:after-throwing method="afterThorwing" pointcut-ref="myPointcut3"/>
  • 应用:包装异常的信息

5, 环绕通知

  • 方法的执行前后执行。
  • 在配置文件中编写具体的配置:<aop:around method="around" pointcut-ref="myPointcut2"/>
  • 要注意:目标的方法默认不执行,需要使用ProceedingJoinPoint对来让目标对象的方法执行。
/**
  * 环绕通知:方法执行之前和方法执行之后进行通知,默认的情况下,目标对象的方法不能执行的。需要手动让目标对象的方法执行
  */
 public void around(ProceedingJoinPoint joinPoint){
 System.out.println("环绕通知1...");
 try {
 // 手动让目标对象的方法去执行
 joinPoint.proceed();
 } catch (Throwable e) {
 e.printStackTrace();
 }
 System.out.println("环绕通知2...");
 }

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

推荐阅读更多精彩内容