Spring Boot 2 原理簡(jiǎn)介

Spring Boot 2 原理

springboot幫我們做了什么

通常搭建一個(gè)基于spring的web應(yīng)用蛮瞄,我們需要做以下工作:

  1. pom文件中引入相關(guān)jar包庇茫,包括spring蕊玷、springmvc痘儡、redis爽航、mybaits横浑、log4j、mysql-connector-java 等等相關(guān)jar ...

  2. 配置web.xml腻暮,Listener配置彤守、Filter配置、Servlet配置哭靖、log4j配置具垫、error配置 ...

  3. 配置數(shù)據(jù)庫(kù)連接、配置spring事務(wù)

  4. 配置視圖解析器

  5. 開(kāi)啟注解试幽、自動(dòng)掃描功能

  6. 配置完成后部署tomcat筝蚕、啟動(dòng)調(diào)試

  7. ......

  • 搭個(gè)初始項(xiàng)目不一會(huì)就一個(gè)小時(shí)甚至半天過(guò)去了。而用springboot后铺坞,一切都變得很簡(jiǎn)便快速起宽。下來(lái)我們來(lái)一步步分析springboot的起步依賴與自動(dòng)配置這兩個(gè)核心原理。

起步依賴

1. 引入jar


<parent>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-parent</artifactId>

        <version>2.0.3.RELEASE</version>

        <relativePath/> <!-- lookup parent from repository -->

</parent>

<!--mybatis 開(kāi)發(fā)包-->

<dependency>

        <groupId>org.mybatis.spring.boot</groupId>

        <artifactId>mybatis-spring-boot-starter</artifactId>

        <version>1.3.1</version>

</dependency>

<!--springboot web模塊支持-->

<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>

<!--druid 的數(shù)據(jù)源-->

<dependency>

        <groupId>com.alibaba</groupId>

        <artifactId>druid</artifactId>

        <version>1.0.31</version>

</dependency>

  • spring-boot-starter-web包自動(dòng)幫我們引入了web模塊開(kāi)發(fā)需要的相關(guān)jar包济榨,

  • mybatis-spring-boot-starter幫我們引入了dao開(kāi)發(fā)相關(guān)的jar包坯沪。

  • spring-boot-starter-xxx是官方提供的starter,xxx-spring-boot-starter是第三方提供的starter擒滑。

image
  • 可以看出在這個(gè)mybatis-spring-boot-starter 中腐晾,并沒(méi)有任何源碼叉弦,只有一個(gè)pom文件,它的作用就是幫我們引入了相關(guān)jar包藻糖。

2. 配置數(shù)據(jù)源


spring:

        datasource:

                url: jdbc:mysql://127.0.0.1:3306/mybatis_test

                username: root

                password: root

                driver-class-name: com.mysql.jdbc.Driver

                type: com.alibaba.druid.pool.DruidDataSource

                dbcp2:

                        min-idle: 5

                        initial-size: 5

                        max-total: 5

                        max-wait-millis: 200

  • stater機(jī)制幫我們完成了項(xiàng)目起步所需要的的相關(guān)jar包淹冰。那問(wèn)題又來(lái)了,傳統(tǒng)的spring應(yīng)用中不是要在application.xml中配置很多bean的嗎巨柒,比如dataSource的配置榄棵,transactionManager的配置 ... springboot是如何幫我們完成這些bean的配置的?下面我們來(lái)分析這個(gè)過(guò)程

自動(dòng)配置

基于java代碼的bean配置

  • 以mybatis為例潘拱,在上面的截圖中,我們發(fā)下mybatis-spring-boot-starter這個(gè)包幫我們引入了mybatis-spring-boot-autoconfigure這個(gè)包拧略,如下圖:
