Springboot starter詳解

springboot starter封裝

什么是springboot starter機(jī)制箕慧?

能夠拋棄以前繁雜的配置偏螺,將其統(tǒng)一集成進(jìn)starter,應(yīng)用者只需要在maven中引入starter依賴,SpringBoot就能自動(dòng)掃描到要加載的信息并啟動(dòng)相應(yīng)的默認(rèn)配置状知。

starter讓我們擺脫了各種依賴庫(kù)的處理,需要配置各種信息的困擾孽查。SpringBoot會(huì)自動(dòng)通過(guò)classpath路徑下的類發(fā)現(xiàn)需要的Bean饥悴,并注冊(cè)進(jìn)IOC容器。SpringBoot提供了針對(duì)日常企業(yè)應(yīng)用研發(fā)各種場(chǎng)景的spring-boot-starter依賴模塊盲再。
所有這些依賴模塊都遵循著約定成俗的默認(rèn)配置西设,并允許我們調(diào)整這些配置,即遵循“約定大于配置”的理念答朋。

為什么需要自定義starter?

在我們的日常開發(fā)工作中梦碗,經(jīng)常會(huì)有一些獨(dú)立于業(yè)務(wù)之外的配置模塊禽绪,我們經(jīng)常將其放到一個(gè)特定的包下蓖救,然后如果另一個(gè)工程需要復(fù)用這塊功能的時(shí)候,需要將代碼硬拷貝到另一個(gè)工程印屁,重新集成一遍循捺,麻煩至極。 如果我們將這些可獨(dú)立于業(yè)務(wù)代碼之外的功配置模塊封裝成一個(gè)個(gè)starter雄人,復(fù)用的時(shí)候只需要將其在pom中引用依賴即可从橘,SpringBoot為我們完成自動(dòng)裝配,簡(jiǎn)直不要太爽。

什么時(shí)候需要自定義starter?

在我們的日常開發(fā)工作中署辉,可能會(huì)需要開發(fā)一個(gè)通用模塊静浴,以供其它工程復(fù)用。SpringBoot就為我們提供這樣的功能機(jī)制挟阻,我們可以把我們的通用模塊封裝成一個(gè)個(gè)starter,這樣其它工程復(fù)用的時(shí)候只需要在pom中引用依賴即可,由SpringBoot為我們完成自動(dòng)裝配驻民。

舉一些常見場(chǎng)景:

通用模塊-短信發(fā)送模塊
基于AOP技術(shù)實(shí)現(xiàn)日志切面
分布式雪花ID,Long-->string履怯,解決精度問(wèn)題 jackson2/fastjson
微服務(wù)項(xiàng)目的數(shù)據(jù)庫(kù)連接池配置
微服務(wù)項(xiàng)目的每個(gè)模塊都要訪問(wèn)redis數(shù)據(jù)庫(kù)回还,每個(gè)模塊都要配置redisTemplate

自動(dòng)加載核心注解說(shuō)明

image-20220803154634046.png

自定義starter的開發(fā)流程

這里以封裝 liteflow-spring-boot-starter 為例

(1)創(chuàng)建Starter項(xiàng)目

命名規(guī)范

SpringBoot官方命名方式
格式:spring-boot-starter-{模塊名}
舉例:spring-boot-starter-web

自定義命名方式
格式:{模塊名}-spring-boot-starter
舉例:mystarter-spring-boot-starter

引入必要的依賴

該依賴作用是在使用IDEA編寫配置文件有代碼提示, 作用在編譯階段

<!--表示兩個(gè)項(xiàng)目之間依賴不傳遞;不設(shè)置optional或者optional是false叹洲,表示傳遞依賴-->
<!--例如:project1依賴a.jar(optional=true),project2依賴project1,則project2不依賴a.jar-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional> <!-- 避免傳遞依賴 -->
</dependency>       

