Spring的IOC

一、入門案例

1.導入依賴:

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>5.1.5.RELEASE</version>
</dependency>

2.編寫beans.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 
    bean 標簽:用于配置讓 spring 創建對象,并且存入 ioc 容器之中
    id 屬性:對象的唯一標識。
    class 屬性:指定要創建對象的全限定類名
    -->
    <!-- 配置 service -->
    <bean id="userService" class="com.hcx.service.impl.UserSerivceImpl"></bean>
    <!-- 配置 dao -->
    <bean id="userDao" class="com.hcx.dao.impl.UserDaoImpl"></bean>
</beans>

3.使用

public class UserController {

    public static void main(String[] args) {
        //獲取核心容器
        //ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");//更常用
        ApplicationContext applicationContext = new FileSystemXmlApplicationContext("D:\\config\\beans.xml");
        //根據id獲取Bean對象
        //方式一
        UserService userService = (UserService) applicationContext.getBean("userService");
        //方式二
        UserDao userDao = applicationContext.getBean("userDao", UserDao.class);
        //com.hcx.service.impl.UserSerivceImpl@3e6fa38a
        System.out.println(userService);
        //com.hcx.dao.impl.UserDaoImpl@66a3ffec
        System.out.println(userDao);
//        UserService userService = (UserService) BeanFactory.getBean("userService");
//        userService.saveUser();
    }
}

二、重要類詳解

1.BeanFactory

在構建核心容器時,創建對象采取的策略是延遲加載。即根據id獲取對象時才創建對象。
適用場景:多例對象

public class UserController {
    public static void main(String[] args) {
        Resource resource = new ClassPathResource("beans.xml");
        BeanFactory beanFactory = new XmlBeanFactory(resource);
        UserService userService = (UserService) beanFactory.getBean("userService");
        System.out.println(userService);
    }
}
image.png

2.ApplicationContext

在構建核心容器時,創建對象采取的是立即加載的方式。即一讀取完配置文件就馬上創建對象。
適用場景:單例對象

public class UserController {
    public static void main(String[] args) {
        //獲取核心容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
//        ApplicationContext applicationContext = new FileSystemXmlApplicationContext("D:\\config\\beans.xml");
        //根據id獲取Bean對象
        //方式一
        UserService userService = (UserService) applicationContext.getBean("userService");
        //方式二
        UserDao userDao = applicationContext.getBean("userDao", UserDao.class);
        //com.hcx.service.impl.UserSerivceImpl@3e6fa38a
        System.out.println(userService);
        //com.hcx.dao.impl.UserDaoImpl@66a3ffec
        System.out.println(userDao);
    }
}
image.png
image.png

ApplicationContext的三個常用實現類:
①ClassPathXmlApplicationContext
可以加載類路徑下的配置文件,要求配置文件必須在類路徑下,否則無法加載。

②FileSystemXmlApplicationContext
可以加載磁盤任意路徑下的配置文件(須有訪問權限)

③AnnotationConfigApplicationContext
用于讀取注解創建的容器

三、Bean詳解

1.創建Bean對象的三種方式

①方式一:采用默認構造函數
<bean id="userService" class="com.hcx.service.impl.UserSerivceImpl"></bean>
spring配置文件中使用bean標簽,僅配置id和class屬性(沒有其他屬性和標簽),此時采用默認構造函數創建對象,如果類中沒有默認構造函數,則對象無法創建。

    <!-- 
        bean 標簽:用于配置讓 spring 創建對象,并且存入 ioc 容器之中
        id 屬性:對象的唯一標識。
        class 屬性:指定要創建對象的全限定類名
    -->
    <!-- 配置 service -->
    <bean id="userService" class="com.hcx.service.impl.UserSerivceImpl"></bean>

②方式二:使用普通工廠中的方法創建對象
即使用某個類中的方法創建對象,并存入spring容器
當使用一些外部類時,如引入的jar中的類,都是字節碼文件。

InstanceFactory:

/**
 * 模擬工廠類(該類可能存在于jar包中,無法修改代碼提供默認構造函數)
 */
