01、IOC容器設(shè)計理念與核心注解的使用

一、Spring框架功能整體介紹

1、SpringCoreContainer

模塊作用: Core 和 Beans 模塊是框架的基礎(chǔ)部分,提供 IoC (轉(zhuǎn)控制)和依賴注入特性。 這里的基礎(chǔ) 概念是 BeanFactory,它提供對 Factory 模式的經(jīng)典實現(xiàn)來消除對程序性單例模式的需要,并真 正地允許你從程序邏輯中分離出依賴關(guān)系和配置。

1.1)Core模塊

主要包含 Spring 框架基本的核心工具類, Spring 的其他組件都要用到這個包 里的類, Core模塊是其他組件的基 本核心。

1.2)Beans (BeanFacotry的作用)

它包含訪問配直文件、創(chuàng)建和管理 bean 以及進行 Inversion of Control I Dependency Injection (IoC/DI)操作相關(guān)的所有類。

1.3)Context(處理BeanFactory,一下還是ApplicationContext的作用)

模構(gòu)建于 Core 和 Beans 模塊基礎(chǔ)之上,提供了一種類似JNDI 注冊器的框 架式的對象訪問方法。 Context 模塊繼承了 Beans 的特性,為 Spring 核心提供了大量 擴展,添加了對 國際化(例如資源綁定)、事件傳播、資源加載和對 Context 的透明創(chuàng) 建的支持。 Context 模塊同時 也支持 J2EE 的一些特性, ApplicationContext 接口是 Context 模塊的關(guān)鍵
本質(zhì)區(qū)別:使用BeanFacotry的bean是延時加載的,ApplicationContext是非延時加載的

1.4)Expression Language

模塊提供了強大的表達式語言,用于在運行時查詢和操縱對象。 它是 JSP 2.1 規(guī)范中定義的 unifedexpression language 的擴展。 該語言支持設(shè)直/獲取屬 性的值,屬性的分配,方法的調(diào)用,訪問數(shù)組上下文( accessiong the context of arrays )、 容器和索引器、邏輯和算術(shù)運算符、命名變量以及從Spring的 IoC 容器中根據(jù)名稱檢 索對象。 它也支持 list 投影、選擇和一般的 list 聚合.

2、Spring Data Access/Integration

2.1) JDBC

模塊提供了一個 JDBC 抽象層,它可以消除冗長的 JDBC 編碼和解析數(shù)據(jù)庫廠 商特有的錯誤代碼。這個模塊包含了 Spring 對 JDBC 數(shù)據(jù)訪問進行封裝的所有類。

2.2) ORM 模塊為流行的對象-關(guān)系映射 API

如 JPA、 JDO、 Hibernate、 iBatis 等,提供了 一個交互層。 利用 ORM 封裝包,可以混合使用所有 Spring 提供的特性進行 O/R 映射, 如前邊提到的簡單聲 明性事務(wù)管理。

2.3) OXM 模塊提供了一個對 ObjecνXML 映射實現(xiàn)的抽象層

Object/XML 映射實現(xiàn)包括 JAXB、 Castor、 XMLBeans、 JiBX 和 XStrearn

2.4) JMS ( Java Messaging Service)

模塊主要包含了一些制造和消 費消息的特性。

2.5) Transaction

支持編程和聲明性的事務(wù)管理,這些事務(wù)類必須實現(xiàn)特定的接口,并 且對所有的 POJO 都適用

3、Spring Web

Web 模塊:提供了基礎(chǔ)的面向 Web 的集成特性c 例如,多文件上傳、使用 servlet listeners 初始化
IoC 容器以及一個面向 Web 的應(yīng)用上下文。 它還包含 Spring 遠程支持中 Web 的相關(guān)部分。

4、Spring Aop

  1. Aspects 模塊提供了對 AspectJ 的集成支持。
  2. Instrumentation 模塊提供了 class instrumentation 支持和 classloader 實現(xiàn),使得可以在特
    定的應(yīng)用服務(wù)器上使用

5、Test

Test 模塊支持使用 JUnit 和 TestNG 對 Spring 組件進行測試

6、Spring 容器繼承圖:

