2018-12-27 Spring框架學習

Spring框架官網下載教程:https://blog.csdn.net/saszyl/article/details/70148303

1. 面試必備知識點

一. SpringAOP,IOC實現原理

在面試當中,AOP實現原理、動態代理和靜態代理、Spring IOC的初始化過程、IOC原理、自己實現怎么實現一個IOC容器?這些東西都是經常會被問到的。
自己動手實現的 Spring IOC 和 AOP - 上篇

自己動手實現的 Spring IOC 和 AOP - 下篇

當沒有IOC,可以使用工廠模式來模擬IOC,即創建一個工廠類,在工廠類當中創建幾個靜態方法,當調用這幾個方法的時候,會返回這幾個方法的所要返回的對象。但是創建工廠模式任然需要主動去調用,如果要實現自動去調用需要在配置文件當中配置。

package com.rl.spring.dao;

public interface UserDao {
    
    public void save();
}
package com.rl.spring.dao.impl;

import com.rl.spring.dao.UserDao;

public class UserDaoImpl implements UserDao {

    @Override
    public void save() {
        System.out.println("user被保存了");
    }
}

Spring實際上也是提供了這樣的一個工廠,不過去區別是spring提供的工廠比這個工廠要強大的多。

package com.rl.spring.factory;

import com.rl.spring.dao.UserDao;
import com.rl.spring.dao.impl.UserDaoImpl;

public class FactoryBean {
    
    public static UserDao getDao(String name){
        if(name == "userDao"){
            return new UserDaoImpl();
        }
        return null;
    }
    public static UserDao getDao(String name){
        if(name == "userService"){
            return new UserServiceImpl ();
        }
        return null;
    }
}
package com.rl.spring.service;

public interface UserService {
    public void save();
}
package com.rl.spring.service.impl;

import com.rl.spring.dao.UserDao;
import com.rl.spring.dao.impl.UserDaoImpl;
import com.rl.spring.factory.FactoryBean;
import com.rl.spring.service.UserService;

public class UserServiceImpl implements UserService {

    /**
     * UserDaoImpl是我們自己創建的,
     * 我們自己創建DaoImpl();帶來了很大的耦合性,項目不好維護,測試成本也高
     * 
     */
    private UserDao userDao = FactoryBean.getDao("userDao");
    
    @Override
    public void save() {
        userDao.save();
    }
}

二.AOP

AOP思想的實現一般都是基于代理模式 ,在JAVA中一般采用JDK動態代理模式,但是我們都知道,JDK動態代理模式只能代理接口而不能代理類。因此,Spring AOP 會這樣子來進行切換,因為Spring AOP 同時支持 CGLIB、ASPECTJ、JDK動態代理。通過預編譯的方式在運行期通過動態代理實現的一種技術。
如果目標對象的的實現類實現了接口,Spring AOP將會采用JDK動態代理來生成AOP代理類。
如果目標對象的實現類沒有實現接口,Spring AOP就會采用CGLIB動態代理來生成AOP代理類。

AOP可以分離系統的業務邏輯和系統服務(日志,安全等)

※靜態代理、JDK動態代理、CGLIB動態代理講解

我們知道AOP思想的實現一般都是基于 代理模式 ,所以在看下面的文章之前建議先了解一下靜態代理以及JDK動態代理、CGLIB動態代理的實現方式。
Spring AOP 入門

帶你入門的一篇文章。這篇文章主要介紹了AOP中的基本概念:5種類型的通知(Before,After,After-returning,After-throwing,Around);Spring中對AOP的支持:AOP思想的實現一般都是基于代理模式,在JAVA中一般采用JDK動態代理模式,Spring AOP 同時支持 CGLIB、ASPECTJ、JDK動態代理,

※Spring AOP 基于AspectJ注解如何實現AOP

AspectJ是一個AOP框架,它能夠對java代碼進行AOP編譯(一般在編譯期進行),讓java代碼具有AspectJ的AOP功能(當然需要特殊的編譯器),可以這樣說AspectJ是目前實現AOP框架中最成熟,功能最豐富的語言,更幸運的是,AspectJ與java程序完全兼容,幾乎是無縫關聯,因此對于有java編程基礎的工程師,上手和使用都非常容易

Spring注意到AspectJ在AOP的實現方式上依賴于特殊編譯器(ajc編譯器),因此Spring很機智回避了這點,轉向采用動態代理技術的實現原理來構建Spring AOP的內部機制(動態織入),這是與AspectJ(靜態織入)最根本的區別