image
image
image
  • 熟悉@Configuration&@Bean這兩個(gè)bean的同學(xué)或許已經(jīng)知道了芦岂。這兩個(gè)注解一起使用就可以創(chuàng)建一個(gè)基于java代碼的配置類,可以用來(lái)替代相應(yīng)的xml配置文件垫蛆。

  • @Configuration注解的類可以看作是能生產(chǎn)讓Spring IoC容器管理的Bean實(shí)例的工廠禽最。

  • @Bean注解告訴Spring,一個(gè)帶有@Bean的注解方法將返回一個(gè)對(duì)象袱饭,該對(duì)象應(yīng)該被注冊(cè)到spring容器中川无。

  • 傳統(tǒng)的基于xml的bean配置方法如下:


<beans>  

    <bean id = "car" class="com.itpsc.Car">  

        <property name="wheel" ref = "wheel"></property>  

    </bean>  

    <bean id = "wheel" class="com.itpsc.Wheel"></bean>  

</beans>

  • 相當(dāng)于用基于java代碼的配置方式:

@Configuration  

public class Conf {  

        @Bean  

        public Car car() {  

                Car car = new Car();  

                car.setWheel(wheel());  

                return car;  

        }  

        @Bean   

        public Wheel wheel() {  

                return new Wheel();  

        }  

}

  • 所以上面的MybatisAutoConfiguration這個(gè)類,自動(dòng)幫我們生成了SqlSessionFactory這些Mybatis的重要實(shí)例并交給spring容器管理虑乖,從而完成bean的自動(dòng)注冊(cè)懦趋。

自動(dòng)配置條件依賴

  • 從MybatisAutoConfiguration這個(gè)類中使用的注解可以看出,要完成自動(dòng)配置是有依賴條件的疹味。

@Configuration

@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})

@ConditionalOnBean({DataSource.class})

@EnableConfigurationProperties({MybatisProperties.class})

@AutoConfigureAfter({DataSourceAutoConfiguration.class})

public class MybatisAutoConfiguration {

//....

}

  • 這些是springboot特有的仅叫,常見(jiàn)的條件依賴注解有:

  • @ConditionalOnBean,僅在當(dāng)前上下文中存在某個(gè)bean時(shí)糙捺,才會(huì)實(shí)例化這個(gè)Bean诫咱。

  • @ConditionalOnClass,某個(gè)class位于類路徑上洪灯,才會(huì)實(shí)例化這個(gè)Bean坎缭。

  • @ConditionalOnExpression,當(dāng)表達(dá)式為true的時(shí)候签钩,才會(huì)實(shí)例化這個(gè)Bean掏呼。

  • @ConditionalOnMissingBean,僅在當(dāng)前上下文中不存在某個(gè)bean時(shí)铅檩,才會(huì)實(shí)例化這個(gè)Bean哄尔。

  • @ConditionalOnMissingClass,某個(gè)class在類路徑上不存在的時(shí)候柠并,才會(huì)實(shí)例化這個(gè)Bean岭接。

  • @ConditionalOnNotWebApplication富拗,不是web應(yīng)用時(shí)才會(huì)實(shí)例化這個(gè)Bean。

  • @AutoConfigureAfter鸣戴,在某個(gè)bean完成自動(dòng)配置后實(shí)例化這個(gè)bean啃沪。

  • @AutoConfigureBefore,在某個(gè)bean完成自動(dòng)配置前實(shí)例化這個(gè)bean窄锅。

  • 所以要完成Mybatis的自動(dòng)配置创千,需要在類路徑中存在SqlSessionFactory.class、SqlSessionFactoryBean.class這兩個(gè)類入偷,需要存在DataSource這個(gè)bean且這個(gè)bean完成自動(dòng)注冊(cè)追驴。

  • 進(jìn)入DataSourceAutoConfiguration這個(gè)類,可以看到這個(gè)類屬于這個(gè)包:

  • org.springframework.boot.autoconfigure.jdbc

  • 這個(gè)包又屬于spring-boot-autoconfigure-2.0.3.RELEASE.jar這個(gè)包疏之,自動(dòng)配置這個(gè)包幫們引入了jdbc殿雪、kafka、logging锋爪、mail丙曙、mongo等包。很多包需要我們引入相應(yīng)jar后自動(dòng)配置才生效其骄。