public class InstanceFactory {
    public UserService getUserService(){
        return new UserSerivceImpl();
    }
}

此時要獲取的是InstanceFactory 類中的getUserService返回值

    <!--得到工廠實例-->
    <bean id="instanceFactory" class="com.hcx.factory.InstanceFactory"></bean>
    <!--
        factory-bean:指定工廠bean
        factory-method:獲取對象的方法名
        userService對象由instanceFactory id所指向的工廠中的getUserService方法獲取
    -->
    <bean id="userService" factory-bean="instanceFactory" factory-method="getUserService"></bean>

③方式三:使用工廠中的靜態方法創建對象
使用某個類中的靜態方法,并存入spring容器

StaticFactory:

public class StaticFactory {
    public static UserService getUserService(){
        return new UserSerivceImpl();
    }
}

xml配置:

<bean id="userService" class="com.hcx.factory.StaticFactory" factory-method="getUserService"></bean>

④注解方式:
作用和xml配置的<bean>標簽功能一樣
@Component:把當前類對象存入spring容器中
屬性value用于指定bean的id,不寫時默認為類名首字母小寫
@Controller:一般用于表現層
@Service:一般用于業務層
@Repository:一般用于持久層

使用注解的方式,需要加入context命名空間,并且要配置告訴spring使用注解的方式,需要spring去掃描對應的包,配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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">

    <!-- 告知 spring 創建容器時要掃描的包 -->
    <context:component-scan base-package="com.hcx"></context:component-scan>

</beans>
image.png

2.bean對象的作用范圍

①xml配置:
默認情況spring創建的bean都是單例的。
bean的作用范圍通過bean標簽的scope屬性可以指定:
取值:

  • singleton:單例(默認值)
  • prototype:多例
  • request:作用于web應用的請求范圍
  • session:作用于web應用的會話范圍
  • global-session:作用于集群環境的會話范圍(全局會話范圍),當不是集群環境時,等同于session
<bean id="userService" class="com.hcx.service.impl.UserSerivceImpl" scope="singleton"></bean>

②注解配置:
@Scope:指定bean的作用范圍
屬性value:指定范圍的取值,常用取值:singletonprototype

3.bean對象的生命周期

①單例對象
生命周期跟容器的相同,讓其創建時對象創建,只要容器還在,對象一直存活,容器銷毀,對象死亡。
通過init-methoddestory-method屬性指定
UserSerivceImpl:

public class UserSerivceImpl implements UserService {
    public UserSerivceImpl() {
        System.out.println("對象創建了");
    }
    public void saveUser() {
        System.out.println("service實現類被調用了");
//        userDao.saveUser();
    }
    public void init() {
        System.out.println("對象初始化");
    }
    public void destory() {
        System.out.println("對象銷毀");
    }
}

xml:

    <bean id="userService" class="com.hcx.service.impl.UserSerivceImpl" scope="singleton"
          init-method="init" destroy-method="destory"></bean>

調用:

public class UserController {
    public static void main(String[] args) {
        //獲取核心容器
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        //根據id獲取Bean對象
        //方式一
        UserService userService = (UserService) applicationContext.getBean("userService");
        //方式二
//        UserDao userDao = applicationContext.getBean("userDao", UserDao.class);
        userService.saveUser();
        //手動關閉容器
        applicationContext.close();
    }
}

結果:

對象創建了
對象初始化
service實現類被調用了
對象銷毀

②多例對象
出生:使用對象時spring框架創建
存活:對象只要在使用則一直存活
死亡:當對象長時間不用且沒有其他對象引用時,由垃圾回收器回收

即使手動關閉容器,對象也不會銷毀

    <bean id="userService" class="com.hcx.service.impl.UserSerivceImpl" scope="prototype"
          init-method="init" destroy-method="destory"></bean>

打印結果:

對象創建了
對象初始化
service實現類被調用了

③使用注解指定生命周期
作用與bean標簽中使用init-methoddestroy-method作用相同
PostConstruct:用于指定初始化方法
PreDestroy:用于指定銷毀方法

UserSerivceImpl :