完整pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.unionman</groupId>
    <artifactId>liteflow-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>liteflow-spring-boot-starter</name>
    <description>liteflow-spring-boot-starter</description>
    <properties>
        <java.version>1.8</java.version>
        <swagger.fox.version>3.0.0</swagger.fox.version>
        <knife4j.version>2.0.8</knife4j.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!--非必需,該依賴作用是在使用IDEA編寫配置文件有代碼提示-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
<!--        <dependency>-->
<!--            <groupId>org.springframework.boot</groupId>-->
<!--            <artifactId>spring-boot-starter-test</artifactId>-->
<!--            <scope>test</scope>-->
<!--        </dependency>-->

        <dependency>
            <groupId>com.yomahub</groupId>
            <artifactId>liteflow-spring-boot-starter</artifactId>
            <version>2.8.3</version>
        </dependency>
        <dependency>
            <groupId>com.yomahub</groupId>
            <artifactId>liteflow-script-groovy</artifactId>
            <version>2.8.0</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
<!--        <dependency>-->
<!--            <groupId>com.baomidou</groupId>-->
<!--            <artifactId>mybatis-plus-boot-starter-test</artifactId>-->
<!--            <version>3.5.1</version>-->
<!--        </dependency>-->


        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
            <version>${swagger.fox.version}</version>
        </dependency>

        <!--
            // swagger2.0版本后柠硕,swagger ui訪問(wèn)地址 ip:port/swagger-ui.html
        // swagger3.0版本后,swagger ui訪問(wèn)地址 ip:port/swagger-ui/index.html (當(dāng)前使用)
        // 兼容swagger3.0, 增強(qiáng)型swagger knife4j ui界面: ip:port/doc.html (當(dāng)前使用)

        -->
        <!-- knife4j提供的微服務(wù)starter -->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>${knife4j.version}</version>
        </dependency>
        <!-- knife4j  ui -->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-micro-spring-boot-starter</artifactId>
            <version>${knife4j.version}</version>
        </dependency>
        <dependency>
            <groupId>jakarta.validation</groupId>
            <artifactId>jakarta.validation-api</artifactId>
            <version>2.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy</artifactId>
        </dependency>
    </dependencies>


    <!-- starter 我們沒有main入口运提,需要去除pom文件中maven打包插件spring-boot-maven-plugin,starter無(wú)需打成jar包 -->
    <build>
        <plugins>
        </plugins>
    </build>

</project>
(2)編寫相關(guān)屬性類
package com.unionman.liteflow.config;


import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;


@ConfigurationProperties(prefix = "app.service")
@Data
public class LiteServiceConfig {

    private String serviceUid;
}

@ConfigurationProperties注解基本用法

以定義一個(gè)配置信息類蝗柔,和配置文件進(jìn)行映射

  • 前綴定義了哪些外部屬性將綁定到類的字段上
  • 根據(jù) Spring Boot 寬松的綁定規(guī)則,類的屬性名稱必須與外部屬性的名稱匹配
  • 我們可以簡(jiǎn)單地用一個(gè)值初始化一個(gè)字段來(lái)定義一個(gè)默認(rèn)值
  • 類本身可以是包私有的
  • 類的字段必須有公共 setter 方法

注意:需要在配置類上加上 @EnableConfigurationProperties(LiteServiceConfig.class)

(3)編寫Starter項(xiàng)目的業(yè)務(wù)功能
(4)編寫自動(dòng)配置類 xxxAutoConfiguration

命名規(guī)范: XXXAutoConfiguration民泵,如 LiteFlowAutoConfiguration

package com.unionman.liteflow.config;


import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration // 表示該類是配置類
@ComponentScan("com.unionman.liteflow") // 由于這里沒有啟動(dòng)類癣丧,注入組件不能通過(guò)@SpringBootApplication,而需通過(guò)注解掃描
//@MapperScan("com.unionman.liteflow.mapper") // 不使用@Mapper注入mapper接口栈妆,則使用包掃描
@EnableConfigurationProperties(LiteServiceConfig.class) // 激活自動(dòng)配置(指定文件中的配置)
public class LiteFlowAutoConfiguration {

//
//    @Bean(initMethod = "init", destroyMethod = "beforeDestory")
//    public InitLiteFlowBean initLiteFlowBean(){
//        return new InitLiteFlowBean();
//    }


}