springbootautoconfig.png
jars.png

bean參數(shù)獲取

  • 到此我們已經(jīng)知道了bean的配置過(guò)程亏镰,但是還沒(méi)有看到springboot是如何讀取yml或者properites配置文件的的屬性來(lái)創(chuàng)建數(shù)據(jù)源的?

  • 在DataSourceAutoConfiguration類里面拯爽,我們注意到使用了EnableConfigurationProperties這個(gè)注解索抓。


@Configuration

@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})

@EnableConfigurationProperties({DataSourceProperties.class})

@Import({DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class})

public class DataSourceAutoConfiguration {

...

}

  • DataSourceProperties中封裝了數(shù)據(jù)源的各個(gè)屬性,且使用了注解ConfigurationProperties指定了配置文件的前綴毯炮。

@ConfigurationProperties(

        prefix = "spring.datasource"

)

public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {

        private ClassLoader classLoader;

        private String name;

        private boolean generateUniqueName;

        private Class<? extends DataSource> type;

        private String driverClassName;

        private String url;

        private String username;

        private String password;

        private String jndiName;

        ...

}

  • @EnableConfigurationProperties與@ConfigurationProperties這兩個(gè)注解有什么用呢纸兔?

  • @ConfigurationProperties注解的作用是把yml或者properties配置文件轉(zhuǎn)化為bean。

  • @EnableConfigurationProperties注解的作用是使@ConfigurationProperties注解生效否副。如果只配置@ConfigurationProperties注解汉矿,在spring容器中是獲取不到y(tǒng)ml或者properties配置文件轉(zhuǎn)化的bean的。

bean發(fā)現(xiàn)

  • springboot默認(rèn)掃描啟動(dòng)類所在的包下的主類與子類的所有組件备禀,但并沒(méi)有包括依賴包的中的類洲拇,那么依賴包中的bean是如何被發(fā)現(xiàn)和加載的?

  • 我們通常在啟動(dòng)類中加@SpringBootApplication這個(gè)注解曲尸,點(diǎn)進(jìn)去看


@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@SpringBootConfiguration

@EnableAutoConfiguration

@ComponentScan(

        excludeFilters = {@Filter(

        type = FilterType.CUSTOM,

        classes = {TypeExcludeFilter.class}

), @Filter(

        type = FilterType.CUSTOM,

        classes = {AutoConfigurationExcludeFilter.class}

)}

)

public @interface SpringBootApplication {

...

}

  • 實(shí)際上重要的只有三個(gè)Annotation:

  • @Configuration(@SpringBootConfiguration里面還是應(yīng)用了@Configuration)

  • @EnableAutoConfiguration

  • @ComponentScan

  • @Configuration的作用上面我們已經(jīng)知道了赋续,被注解的類將成為一個(gè)bean配置類。

  • @ComponentScan的作用就是自動(dòng)掃描并加載符合條件的組件另患,比如@Component和@Repository等纽乱,最終將這些bean定義加載到spring容器中。

  • @EnableAutoConfiguration 這個(gè)注解的功能很重要昆箕,借助@Import的支持鸦列,收集和注冊(cè)依賴包中相關(guān)的bean定義租冠。


@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@AutoConfigurationPackage

@Import({AutoConfigurationImportSelector.class})

public @interface EnableAutoConfiguration {

        String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

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

        String[] excludeName() default {};

}

  • 如上源碼,@EnableAutoConfiguration注解引入了@AutoConfigurationPackage和@Import這兩個(gè)注解薯嗤。@AutoConfigurationPackage的作用就是自動(dòng)配置的包顽爹,@Import導(dǎo)入需要自動(dòng)配置的組件。

  • 進(jìn)入@AutoConfigurationPackage骆姐,發(fā)現(xiàn)也是引入了@Import注解