7、依賴注入控制反轉(zhuǎn)

7.1) 什么是控制反轉(zhuǎn)?我覺得有必要先了解軟件設(shè)計的一個重要思想:依賴倒置原則(Dependency Inversion Principle )

①:什么是依賴倒置原則? 假設(shè)我們設(shè)計一輛汽車:先設(shè)計輪子,然后根據(jù)輪子大小設(shè)計底盤,接著根據(jù)底盤設(shè)計車身,最后根據(jù)車身設(shè)計好整個汽車。這里就出現(xiàn)了一個“依賴”關(guān)系:汽車依賴車身,車身依賴底盤,底盤依賴輪子。

上圖看上去沒有什么毛病?但是 萬一輪胎尺寸改了,那么地盤需要改,地盤改了,車身也改了,讓后整個汽車構(gòu)造都改了.
然后汽車公司倒閉了!!!
....................................................................................................................................................
董事長依賴總經(jīng)理爭取,總經(jīng)理依賴部門經(jīng)理掙錢,部門經(jīng)理依賴員工爭取,那么員工離職了怎么
辦???
....................................................................................................................................................
反過來:假如汽車公司決定修改輪胎的 我們就只需要改動輪子的設(shè)計,而不需要動底盤,車身,汽車的設(shè)計了。

IOC容器的最最最最核心思想........................
ioc的思想最核心的地方在于,資源不由使用資源的雙方管理,而由不使用資源的第三方管理,這可以帶來很多好處。第一,資源集中管理,實現(xiàn)資源的可配置和易管理。第二,降低了使用資源雙方的依賴程度,也就是我們說的耦合度。

二、Spring IOC 容器底層注解使用

2.1) xml配置文件的形式 VS 配置類的形式

2.1.1) 基于xml的形式定義Bean的信息
<?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的信息
    <bean id="car" class="com.tuling.compent.Car"></bean>
</beans>

去容器中讀取bean

public static void main( String[] args ){
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
    System.out.println(ctx.getBean("person"));
}
2.1.2) 基于讀取配置類的形式定義Bean信息
@Configuration
public class MainConfig {
    @Bean
    public Person person(){
        return new Person();
    }
}

注意: 通過@Bean的形式是使用的話, bean的默認(rèn)名稱是方法名,若@Bean(value="bean的名稱")那么bean的名稱是指定的

去容器中讀取Bean的信息(傳入配置類)

public static void main( String[] args ){
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
    System.out.println(ctx.getBean("person"));
}

2.2) 在配置類上寫@CompentScan注解來進行包掃描

@Configuration
@ComponentScan(basePackages = {"com.tuling.testcompentscan"})
public class MainConfig {
}
2.2.1)排除用法 excludeFilters(排除@Controller注解的,和TulingService的)
@Configuration
@ComponentScan(basePackages = {"com.tuling.testcompentscan"},excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}),
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {TulingService.class})
})
public class MainConfig {
}
2.2.2)包含用法 includeFilters ,注意,若使用包含的用法, 需要把useDefaultFilters屬性設(shè)置為false(true表示掃描全部的)
@Configuration
@ComponentScan(basePackages = {"com.tuling.testcompentscan"},includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class, Service.class})
},useDefaultFilters = false)
public class MainConfig {
}
2.2.3)@ComponentScan.Filter type的類型

a)注解形式的FilterType.ANNOTATION @Controller @Service @Repository @Compent
b)指定類型的 FilterType.ASSIGNABLE_TYPE @ComponentScan.Filter(type =
FilterType.ASSIGNABLE_TYPE,value = {TulingService.class})
c)aspectj類型的 FilterType.ASPECTJ(不常用)
d)正則表達式的 FilterType.REGEX(不常用)
e)自定義的 FilterType.CUSTOM

public enum FilterType {
    //注解形式  比如@Controller @Service @Repository  @Compent
    ANNOTATION,
    //指定的類型
    ASSIGNABLE_TYPE,
    //aspectJ形式的
    ASPECTJ,
    //正則表達式的
    REGEX,
    //自定義的
    CUSTOM
}

FilterType.CUSTOM 自定義類型如何使用