@Configuration: 定義一個(gè)配置類

@EnableConfigurationProperties:作用是使@ConfigurationProperties注解生效胁编。

如 @EnableConfigurationProperties(LiteServiceConfig.class) 讓上面的LiteServiceConfig中的

@ConfigurationProperties生效

(5)編寫spring.factories文件加載自動(dòng)配置類

為什么需要spring.factories?

Spring Boot會(huì)默認(rèn)掃描跟啟動(dòng)類平級(jí)的包鳞尔,如果我們的Starter跟啟動(dòng)類不在同一個(gè)主包下嬉橙,需要通過(guò)配置spring.factories文件來(lái)配置生效,SpringBoot默認(rèn)加載各個(gè)jar包下classpath路徑的spring.factories文件寥假,配置的key為

org.springframework.boot.autoconfigure.EnableAutoConfiguration

image-20220803120012943.png

在 resources 目錄下新建 META-INF文件夾憎夷,再創(chuàng)建 spring.factories 文件,加入以下內(nèi)容

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.example.liteflowstarter.config.LiteFlowAutoConfiguration,\

注意:其中填的是配置類的全限定名昧旨,多個(gè)之間逗號(hào)分割拾给,還可以 \ 進(jìn)行轉(zhuǎn)義即相當(dāng)于去掉后面換行和空格符號(hào)

(6)maven去掉打包插件

starter 我們沒有main入口祥得,需要去除pom文件中maven打包插件spring-boot-maven-plugin,starter無(wú)需打成jar包

 <build>
        <plugins>
            <plugin>
<!--                <groupId>org.springframework.boot</groupId>-->
<!--                <artifactId>spring-boot-maven-plugin</artifactId>-->
<!--                <version>2.3.1.RELEASE</version>-->
            </plugin>
        </plugins>
    </build>
(7)在其他項(xiàng)目中引用
<dependency>
    <groupId>com.unionman</groupId>
    <artifactId>liteflow-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

配置文件application.yml 添加starter所需的配置