※探秘Spring AOP(慕課網視頻,很不錯)

慕課網視頻,講解的很不錯,詳細且深入

spring源碼剖析(六)AOP實現原理剖析

通過源碼分析Spring AOP的原理

IOC:

Spring IOC的初始化過程:

[Spring框架]Spring IOC的原理及詳解。

Spring IOC核心源碼學習

比較簡短,推薦閱讀。

Spring IOC 容器源碼分析

強烈推薦,內容詳盡,而且便于閱讀。

Spring事務管理

可能是最漂亮的Spring事務管理詳解

Spring編程式和聲明式事務實例講解

其他

Spring單例與線程安全:

Spring框架中的單例模式(源碼解讀)

單例模式是一種常用的軟件設計模式。通過單例模式可以保證系統中一個類只有一個實例。spring依賴注入時,使用了 多重判斷加鎖 的單例模式。

Spring源碼閱讀

閱讀源碼不僅可以加深我們對Spring設計思想的理解,提高自己的編碼水品,還可以讓自己字面試中如魚得水。下面的是Github上的一個開源的Spring源碼閱讀,大家有時間可以看一下,當然你如果有時間也可以自己慢慢研究源碼。

Spring源碼閱讀

2.Spring當中bean的生命周期及作用域?

在spring當中將所有納入spring管理的對象皆稱為bean,簡單地講,bean 就是由 IOC 容器初始化、裝配及管理的對象,除此之外,bean 就與應用程序中的其他對象沒有什么區別了。而 bean 的定義以及 bean 相互間的依賴關系將通過配置元數據來描述。
Spring中的bean默認都是單例的,這些單例Bean在多線程程序下如何保證線程安全呢? 例如對于Web應用來說,Web容器對于每個用戶請求都創建一個單獨的Sevlet線程來處理請求,引入Spring框架之后,每個Action都是單例的,那么對于Spring托管的單例Service Bean,如何保證其安全呢? Spring的單例是基于BeanFactory也就是Spring容器的,單例Bean在此容器內只有一個,Java的單例是基于 JVM,每個 JVM 內只有一個實例。

一.bean的作用域

在bean當中可以靈活的設置對象的作用域,Spring Framework支持五種作用域,分別闡述如下表。當然你也可以在class里面設置bean的作用域

圖片.png

五種作用域中,request、session 和 global session 三種作用域僅在基于web的應用中使用(不必關心你所采用的是什么web應用框架),只能用在基于 web 的 Spring ApplicationContext 環境。

二. singleton——唯一 bean 實例

當一個 bean 的作用域為 singleton,那么Spring IoC容器中只會存在一個共享的 bean 實例,并且所有對 bean 的請求,只要 id 與該 bean 定義相匹配,則只會返回bean的同一實例。 singleton 是單例類型(對應于單例模式),就是在創建起容器時就同時自動創建了一個bean的對象,不管你是否使用,但我們可以指定Bean節點的 lazy-init=”true” 來延遲初始化bean,這時候,只有在第一次獲取bean時才會初始化bean,即第一次請求該bean時才初始化。 每次獲取到的對象都是同一個對象。注意,singleton 作用域是Spring中的缺省作用域。要在XML中將 bean 定義成 singleton ,可以這樣配置:

<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">

也可以通過 @Scope 注解(它可以顯示指定bean的作用范圍。)的方式

@Service
@Scope("singleton")
public class ServiceImpl{

}

2. prototype——每次請求都會創建一個新的 bean 實例

當一個bean的作用域為 prototype,表示一個 bean 定義對應多個對象實例。 prototype 作用域的 bean 會導致在每次對該 bean 請求(將其注入到另一個 bean 中,或者以程序的方式調用容器的 getBean() 方法)時都會創建一個新的 bean 實例。prototype 是原型類型,它在我們創建容器的時候并沒有實例化,而是當我們獲取bean的時候才會去創建一個對象,而且我們每次獲取到的對象都不是同一個對象。根據經驗,對有狀態的 bean 應該使用 prototype 作用域,而對無狀態的 bean 則應該使用 singleton 作用域。 在 XML 中將 bean 定義成 prototype ,可以這樣配置:

<bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>  
 或者
<bean id="account" class="com.foo.DefaultAccount" singleton="false"/> 

通過 @Scope 注解的方式實現。

@Service
@Scope("prototype")
public class ServiceImpl{

}

3. request——每一次HTTP請求都會產生一個新的bean,該bean僅在當前HTTP request內有效