public class TulingFilterType implements TypeFilter {
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        //獲取當(dāng)前類的注解源信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //獲取當(dāng)前類的class的源信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //獲取當(dāng)前類的資源信息
        Resource resource =  metadataReader.getResource();
        if(classMetadata.getClassName().contains("dao")) {
            return true;
        }
        return false;
    }
}
@ComponentScan(basePackages = {"com.tuling.testcompentscan"},includeFilters = {
        @ComponentScan.Filter(type = FilterType.CUSTOM,value = TulingFilterType.class)
},useDefaultFilters = false)
public class MainConfig {
}

2.3配置Bean的作用域?qū)ο?/h4>

2.3.1)在不指定@Scope的情況下,所有的bean都是單實例的bean,而且是餓漢加載(容器啟動實例就創(chuàng)建好了)
@Bean
public Person person() {
    return new Person();
}
2.3.2)指定@Scope為 prototype 表示為多實例的,而且還是懶漢模式加載(IOC容器啟動的時候,并不會創(chuàng)建對象,而是在第一次使用的時候才會創(chuàng)建)
@Bean
@Scope(value = "prototype")
public Person person() {
    return new Person();
}
2.3.3)@Scope指定的作用域方法取值

a) singleton 單實例的(默認(rèn))
b) prototype 多實例的
c) request 同一次請求
d) session 同一個會話級別

2.4)Bean的懶加載@Lazy(主要針對單實例的bean 容器啟動的時候,不創(chuàng)建對象,在第一次使用的時候才會創(chuàng)建該對象)

@Bean
@Lazy
public Person person() {
    return new Person();
}

2.5)@Conditional進行條件判斷等

場景,有二個組件TulingAspect 和TulingLog ,我的TulingLog組件是依賴于TulingAspect的組件應(yīng)用:自己創(chuàng)建一個TulingCondition的類 實現(xiàn)Condition接口