liteflow:
  ruleSource: liteflow/*.el.xml

app:
  service:
    # umliteflow-spring-boot-starter 識(shí)別 不同服務(wù)的唯一標(biāo)識(shí)
    serviceUid: demo
(8)在starter中使用@Component等注解無(wú)法注入問(wèn)題

由于這里沒有啟動(dòng)類,注入組件不能通過(guò)@SpringBootApplication蒋得,而需通過(guò)包路徑注解掃描 @ComponentScan指定starter最外層包 级及,如 @ComponentScan("com.unionman.liteflow"),即掃描 該包目錄下的@Component额衙,@Repository饮焦,@Service,@Controller

@Configuration 使用詳解

Full全模式和Lite輕量級(jí)模式

@Configuration參數(shù)proxyBeanMethods:

Full 全模式(默認(rèn)):@Configuration(proxyBeanMethods = true)

同一配置類下窍侧,當(dāng)直接調(diào)用@Bean修飾的方法注入的對(duì)象县踢,則調(diào)用該方法會(huì)被代理,從ioc容器中取bean實(shí)列伟件,所以實(shí)例是一樣的硼啤。即單實(shí)例對(duì)象在該模式下SpringBoot每次啟動(dòng)都會(huì)判斷檢查容器中是否存在該組件

Lite 輕量級(jí)模式:@Configuration(proxyBeanMethods = false)

同一配置類下斧账,當(dāng)直接調(diào)用@Bean修飾的方法注入的對(duì)象谴返,則調(diào)用該方法不會(huì)被代理,相當(dāng)于直接調(diào)用一個(gè)普通方法咧织,會(huì)有構(gòu)造方法嗓袱,但是沒有bean的生命周期,返回的是不同的實(shí)例习绢。

注:proxyBeanMethods 是為了讓使用@Bean注解的方法被代理渠抹。而不是@Bean的單例多例的設(shè)置參數(shù)。

測(cè)試?yán)舆@里不展示闪萄,可以下載我的代碼查看

@Configuration(proxyBeanMethods = false)
public class AppConfig {
    
    //放一份myBean到ioc容器
    @Bean
    public Mybean myBean() {
        return new Mybean();
    }
 
    //放一份yourBean到ioc容器
    @Bean
    public YourBean yourBean() {
        System.out.println("==========");
        //注意:@Configuration(proxyBeanMethods = false):myBean()方法不代理梧却,直接調(diào)用
        //注意:@Configuration(proxyBeanMethods = true):myBean()方法代理,從ioc容器拿
        return new YourBean(myBean());
    }
}
什么時(shí)候用Full全模式桃煎,什么時(shí)候用Lite輕量級(jí)模式?

當(dāng)在你的同一個(gè)Configuration配置類中大刊,注入到容器中的bean實(shí)例之間有依賴關(guān)系時(shí)为迈,建議使用Full全模式

當(dāng)在你的同一個(gè)Configuration配置類中,注入到容器中的bean實(shí)例之間沒有依賴關(guān)系時(shí)缺菌,建議使用Lite輕量級(jí)模式葫辐,以提高springboot的啟動(dòng)速度和性能

@ComponentScan 使用詳解

原文鏈接:https://blog.csdn.net/u012326462/article/details/82765485

作用就是根據(jù)定義的掃描路徑,把符合掃描規(guī)則的類裝配spring容器中伴郁。

如果@ComponentScan配置了包耿战,則掃描@ComponentScan配置的包

如果@ComponentScan沒有配置包,則掃描其注解的類的包(如 @SpringbootApplication內(nèi)部就有@ComponentScan焊傅,則掃描啟動(dòng)類所在的包剂陡,這就是為什么只要在該包下基本都能被掃到的原因)


image-20220803144331854.png
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.context.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AliasFor;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;

    String resourcePattern() default "**/*.class";

    boolean useDefaultFilters() default true;

    ComponentScan.Filter[] includeFilters() default {};

    ComponentScan.Filter[] excludeFilters() default {};

    boolean lazyInit() default false;

    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    public @interface Filter {
        FilterType type() default FilterType.ANNOTATION;

        @AliasFor("classes")
        Class<?>[] value() default {};

        @AliasFor("value")
        Class<?>[] classes() default {};

        String[] pattern() default {};
    }
}

basePackages與value: 用于指定包的路徑狈涮,進(jìn)行掃描

basePackageClasses: 用于指定某個(gè)類所在的包的路徑進(jìn)行掃描

nameGenerator: bean的名稱的生成器

useDefaultFilters: 是否開啟對(duì)@Component,@Repository鸭栖,@Service歌馍,@Controller的類進(jìn)行檢測(cè),默認(rèn)true

includeFilters: 包含的過(guò)濾條件

        FilterType.ANNOTATION:按照注解過(guò)濾

        FilterType.ASSIGNABLE_TYPE:按照給定的類型

        FilterType.ASPECTJ:使用ASPECTJ表達(dá)式

        FilterType.REGEX:正則

        FilterType.CUSTOM:自定義規(guī)則

excludeFilters: 排除的過(guò)濾條件晕鹊,用法和includeFilters一樣

DEMO項(xiàng)目目錄


image-20220803142954185.png

應(yīng)用默認(rèn)的過(guò)濾器松却,掃描service包:

@Configuration
@ComponentScan(value = "com.xhx.spring.service",
        useDefaultFilters = true
)
public class MyConfig {
}

HelloController所在的包的類也被掃描了進(jìn)去

@Configuration
@ComponentScan(value = "com.xhx.spring.service",
        useDefaultFilters = true,
        basePackageClasses = HelloController.class
)
public class MyConfig {
}

把默認(rèn)的過(guò)濾器關(guān)掉,掃描帶Controller注解的溅话。

@Configuration
@ComponentScan(value = "com.xhx.spring",
        useDefaultFilters = false,
        includeFilters = {
            @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
        }
)
public class MyConfig {
}