request只適用于Web程序,每一次 HTTP 請求都會產生一個新的bean,同時該bean僅在當前HTTP request內有效,當請求結束后,該對象的生命周期即告結束。 在 XML 中將 bean 定義成 request ,可以這樣配置:

<bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>

#4. session——每一次HTTP請求都會產生一個新的 bean,該bean僅在當前 HTTP session 內有效

session只適用于Web程序,session 作用域表示該針對每一次 HTTP 請求都會產生一個新的 bean,同時該 bean 僅在當前 HTTP session 內有效.與request作用域一樣,可以根據需要放心的更改所創建實例的內部狀態,而別的 HTTP session 中根據 userPreferences 創建的實例,將不會看到這些特定于某個 HTTP session 的狀態變化。當HTTP session最終被廢棄的時候,在該HTTP session作用域內的bean也會被廢棄掉。

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

5. globalSession

global session 作用域類似于標準的 HTTP session 作用域,不過僅僅在基于 portlet 的 web 應用中才有意義。Portlet 規范定義了全局 Session 的概念,它被所有構成某個 portlet web 應用的各種不同的 portle t所共享。在global session 作用域中定義的 bean 被限定于全局portlet Session的生命周期范圍內。

<bean id="user" class="com.foo.Preferences "scope="globalSession"/>

3.bean的生命周期

Spring Bean是Spring應用中最最重要的部分了。所以來看看Spring容器在初始化一個bean的時候會做那些事情,順序是怎樣的,在容器關閉的時候,又會做哪些事情。

有時我們需要在Bean屬性值set好之后和Bean銷毀之前做一些事情,比如檢查Bean中某個屬性是否被正常的設置好值了。Spring框架提供了多種方法讓我們可以在Spring Bean的生命周期中執行initialization和pre-destroy方法。

1.實現InitializingBean和DisposableBean接口

實現了這2個接口之后,無需再bean當中定義init-method和destroy-method方法,bean容器會自動去調用afterProperties()與destory()方法,如果沒有實現這2個接口,要調用init-method和destroy-method方法,必須要在bean當中定義。


圖片.png

圖片.png

圖片.png

圖片.png

需要注意的是自定義的init-method和post-method方法可以拋異常但是不能有參數。

這種方式比較推薦,因為可以自己創建方法,無需將Bean的實現直接依賴于spring的框架。

3.使用@PostConstruct和@PreDestroy注解

除了xml配置的方式,Spring 也支持用 @PostConstruct和 @PreDestroy注解來指定 init 和 destroy 方法。這兩個注解均在javax.annotation 包中。為了注解可以生效,需要在配置文件中定義

org.springframework.context.annotation.CommonAnnotationBeanPostProcessor或context:annotation-config

例子如下:

public class GiraffeService {
    @PostConstruct
    public void initPostConstruct(){
        System.out.println("執行PostConstruct注解標注的方法");
    }
    @PreDestroy
    public void preDestroy(){
        System.out.println("執行preDestroy注解標注的方法");
    }
}

配置文件:

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />

4.實現*Aware接口 在Bean中使用Spring框架的一些對象

有些時候我們需要在 Bean 的初始化中使用 Spring 框架自身的一些對象來執行一些操作,比如獲取 ServletContext 的一些參數,獲取 ApplicaitionContext 中的 BeanDefinition 的名字,獲取 Bean 在容器中的名字等等。為了讓 Bean 可以獲取到框架自身的一些對象,Spring 提供了一組名為Aware的接口。*

這些接口均繼承于org.springframework.beans.factory.Aware標記接口,并提供一個將由 Bean 實現的set*方法,Spring通過基于setter的依賴注入方式使相應的對象可以被Bean使用。 網上說,這些接口是利用觀察者模式實現的,類似于servlet listeners,目前還不明白,不過這也不在本文的討論范圍內。 介紹一些重要的Aware接口:

  • ApplicationContextAware: 獲得ApplicationContext對象,可以用來獲取所有Bean definition的名字。
  • BeanFactoryAware:獲得BeanFactory對象,可以用來檢測Bean的作用域。
  • BeanNameAware:獲得Bean在配置文件中定義的名字。
  • ResourceLoaderAware:獲得ResourceLoader對象,可以獲得classpath中某個文件。
  • ServletContextAware:在一個MVC應用中可以獲取ServletContext對象,可以讀取context中的參數。
  • ServletConfigAware: 在一個MVC應用中可以獲取ServletConfig對象,可以讀取config中的參數。