@Service("userService")
public class UserSerivceImpl implements UserService {
    @Resource(name = "userDao1")
    private UserDao userDao;
    @PostConstruct
    public void init(){
        System.out.println("初始化方法");
    }
    @PreDestroy
    public void destroy(){
        System.out.println("銷毀方法");
    }
    public void saveUser() {
        userDao.saveUser();
    }
}

調用:

public class UserController {
    @Autowired
    private UserService userService;
    public static void main(String[] args) {
        //獲取核心容器
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        //根據id獲取Bean對象
        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.saveUser();
        //手動關閉才會調用銷毀方法
        applicationContext.close();
    }
}

打印結果:

初始化方法
保存用戶1
銷毀方法

四、Spring的依賴注入

依賴注入:Dependency Injection。它是 spring 框架核心 ioc 的具體實現
程序在編寫時,通過控制反轉,把對象的創建交給了 spring,但是代碼中不可能出現沒有依賴的情況。
ioc 解耦只是降低他們的依賴關系,但不會消除。
例如:我們的業務層仍會調用持久層的方法。
這種業務層和持久層的依賴關系,在使用 spring 之后,就讓 spring 來維護了。
簡單的說,就是框架把持久層對象傳入業務層,而不用我們自己去獲取。

依賴關系的管理:交由spring來維護
當前類需要用到其他類對象時,由spring為我們提供,我們只需要在配置文件中說明。

能注入的數據類型:

  • 基本類型和String
  • 其他bean類型(在配置文件或者注解配置過的bean)
  • 復雜類型(集合類型)

注入的方式:

  • 使用構造器
  • 使用set方法
  • 使用注解

注意:經常變化的一些數據不適用于注入的方式

1.構造函數注入

在bean標簽中使用標簽constructor-arg,屬性:

  • type:指定要注入的數據的數據類型,該數據類型是構造函數中某個或某些參數的數據類型
  • index:指定給構造函數中指定索引位置的參數賦值。(索引從0開始)
  • name:指定給構造函數中指定名稱的參數賦值
  • value:賦的值是基本數據類型和 String 類型
  • ref:賦的值是其他 bean 類型(必須是在配置文件中配置過的 bean)

注意:typeindexname用于指定給構造函數中的哪個參數賦值

UserSerivceImpl:

public class UserSerivceImpl implements UserService {
    private String name;
    private Integer age;
    private Date birthday;
    public UserSerivceImpl(String name, Integer age, Date birthday) {
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }
    public void saveUser() {
        System.out.println("service實現類被調用了:"+name+","+age+","+birthday);
    }
}

beans.xml

    <bean id="userService" class="com.hcx.service.impl.UserSerivceImpl">
        <constructor-arg name="name" value="極多人小紅"></constructor-arg>
        <constructor-arg name="age" value="24"></constructor-arg>
        <constructor-arg name="birthday" ref="date"></constructor-arg>
    </bean>

    <!--配置日期對象-->
    <bean id="date" class="java.util.Date"></bean>

使用:

public class UserController {

    public static void main(String[] args) {
        //獲取核心容器
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        //根據id獲取Bean對象
        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.saveUser();
    }
}

結果:

service實現類被調用了:極多人小紅,24,Wed Dec 11 20:09:09 CST 2019

此種方式的優缺點:
優點:在獲取bean對象時,注入數據是必須的操作,否則無法創建對象(如果同時提供無參構造器則沒問題)
缺點:改變了bean對象的實例化方式,使得在創建對象時,即使不使用這些數據也必須提供。

2.set 方法注入

通過配置文件給 bean 中的屬性傳值:使用 set 方法的方式,
property標簽:

  • name:找的是類中 set 方法后面的部分(并不是屬性的名稱)
  • ref:給屬性賦值是其他 bean 類型的
  • value:給屬性賦值是基本數據類型和 string 類型的

UserSerivceImpl:

 public class UserSerivceImpl implements UserService {
    private String name;
    private Integer age;
    private Date birthday;
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public void saveUser() {
        System.out.println("service實現類被調用了:"+name+","+age+","+birthday);
    }
}