@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@Import({Registrar.class})

public @interface AutoConfigurationPackage {

}


static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

        Registrar() {

        }

        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {

                 AutoConfigurationPackages.register(registry, new String[]{(new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()});

        }

        public Set<Object> determineImports(AnnotationMetadata metadata) {

                return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));

        }

    }

  • new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()

  • new AutoConfigurationPackages.PackageImport(metadata)

  • 這兩句代碼的作用就是加載啟動(dòng)類所在的包下的主類與子類的所有組件注冊(cè)到spring容器镜粤,這就是前文所說(shuō)的springboot默認(rèn)掃描啟動(dòng)類所在的包下的主類與子類的所有組件。

  • 那問(wèn)題又來(lái)了玻褪,要搜集并注冊(cè)到spring容器的那些beans來(lái)自哪里肉渴?

  • 進(jìn)入 AutoConfigurationImportSelector類


public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {

private static final String[] NO_IMPORTS = new String[0];

...

    public String[] selectImports(AnnotationMetadata annotationMetadata) {

                if(!this.isEnabled(annotationMetadata)) {

                        return NO_IMPORTS;

                } else {

                        AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);

                        AnnotationAttributes attributes = this.getAttributes(annotationMetadata);

                        List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);

                        configurations = this.removeDuplicates(configurations);

                        Set exclusions = this.getExclusions(annotationMetadata, attributes);

                        this.checkExcludedClasses(configurations, exclusions);

                        configurations.removeAll(exclusions);

                        configurations = this.filter(configurations, autoConfigurationMetadata);

                        this.fireAutoConfigurationImportEvents(configurations, exclusions);

                        return StringUtils.toStringArray(configurations);

                }

    }

...

    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {

                List configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());

                Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");

                return configurations;

    }

...

}

  • SpringFactoriesLoader.loadFactoryNames方法調(diào)用loadSpringFactories方法從所有的jar包中讀取META-INF/spring.factories文件信息。

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {

        MultiValueMap result = (MultiValueMap)cache.get(classLoader);

        if(result != null) {

                return result;

        } else {

                try {

                        Enumeration ex = classLoader != null?classLoader.getResources("META-INF/spring.factories"):ClassLoader.getSystemResources("META-INF/spring.factories");

                        LinkedMultiValueMap result1 = new LinkedMultiValueMap();

                        while(ex.hasMoreElements()) {

                        URL url = (URL)ex.nextElement();

                        UrlResource resource = new UrlResource(url);

                        Properties properties = PropertiesLoaderUtils.loadProperties(resource);

                        Iterator var6 = properties.entrySet().iterator();

                        while(var6.hasNext()) {

                                Entry entry = (Entry)var6.next();

                                List factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue()));

                                result1.addAll((String)entry.getKey(), factoryClassNames);

                        }

                        }

                        cache.put(classLoader, result1);

                        return result1;

                } catch (IOException var9) {

                        throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);

            }

        }

    }

  • 下面是spring-boot-autoconfigure這個(gè)jar中spring.factories文件部分內(nèi)容带射,其中有一個(gè)key為org.springframework.boot.autoconfigure.EnableAutoConfiguration的值定義了需要自動(dòng)配置的bean同规,通過(guò)讀取這個(gè)配置獲取一組@Configuration類。

org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\

org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters

org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\

org.springframework.boot.autoconfigure.condition.OnClassCondition

# Auto Configure

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\

org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\

org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\

org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\

org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\

  • 每個(gè)xxxAutoConfiguration都是一個(gè)基于java的bean配置類庸诱。實(shí)際上,這些xxxAutoConfiguratio不是所有都會(huì)被加載晤揣,會(huì)根據(jù)xxxAutoConfiguration上的@ConditionalOnClass等條件判斷是否加載桥爽。