public class GiraffeService implements   ApplicationContextAware,
        ApplicationEventPublisherAware, BeanClassLoaderAware, BeanFactoryAware,
        BeanNameAware, EnvironmentAware, ImportAware, ResourceLoaderAware{
         @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("執行setBeanClassLoader,ClassLoader Name = " + classLoader.getClass().getName());
    }
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("執行setBeanFactory,setBeanFactory:: giraffe bean singleton=" +  beanFactory.isSingleton("giraffeService"));
    }
    @Override
    public void setBeanName(String s) {
        System.out.println("執行setBeanName:: Bean Name defined in context="
                + s);
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("執行setApplicationContext:: Bean Definition Names="
                + Arrays.toString(applicationContext.getBeanDefinitionNames()));
    }
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        System.out.println("執行setApplicationEventPublisher");
    }
    @Override
    public void setEnvironment(Environment environment) {
        System.out.println("執行setEnvironment");
    }
    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        Resource resource = resourceLoader.getResource("classpath:spring-beans.xml");
        System.out.println("執行setResourceLoader:: Resource File Name="
                + resource.getFilename());
    }
    @Override
    public void setImportMetadata(AnnotationMetadata annotationMetadata) {
        System.out.println("執行setImportMetadata");
    }
}

BeanPostProcessor

上面的*Aware接口是針對某個實現這些接口的Bean定制初始化的過程, Spring同樣可以針對容器中的所有Bean,或者某些Bean定制初始化過程,只需提供一個實現BeanPostProcessor接口的類即可。 該接口中包含兩個方法,postProcessBeforeInitialization和postProcessAfterInitialization。 postProcessBeforeInitialization方法會在容器中的Bean初始化之前執行, postProcessAfterInitialization方法在容器中的Bean初始化之后執行。

例子如下:

public class CustomerBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("執行BeanPostProcessor的postProcessBeforeInitialization方法,beanName=" + beanName);
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("執行BeanPostProcessor的postProcessAfterInitialization方法,beanName=" + beanName);
        return bean;
    }
}

要將BeanPostProcessor的Bean像其他Bean一樣定義在配置文件中

<bean class="com.giraffe.spring.service.CustomerBeanPostProcessor"/>

總結

所以。。。結合第一節控制臺輸出的內容,Spring Bean的生命周期是這樣紙的:

  • Bean容器找到配置文件中 Spring Bean 的定義。
  • Bean容器利用Java Reflection API創建一個Bean的實例。
  • 如果涉及到一些屬性值 利用set方法設置一些屬性值。
  • 如果Bean實現了BeanNameAware接口,調用setBeanName()方法,傳入Bean的名字。
  • 如果Bean實現了BeanClassLoaderAware接口,調用setBeanClassLoader()方法,傳入ClassLoader對象的實例。
  • 如果Bean實現了BeanFactoryAware接口,調用setBeanClassLoader()方法,傳入ClassLoader對象的實例。
  • 與上面的類似,如果實現了其他*Aware接口,就調用相應的方法。
  • 如果有和加載這個Bean的Spring容器相關的BeanPostProcessor對象,執行postProcessBeforeInitialization()方法
  • 如果Bean實現了InitializingBean接口,執行afterPropertiesSet()方法。
  • 如果Bean在配置文件中的定義包含init-method屬性,執行指定的方法。
  • 如果有和加載這個Bean的Spring容器相關的BeanPostProcessor對象,執行postProcessAfterInitialization()方法
  • 當要銷毀Bean的時候,如果Bean實現了DisposableBean接口,執行destroy()方法。
  • 當要銷毀Bean的時候,如果Bean在配置文件中的定義包含destroy-method屬性,執行指定的方法。