beans.xml:

    <!-- 配置 service -->
    <bean id="userService" class="com.hcx.service.impl.UserSerivceImpl">
        <property name="name" value="極多人小紅"></property>
        <property name="age" value="21"></property>
        <property name="birthday" ref="date"></property>
    </bean>

    <!--配置日期對象-->
    <bean id="date" class="java.util.Date"></bean>

優點:創建對象時沒有明確的限制,可以直接使用默認構造函數
缺點:如果某個成員必須有值,則獲取對象時有可能set方法沒有執行。

復雜類型注入

用于給List結構注入的標簽包括:listarrayset
用于給Map結構集合注入的標簽包括:mapproperties
即結構相同的數據類型,標簽都通用。

UserSerivceImpl:

public class UserSerivceImpl implements UserService {
    private String[] strArrs;
    private List<String> strList;
    private Set<String> strSet;
    private Map<String,String> strMap;
    private Properties properties;
    public void setStrArrs(String[] strArrs) {
        this.strArrs = strArrs;
    }
    public void setStrList(List<String> strList) {
        this.strList = strList;
    }
    public void setStrSet(Set<String> strSet) {
        this.strSet = strSet;
    }
    public void setStrMap(Map<String, String> strMap) {
        this.strMap = strMap;
    }
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
    public void saveUser() {
        System.out.println("service實現類被調用了");
        System.out.println(Arrays.toString(strArrs));
        System.out.println(strList);
        System.out.println(strSet);
        System.out.println(strMap);
        System.out.println(properties);
    }
}

beans.xml:

<bean id="userService" class="com.hcx.service.impl.UserSerivceImpl">
        <property name="strArrs">
            <array>
                <value>arr1</value>
                <value>arr2</value>
                <value>arr3</value>
            </array>
        </property>

        <property name="strList">
            <list>
                <value>list1</value>
                <value>list2</value>
                <value>list3</value>
            </list>
        </property>

        <property name="strSet">
            <set>
                <value>set1</value>
                <value>set2</value>
                <value>set3</value>
            </set>
        </property>

        <property name="strMap">
            <map>
                <entry key="keya" value="map1"></entry>
                <entry key="keyb">
                    <value>map2</value>
                </entry>
            </map>
        </property>

        <property name="properties">
            <props>
                <prop key="propertieskey1">properties1</prop>
                <prop key="propertieskey2">properties2</prop>
            </props>
        </property>
    </bean>

調用:

public class UserController {

    public static void main(String[] args) {
        //獲取核心容器
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        //根據id獲取Bean對象
        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.saveUser();
    }
}

打印結果:


image.png

3.注解注入

@Autowired:按照類型注入
只要容器中有唯一的一個bean對象類型和要注入的變量類型匹配,就能注入成功。
如果容器中沒有bean的類型和要注入的變量匹配,報錯。
如果容器中有多個類型匹配時,報錯。

image.png

注意:當有多個類型都匹配上時,會再次按照名稱匹配,如果相同了,也能匹配上。
即注入時的類的名稱private UserDao userDao2;userDao2與聲明時的注解@Repository("userDao2")匹配上了。

@Qualifier:按照類型注入的基礎之上再按照名稱注入。
(給方法參數注入時可以單獨使用,給類成員注入時則不能單獨使用,必須配合@Autowired注解)
value屬性:用于指定注入bean的id

@Service("userService")
public class UserSerivceImpl implements UserService {
    @Autowired
    @Qualifier("userDao1")
    private UserDao userDao;
    public void saveUser() {
        userDao.saveUser();
    }
}

@Resource:按照bean的id注入,可以單獨使用
屬性name:用于指定bean的id

@Service("userService")
public class UserSerivceImpl implements UserService {
//    @Autowired
//    @Qualifier("userDao1")
    @Resource(name = "userDao1")
    private UserDao userDao;
    public void saveUser() {
        userDao.saveUser();
    }
}

總結:以上三個注解只能注入bean類型的數據。

@Value:用于注入基本類型和String類型數據
屬性value:指定數據的值,可以使用SpEL(spring的el表達式)
SpEL寫法:${表達式}

位置:變量、方法