private static <T> T instantiateFactory(String instanceClassName, Class<T> factoryClass, ClassLoader classLoader) {

        try {

                Class ex = ClassUtils.forName(instanceClassName, classLoader);

                if(!factoryClass.isAssignableFrom(ex)) {

                        throw new IllegalArgumentException("Class [" + instanceClassName + "] is not assignable to [" + factoryClass.getName() + "]");

                } else {

                        return ReflectionUtils.accessibleConstructor(ex, new Class[0]).newInstance(new Object[0]);

                }

         } catch (Throwable var4) {

                throw new IllegalArgumentException("Unable to instantiate factory class: " + factoryClass.getName(), var4);

        }

}

  • 如上代碼段,通過(guò)反射機(jī)制將spring.factories中@Configuration類實(shí)例化為對(duì)應(yīng)的java實(shí)列昧识。到此我們已經(jīng)知道怎么發(fā)現(xiàn)要自動(dòng)配置的bean了钠四,最后一步就是怎么樣將這些bean加載到spring容器。

bean加載

  • 如果要讓一個(gè)普通類交給Spring容器管理跪楞,通常有以下方法:
  1. 使用 @Configuration與@Bean 注解

  2. 使用@Controller @Service @Repository @Component 注解標(biāo)注該類缀去,然后啟用@ComponentScan自動(dòng)掃描

  3. 使用@Import 方法

  • springboot中使用了@Import 方法

  • @EnableAutoConfiguration注解中使用了@Import({AutoConfigurationImportSelector.class})注解,AutoConfigurationImportSelector實(shí)現(xiàn)了DeferredImportSelector接口甸祭,

DeferredImportSelector接口繼承了ImportSelector接口缕碎,ImportSelector接口只有一個(gè)selectImports方法。

總結(jié)

  • 我們可以將自動(dòng)配置的關(guān)鍵幾步以及相應(yīng)的注解總結(jié)如下:
  1. @Configuration&與@Bean->基于java代碼的bean配置

  2. @Conditional->設(shè)置自動(dòng)配置條件依賴

  3. @EnableConfigurationProperties與@ConfigurationProperties->讀取配置文件轉(zhuǎn)換為bean池户。

  4. @EnableAutoConfiguration咏雌、@AutoConfigurationPackage 與@Import->實(shí)現(xiàn)bean發(fā)現(xiàn)與加載。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載校焦,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者赊抖。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市寨典,隨后出現(xiàn)的幾起案子氛雪,更是在濱河造成了極大的恐慌,老刑警劉巖耸成,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件报亩,死亡現(xiàn)場(chǎng)離奇詭異浴鸿,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)捆昏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門赚楚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人骗卜,你說(shuō)我怎么就攤上這事宠页。” “怎么了寇仓?”我有些...
    開(kāi)封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵举户,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我遍烦,道長(zhǎng)俭嘁,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任服猪,我火速辦了婚禮供填,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘罢猪。我一直安慰自己近她,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布膳帕。 她就那樣靜靜地躺著粘捎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪危彩。 梳的紋絲不亂的頭發(fā)上攒磨,一...
    開(kāi)封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音汤徽,去河邊找鬼娩缰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛谒府,可吹牛的內(nèi)容都是我干的漆羔。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼狱掂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼演痒!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起趋惨,我...
    開(kāi)封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤鸟顺,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體讯嫂,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蹦锋,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了欧芽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片莉掂。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖千扔,靈堂內(nèi)的尸體忽然破棺而出憎妙,到底是詐尸還是另有隱情,我是刑警寧澤曲楚,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布厘唾,位于F島的核電站,受9級(jí)特大地震影響龙誊,放射性物質(zhì)發(fā)生泄漏抚垃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一趟大、第九天 我趴在偏房一處隱蔽的房頂上張望鹤树。 院中可真熱鬧,春花似錦逊朽、人聲如沸罕伯。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)捣炬。三九已至熊昌,卻和暖如春绽榛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背婿屹。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工灭美, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人昂利。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓届腐,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蜂奸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子犁苏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

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