public class TulingCondition implements Condition {
    /**
     *
     * @param context
     * @param metadata
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //判斷容器中是否有tulingAspect的組件
        if(context.getBeanFactory().containsBean("tulingAspect")) {
            return true;
        }
        return false;
    }
}

public class MainConfig {
    @Bean
    public TulingAspect tulingAspect() {
        return new TulingAspect();
    }
   
    //當(dāng)切 容器中有tulingAspect的組件,那么tulingLog才會被實例化.
    @Bean
    @Conditional(value = TulingCondition.class)
    public TulingLog tulingLog() {
        return new TulingLog();
    }
}

2.6)往IOC 容器中添加組件的方式

①:通過@CompentScan +@Controller @Service @Respository @compent
適用場景: 針對我們自己寫的組件可以通過該方式來進行加載到容器中。
②:通過@Bean的方式來導(dǎo)入組件(適用于導(dǎo)入第三方組件的類)
③:通過@Import來導(dǎo)入組件 (導(dǎo)入組件的id為全類名路徑)

@Configuration
@Import(value = {Person.class, Car.class})
public class MainConfig {
}

通過@Import 的ImportSeletor類實現(xiàn)組件的導(dǎo)入 (導(dǎo)入組件的id為全類名路徑)

public class TulingImportSelector implements ImportSelector {
    /可以獲取導(dǎo)入類的注解信息
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.tuling.testimport.compent.Dog"};
    }
}
@Configuration
@Import(value = {Person.class, Car.class, TulingImportSelector.class})
public class MainConfig {
}

通過@Import的 ImportBeanDefinitionRegister導(dǎo)入組件 (可以指定bean的名稱)

public class TulingBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //創(chuàng)建一個bean定義對象
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Cat.class);
        //把bean定義對象導(dǎo)入到容器中
        registry.registerBeanDefinition("cat",rootBeanDefinition);
    }
}
@Configuration
//@Import(value = {Person.class, Car.class})
//@Import(value = {Person.class, Car.class, TulingImportSelector.class})
@Import(value = {Person.class, Car.class, TulingImportSelector.class, TulingBeanDefinitionRegister.class})
public class MainConfig {
}

④:通過實現(xiàn)FacotryBean接口來實現(xiàn)注冊 組件
使用場景:類的初始化過程比較復(fù)雜的時候,使用該方式(原理:工廠方法模式)

public class CarFactoryBean implements FactoryBean<Car> {
   
    /返回bean的對象
    @Override
    public Car getObject() throws Exception {
        return new Car();
    }
   
    /返回bean的類型
    @Override
    public Class<?> getObjectType() {
        return Car.class;
    }
   
    /是否為單利
    @Override
    public boolean isSingleton() {
        return true;
    }
}

2.7)Bean的初始化方法和銷毀方法.

①:什么是bean的生命周期?
bean的創(chuàng)建----->初始化----->銷毀方法
由容器管理Bean的生命周期,我們可以通過自己指定bean的初始化方法和bean的銷毀方法

@Configuration
public class MainConfig {
   
    //指定了bean的生命周期的初始化方法和銷毀方法.
    @Bean(initMethod = "init",destroyMethod = "destroy")
    public Car car() {
        return new Car();
    }
}

針對單實例bean的話,容器啟動的時候,bean的對象就創(chuàng)建了,而且容器銷毀的時候,也會調(diào)用Bean的銷毀方法
針對多實例bean的話,容器啟動的時候,bean是不會被創(chuàng)建的而是在獲取bean的時候被創(chuàng)建,而且bean的銷毀不受IOC容器的管理.

②:通過 InitializingBean和DisposableBean 的二個接口實現(xiàn)bean的初始化以及銷毀方法

@Component
public class Person implements InitializingBean,DisposableBean {
    public Person() {
        System.out.println("Person的構(gòu)造方法");
    }
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean的destroy()方法 ");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean的 afterPropertiesSet方法");
    }
}

③:通過JSR250規(guī)范 提供的注解@PostConstruct 和@ProDestory標(biāo)注的方法

@Component
public class Book {
    public Book() {
        System.out.println("book 的構(gòu)造方法");
    }
    @PostConstruct
    public void init() {
        System.out.println("book 的PostConstruct標(biāo)志的方法");
    }
    @PreDestroy
    public void destory() {
        System.out.println("book 的PreDestory標(biāo)注的方法");
    }
}

④:通過Spring的BeanPostProcessor的 bean的后置處理器會攔截所有bean創(chuàng)建過程
postProcessBeforeInitialization 在init方法之前調(diào)用
postProcessAfterInitialization 在init方法之后調(diào)用

@Component
public class TulingBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("TulingBeanPostProcessor...postProcessBeforeInitialization:"+beanName);
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("TulingBeanPostProcessor...postProcessAfterInitialization:"+beanName);
        return bean;
    }
}

BeanPostProcessor的執(zhí)行時機

populateBean(beanName, mbd, instanceWrapper)
initializeBean{
    applyBeanPostProcessorsBeforeInitialization()
    invokeInitMethods{
        isInitializingBean.afterPropertiesSet
        自定義的init方法
    }
    applyBeanPostProcessorsAfterInitialization()方法
}

2.8)通過@Value + @PropertySource來給組件賦值

public class Person {
  
    //通過普通的方式
    @Value("司馬")
    private String firstName;
   
    //spel方式來賦值
    @Value("#{28-8}")
    private Integer age;
    通過讀取外部配置文件的值
    @Value("${person.lastName}")
    private String lastName;
}   

@Configuration
@PropertySource(value = {"classpath:person.properties"}) //指定外部文件的位置
public class MainConfig {
    @Bean
    public Person person() {
        return new Person();
    }
}

2.9)自動裝配

@AutoWired的使用
自動注入:

//一個Dao
@Repository
public class TulingDao {
}
@Service
public class TulingService {
    @Autowired
    private TulingDao tulingDao;
}

結(jié)論:

a:自動裝配首先是按照類型進行裝配,若在IOC容器中發(fā)現(xiàn)了多個相同類型的組件,那么就按照 屬性名稱來進行裝配

@Autowired
private TulingDao tulingDao;

比如,我容器中有二個TulingDao類型的組件 一個叫tulingDao 一個叫tulingDao2,那么我們通過@AutoWired 來修飾的屬性名稱時tulingDao,那么拿就加載容器的tulingDao組件,若屬性名稱為tulignDao2 那么他就加載的時tulingDao2組件

b:假設(shè)我們需要指定特定的組件來進行裝配,我們可以通過使用@Qualifier("tulingDao")來指定裝配的組件或者在配置類上的@Bean加上@Primary注解

@Autowired
    @Qualifier("tulingDao")
    private TulingDao tulingDao2;

c:假設(shè)我們?nèi)萜髦屑礇]有tulingDao 和tulingDao2,那么在裝配的時候就會拋出異常
No qualifying bean of type 'com.tuling.testautowired.TulingDao' available
若我們想不拋異常 ,我們需要指定 required為false的時候可以了

 @Autowired(required = false)
    @Qualifier("tulingDao")
    private TulingDao tulingDao2;

d:@Resource(JSR250規(guī)范)
功能和@AutoWired的功能差不多一樣,但是不支持@Primary 和@Qualifier的支持

e:@InJect(JSR330規(guī)范)
需要導(dǎo)入jar包依賴
功能和支持@Primary功能 ,但是沒有Require=false的功能

<dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
</dependency>

f:使用autowired 可以標(biāo)注在方法上
標(biāo)注在set方法上

//@Autowired
    public void setTulingLog(TulingLog tulingLog) {
        this.tulingLog = tulingLog;
    }

標(biāo)注在構(gòu)造方法上:

@Autowired
    public TulingAspect(TulingLog tulingLog) {
        this.tulingLog = tulingLog;
    }

標(biāo)注在配置類的入?yún)⒅校梢圆粚懀?/p>

@Bean
    public TulingAspect tulingAspect(@Autowired TulingLog tulingLog) {
        TulingAspect tulingAspect = new TulingAspect(tulingLog);
        return tulingAspect;
    }

3.0) 我們自己的組件 需要使用spring ioc的底層組件的時候,比如 ApplicationContext等

我們可以通過實現(xiàn)XXXAware接口來實現(xiàn)

@Component
public class TulingCompent implements ApplicationContextAware,BeanNameAware {
    private ApplicationContext applicationContext;
    @Override
    public void setBeanName(String name) {
        System.out.println("current bean name is :【"+name+"】");
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

3.1) 通過@Profile注解 來根據(jù)環(huán)境來激活標(biāo)識不同的Bean

@Profile標(biāo)識在類上,那么只有當(dāng)前環(huán)境匹配,整個配置類才會生效
@Profile標(biāo)識在Bean上 ,那么只有當(dāng)前環(huán)境的Bean才會被激活
沒有標(biāo)志為@Profile的bean 不管在什么環(huán)境都可以被激活

@Configuration
@PropertySource(value = {"classpath:ds.properties"})
public class MainConfig implements EmbeddedValueResolverAware {
    @Value("${ds.username}")
    private String userName;
    @Value("${ds.password}")
    private String password;
    private String jdbcUrl;
    private String classDriver;
    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.jdbcUrl = resolver.resolveStringValue("${ds.jdbcUrl}");
        this.classDriver = resolver.resolveStringValue("${ds.classDriver}");
    }
   
    //標(biāo)識為測試環(huán)境才會被裝配
    @Bean
    @Profile(value = "test")
    public DataSource testDs() {
        return buliderDataSource(new DruidDataSource());
    }
   
    //標(biāo)識開發(fā)環(huán)境才會被激活
    @Bean
    @Profile(value = "dev")
    public DataSource devDs() {
        return buliderDataSource(new DruidDataSource());
    }
   
    //標(biāo)識生產(chǎn)環(huán)境才會被激活
    @Bean
    @Profile(value = "prod")
    public DataSource prodDs() {
        return buliderDataSource(new DruidDataSource());
    }
    private DataSource buliderDataSource(DruidDataSource dataSource) {
        dataSource.setUsername(userName);
        dataSource.setPassword(password);
        dataSource.setDriverClassName(classDriver);
        dataSource.setUrl(jdbcUrl);
        return dataSource;
    }
}

激活切換環(huán)境的方法
方法一:通過運行時jvm參數(shù)來切換 -Dspring.profiles.active=test|dev|prod
方法二:通過代碼的方式來激活

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