五、使用純注解的方式配置(沒有beans.xml配置文件)

beans.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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">

    <!-- 告知 spring 創建容器時要掃描的包 -->
    <context:component-scan base-package="com.hcx"></context:component-scan>

    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner"  scope="prototype">
        <constructor-arg name="ds" ref="dataSource"></constructor-arg>
    </bean>

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/springdemo"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
</beans>

@Configuration:指定當前類是一個配置類
當配置類作為AnnotationConfigApplicationContext對象創建的參數傳遞時,可以省略該注解。
@ComponentScan(basePackage="com.hcx"):指定spring在創建容器時需要掃描的包
屬性value和basePackages:作用相同,都是用于指定創建容器時需要掃描的包。
使用此注解就相當于在xml中配置了:<context:component-scan base-package="com.hcx"></context:component-scan>
@Bean用于把當前方法的返回值作為bean對象存入spring的ioc容器中
屬性name:指定bean的id,默認值為當前方法名
@import:導入其他配置類
屬性value:用于指定其他配置類的字節碼(使用了該注解的類就是主配置類)
@PropertySource:用于指定配置文件的路徑
屬性value:指定文件名稱和路徑(classpath:類路徑)

image.png

SpringConfiguration:

@Configuration
@ComponentScan("com.hcx")
public class SpringConfiguration {

    @Bean(name = "runner")
    @Scope("prototype")
    public QueryRunner createQueryRunner(DataSource dataSource) {
        return new QueryRunner(dataSource);
    }

    @Bean(name = "dataSource")
    public DataSource createDataSource() {
        try {
            ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
            comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver");
            comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/springdemo");
            comboPooledDataSource.setUser("root");
            comboPooledDataSource.setPassword("root");
            return comboPooledDataSource;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

測試:

public class UserServiceTest {
    @Test
    public void testSelectAll(){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        UserService userService = applicationContext.getBean("userService", UserService.class);
        List<User> userList = userService.findAll();
        for(User user : userList){
            System.out.println(user);
        }
    }
}

注意:使用注解配置,方法如果有參數,spring會尋找有沒有對應的bean對象,查找方式與Autowired一樣。

@import注解

當有多個配置類時,可以通過@import注解導入其他的配置類
主配置類:

@ComponentScan("com.hcx")
@Import(JdbcConfig.class)
public class SpringConfiguration {
}

Jdbc配置類:

public class JdbcConfig {

    @Bean(name = "runner")
    @Scope("prototype")
    public QueryRunner createQueryRunner(DataSource dataSource) {
        return new QueryRunner(dataSource);
    }

    @Bean(name = "dataSource")
    public DataSource createDataSource() {
        try {
            ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
            comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver");
            comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/springdemo");
            comboPooledDataSource.setUser("root");
            comboPooledDataSource.setPassword("root");
            return comboPooledDataSource;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

@PropertySource注解

使用讀取配置文件的方式讀取數據庫配置信息:
將數據庫的配置抽取到單獨的properties文件中:
jdbcConfig.properties:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/springdemo
jdbc.useranme=root
jdbc.password=root

JdbcConfig:

public class JdbcConfig {

    @Value("${jdbc.driver}")
    private String driver;

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    @Bean(name = "runner")
    @Scope("prototype")
    public QueryRunner createQueryRunner(DataSource dataSource) {
        return new QueryRunner(dataSource);
    }

    @Bean(name = "dataSource")
    public DataSource createDataSource() {
        try {
            ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
            comboPooledDataSource.setDriverClass(driver);
            comboPooledDataSource.setJdbcUrl(url);
            comboPooledDataSource.setUser(username);
            comboPooledDataSource.setPassword(password);
            return comboPooledDataSource;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

在配置類中指定讀取該配置:
SpringConfiguration:

@ComponentScan("com.hcx")
@Import(JdbcConfig.class)
@PropertySource("classpath:jdbcConfig.properties")
public class SpringConfiguration {
}

在方法參數上使用@Qualifier注解

當有多個數據源時,可以在創建對象時通過@Qualifier注解參數指定具體使用哪一個:

image.png
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容