按照類的類型掃描晓锻,雖然HelloController沒有加注解,但是被注入到了spring容器中

@Configuration
@ComponentScan(value = "com.xhx.spring",
        useDefaultFilters = false,
        includeFilters = {
            @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {HelloController.class})
        }
)
public class MyConfig {
}

自定義掃描過(guò)濾器

package com.xhx.spring.componentscan.config;
 
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
 
import java.io.IOException;
 
/**
 * xuhaixing
 * 2018/9/18 23:07
 **/
public class MyTypeFilter implements TypeFilter {
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        String className = metadataReader.getClassMetadata().getClassName();
        // 滿足類名包含Controller的類 會(huì)被掃描
        if(className.contains("Controller")){
            return true;
        }
        return false;
    }
}

注意: 要設(shè)置useDefaultFilters = false(系統(tǒng)默認(rèn)為true飞几,需要手動(dòng)設(shè)置) includeFilters包含過(guò)濾規(guī)則才會(huì)生效砚哆。

@Configuration
@ComponentScan(value = "com.xhx.spring",
        useDefaultFilters = false,
        includeFilters = {
            @ComponentScan.Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class})
        }
)
public class MyConfig {
}

輸出spring容器中的bean的測(cè)試類:只過(guò)濾輸出了名字中含有hello的類。

package com.xhx.spring.componentscan;
 
import com.xhx.spring.componentscan.config.MyConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;
 
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
 
@RunWith(SpringRunner.class)
@SpringBootTest
public class ComponentScanApplicationTests {
 
    @Test
    public void testLoads() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        List<String> hello = Arrays.stream(context.getBeanDefinitionNames()).collect(Collectors.toList());
        hello.stream().filter(name->name.contains("hello")).peek(System.out::println).count();
    }
 
}

[demo]SpringBoot自定義多數(shù)據(jù)源starter組件

https://blog.csdn.net/weixin_45840947/article/details/123892165#t0

【有空看看】mybatis-spring-boot-starter

mybatis自動(dòng)配置原理

https://jishuin.proginn.com/p/763bfbd5ad27

參考資料

  1. Springboot官方文檔
  2. 一文搞懂??SpringBoot自動(dòng)配置原理
  3. SpringBoot starter的理解與使用
  4. 還在curd嗎?封裝屬于自己的Spring-Boot-Starter
  5. SpringBoot自定義多數(shù)據(jù)源starter組件
  6. MyBaits自動(dòng)配置原理
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末循狰,一起剝皮案震驚了整個(gè)濱河市窟社,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌绪钥,老刑警劉巖灿里,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異程腹,居然都是意外死亡匣吊,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門寸潦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)色鸳,“玉大人,你說(shuō)我怎么就攤上這事见转∶福” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵斩箫,是天一觀的道長(zhǎng)吏砂。 經(jīng)常有香客問(wèn)我,道長(zhǎng)乘客,這世上最難降的妖魔是什么狐血? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮易核,結(jié)果婚禮上匈织,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好缀匕,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布纳决。 她就那樣靜靜地躺著,像睡著了一般弦追。 火紅的嫁衣襯著肌膚如雪岳链。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天劲件,我揣著相機(jī)與錄音掸哑,去河邊找鬼。 笑死零远,一個(gè)胖子當(dāng)著我的面吹牛苗分,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播牵辣,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼摔癣,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了纬向?” 一聲冷哼從身側(cè)響起择浊,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎逾条,沒想到半個(gè)月后琢岩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡师脂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年担孔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吃警。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡糕篇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出酌心,到底是詐尸還是另有隱情拌消,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布安券,位于F島的核電站墩崩,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏完疫。R本人自食惡果不足惜泰鸡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一债蓝、第九天 我趴在偏房一處隱蔽的房頂上張望壳鹤。 院中可真熱鬧,春花似錦饰迹、人聲如沸芳誓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)锹淌。三九已至匿值,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間赂摆,已是汗流浹背挟憔。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留烟号,地道東北人绊谭。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像汪拥,于是被迫代替她去往敵國(guó)和親达传。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容