用圖表示一下(圖來源:http://www.lxweimin.com/p/d00539babca5):%EF%BC%9A)

與之比較類似的中文版本:

其實很多時候我們并不會真的去實現上面說描述的那些接口,那么下面我們就除去那些接口,針對bean的單例和非單例來描述下bean的生命周期:
單例管理的對象

當scope=”singleton”,即默認情況下,會在啟動容器時(即實例化容器時)時實例化。但我們可以指定Bean節點的lazy-init=”true”來延遲初始化bean,這時候,只有在第一次獲取bean時才會初始化bean,即第一次請求該bean時才初始化。如下配置:

<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" lazy-init="true"/>

如果想對所有的默認單例bean都應用延遲初始化,可以在根節點beans設置default-lazy-init屬性為true,如下所示:

<beans default-lazy-init="true" …>

默認情況下,Spring 在讀取 xml 文件的時候,就會創建對象。在創建對象的時候先調用構造器,然后調用 init-method 屬性值中所指定的方法。對象在被銷毀的時候,會調用 destroy-method 屬性值中所指定的方法(例如調用Container.destroy()方法的時候)。寫一個測試類,代碼如下:

public class LifeBean {
    private String name;  

    public LifeBean(){  
        System.out.println("LifeBean()構造函數");  
    }  
    public String getName() {  
        return name;  
    }  

    public void setName(String name) {  
        System.out.println("setName()");  
        this.name = name;  
    }  

    public void init(){  
        System.out.println("this is init of lifeBean");  
    }  

    public void destory(){  
        System.out.println("this is destory of lifeBean " + this);  
    }  
}

life.xml配置如下:

<bean id="life_singleton" class="com.bean.LifeBean" scope="singleton" 
            init-method="init" destroy-method="destory" lazy-init="true"/>

測試代碼:

public class LifeTest {
    @Test 
    public void test() {
        AbstractApplicationContext container = 
        new ClassPathXmlApplicationContext("life.xml");
        LifeBean life1 = (LifeBean)container.getBean("life");
        System.out.println(life1);
        container.close();
    }
}

運行結果:

LifeBean()構造函數
this is init of lifeBean
com.bean.LifeBean@573f2bb1
……
this is destory of lifeBean com.bean.LifeBean@573f2bb1

非單例管理的對象

當scope=”prototype”時,容器也會延遲初始化 bean,Spring 讀取xml 文件的時候,并不會立刻創建對象,而是在第一次請求該 bean 時才初始化(如調用getBean方法時)。在第一次請求每一個 prototype 的bean 時,Spring容器都會調用其構造器創建這個對象,然后調用init-method屬性值中所指定的方法。對象銷毀的時候,Spring 容器不會幫我們調用任何方法,因為是非單例,這個類型的對象有很多個,Spring容器一旦把這個對象交給你之后,就不再管理這個對象了。destory方法在關閉容器或者異常退出的時候才會執行。
為了測試prototype bean的生命周期life.xml配置如下:

<bean id="life_prototype" class="com.bean.LifeBean" scope="prototype" init-method="init" destroy-method="destory"/>

測試程序:

public class LifeTest {
    @Test 
    public void test() {、
        AbstractApplicationContext container = new ClassPathXmlApplicationContext("life.xml");
        LifeBean life1 = (LifeBean)container.getBean("life_singleton");
        System.out.println(life1);

        LifeBean life3 = (LifeBean)container.getBean("life_prototype");
        System.out.println(life3);
        container.close();
    }
}

運行結果:

LifeBean()構造函數
this is init of lifeBean
com.bean.LifeBean@573f2bb1
LifeBean()構造函數
this is init of lifeBean
com.bean.LifeBean@5ae9a829
……
this is destory of lifeBean com.bean.LifeBean@573f2bb1

可以發現,對于作用域為 prototype 的 bean ,其destroy方法并沒有被調用。如果 bean 的 scope 設為prototype時,當容器關閉時,destroy 方法不會被調用。對于 prototype 作用域的 bean,有一點非常重要,那就是 Spring不能對一個 prototype bean 的整個生命周期負責:容器在初始化、配置、裝飾或者是裝配完一個prototype實例后,將它交給客戶端,隨后就對該prototype實例不聞不問了。 不管何種作用域,容器都會調用所有對象的初始化生命周期回調方法。但對prototype而言,任何配置好的析構生命周期回調方法都將不會被調用。清除prototype作用域的對象并釋放任何prototype bean所持有的昂貴資源,都是客戶端代碼的職責(讓Spring容器釋放被prototype作用域bean占用資源的一種可行方式是,通過使用bean的后置處理器,該處理器持有要被清除的bean的引用)。談及prototype作用域的bean時,在某些方面你可以將Spring容器的角色看作是Java new操作的替代者,任何遲于該時間點的生命周期事宜都得交由客戶端來處理。

總結:Spring容器可以管理singleton 作用域下 bean 的生命周期,在此域下,spring可以精準的知道bean是什么時候創建的,什么時候完成初始化的,什么時候銷毀的。但是對于prototype 作用域下的bean,Spring只負責創建,當容器創建bean的實例之后,該對象就會交給客戶端代碼管理,Spring容器不在跟蹤任何生命周期,并且不會管理那些被配置成prototype作用域的bean的生命周期。

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

推薦閱讀更多精彩內容