Spring Boot 注解收集

? ? ? ?Spring Boot使用過程中与倡,經(jīng)常需要和很多注解打交道距帅。也是我們常說的注解編程抖仅。所以接下來我們對Spring Boot常用注解做一個簡單的收集交煞。

一 配置類相關(guān)注解

? ? ? ?

配置類相關(guān)注解 解釋
@SpringBootApplication 組合注解咏窿,由@SpringBootConfiguration、@EnableAutoConfiguration素征、@ComponentScan三者組成集嵌,我們一般把該注解添加在啟動類上
@ComponentScan 用于指定組件的掃描路徑和過濾規(guī)則
@EnableAutoConfiguration 啟用自動配置,就是讓@SpringBootConfiguration御毅、@Configuration注解起作用
@SpringBootConfiguration 標注當前類是配置類
@Configuration 標注當前類是配置類
@Bean 注解在方法上根欧,一般在@Configuration注解類下使用,把方法返回的對象添加到Spring IOC容器里面去端蛆,并且容器里面Bean的名字就是方法名
@Import 導入類凤粗,有時沒有把某個類注入到IOC容器中,但在運用的時候需要獲取該類對應的Bean今豆,這個時候我們就可以使用@Import導入需要的Bean
@AutoConfigureAfter 加載指定配置的類之后再加載當前類侈沪,一般和@Configuration一起出現(xiàn)
@AutoConfigureBefore 加載指定配置的類之前加載當前類,一般和@Configuration一起出現(xiàn)
@AutoConfigureOrder 指定配置類的加載順序晚凿,一般和@Configuration一起出現(xiàn)

1.1 @SpringBootApplication

@Target(ElementType.TYPE) // 添加在類上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration //@SpringBootConfiguration
@EnableAutoConfiguration // @EnableAutoConfiguration
@ComponentScan(excludeFilters = { // @ComponentScan
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM,
                classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

    /**
     * 排除特定的自動配置類 -- @EnableAutoConfiguration里面的功能
     */
    @AliasFor(annotation = EnableAutoConfiguration.class)
    Class<?>[] exclude() default {};

    /**
     * 排除特定的自動配置類名稱 -- @EnableAutoConfiguration里面的功能
     */
    @AliasFor(annotation = EnableAutoConfiguration.class)
    String[] excludeName() default {};

    /**
     *
     * 在指定的包下掃描帶組件注解的類 -- @ComponentScan里面的功能
     */
    @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
    String[] scanBasePackages() default {};

    /**
     * 指定類亭罪,會去掃描該類所在的包下面帶有組件注解的類 -- @ComponentScan里面的功能
     */
    @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
    Class<?>[] scanBasePackageClasses() default {};

}

? ? ? ?@SpringBootApplication是一個組合注解,由@SpringBootConfiguration、@EnableAutoConfiguration歼秽、@ComponentScan三個注解組成.換言之加了@SpringBootApplication注解之后就把相應的三個注解的功能都加上了应役。Springboot提供了。簡化程序的配置燥筷。@SpringBootApplication注解一般添加的啟動了上箩祥。關(guān)于@SpringBootConfiguration、@EnableAutoConfiguration肆氓、@ComponentScan我們會在下面講到袍祖。

1.2 @ComponentScan

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE) // 可以添加在類上
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {

    /**
     * scan對應的包路徑(可以指定多個)
     */
    @AliasFor("basePackages")
    String[] value() default {};
    @AliasFor("value")
    String[] basePackages() default {};

    /**
     * 可以指定多個類或接口的class,掃描時會 在這些指定的類和接口所屬的包進行掃面。
     */
    Class<?>[] basePackageClasses() default {};

    /**
     * 通過BeanNameGenerator來得到bean對應的名字谢揪,進而得到對應的Class
     */
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    /**
     * 處理檢測到的bean的scope范圍
     */
    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

    /**
     * 是否為檢測到的組件生成代理
     */
    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;

    /**
     * 控制符合組件檢測條件的類文件   默認是包掃描下的(包括子包) *.class
     */
    String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;

    /**
     * 是否對帶有@Component @Repository @Service @Controller注解的類開啟檢測,默認是開啟的
     */
    boolean useDefaultFilters() default true;

    /**
     * 指定某些定義Filter滿足條件的組件 FilterType有5種類型如:
     *  ANNOTATION, 注解類型 默認
     *  ASSIGNABLE_TYPE,指定固定類
     *  ASPECTJ蕉陋, ASPECTJ類型
     *  REGEX,正則表達式
     *  CUSTOM,自定義類型
     *
     */
    Filter[] includeFilters() default {};

    /**
     * 排除某些過來器掃描到的類
     */
    Filter[] excludeFilters() default {};

    /**
     * 掃描到的類是都開啟懶加載 捐凭,默認是不開啟的
     */
    boolean lazyInit() default false;

}

? ? ? ?@ComponentScan做的事情就是告訴Spring從哪里找到Bean。@ComponentScan會默認去@SpringBootApplication注解的類所在的包及其下級包去掃描bean(就是去掃描添加了@Component凳鬓、@Service茁肠、@Repository、@Controller)缩举,然后把他們添加到Spring IOC容器里面去垦梆。但是,有的時候有些包不在這個下面仅孩,這個時候我們就需要通過@ComponentScan顯示的去指定要掃描的包名了秀又。

1.3 @EnableAutoConfiguration姐仅、@SpringBootConfiguration、@Configuration

因為@EnableAutoConfiguration、@SpringBootConfiguration洼专、@Configuration這三是一體的商佛,所以咱們把他們歸到一起來說明愁茁。

1.3.1 @EnableAutoConfiguration

@Target(ElementType.TYPE) // 組件添加在類上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class) // 幫助SpringBoot應用將所有符合條件的@Configuration配置都加載到當前SpringBoot創(chuàng)建并使用的IoC容器
public @interface EnableAutoConfiguration {

    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    /**
     * 排除特定的自動配置類
     */
    Class<?>[] exclude() default {};

    /**
     *
     * 排除特定的自動配置類名稱
     */
    String[] excludeName() default {};

}

? ? ? ?@EnableAutoConfiguration注解使自動配置生效严望。用于幫助SpringBoot應用將所有符合條件的@SpringBootConfiguration、@Configuration配置加載到當前SpringBoot IOC容器里面去温艇。換句話說因悲,想使用@SpringBootConfiguration、@Configuration就得一定得使用@EnableAutoConfiguration注解勺爱。只有@EnableAutoConfiguration配合@SpringBootConfiguration晃琳、@Configuration共同作用下,才可以幫助Spring Boot把@SpringBootConfiguration琐鲁、@Configuration修飾的類里面的Bean掃描出來,添加到Spring IOC容器里面去.

按照我們常規(guī)的Spring Boot應用卫旱。我們一般會啟動類上添加@SpringBootApplication注解。其實就已經(jīng)加上了@EnableAutoConfiguration注解围段,因為@SpringBootApplication注解包括了@EnableAutoConfiguration注解顾翼。

1.3.2 @SpringBootConfiguration、@Configuration

? ? ? ?@SpringBootConfiguration奈泪、@Configuration兩個注解是一樣的适贸。用來標記配置類。

@SpringBootConfiguration

@Target(ElementType.TYPE) // 添加在類上的注解
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {

}

@Configuration

@Target(ElementType.TYPE) // 添加在類上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // 也是一個組件
public @interface Configuration {

    /**
     * Configuration注解的類也是一個組件涝桅,用于顯示的指定在Spring容器里面組件的名稱拜姿。
     * 如果沒有顯示指定就是類的名稱并且首字母小寫
     */
    @AliasFor(annotation = Component.class)
    String value() default "";

}

? ? ? ?簡單來說就是用@SpringBootConfiguration、@Configuration標注的類是配置類冯遂,同時在該類下面一般會包含一個或多個被@Bean注解的方法蕊肥。這些方法將會被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext類進行掃描。加入到Spring IOC容器中蛤肌。并且這些Bean的名稱就是方法名壁却。

1.4 @Bean

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) // 一般添加在方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {

    /**
     * 顯示指定Bean對應的名字批狱,如果沒有指定則是對應的方法名字
     */
    @AliasFor("name")
    String[] value() default {};

    /**
     * 顯示指定Bean對應的名字,如果沒有指定則是對應的方法名字
     */
    @AliasFor("value")
    String[] name() default {};

    @Deprecated
    Autowire autowire() default Autowire.NO;

    /**
     * 用來表示當前bean是否可以被注入到其他實例中儒洛,依賴注入
     */
    boolean autowireCandidate() default true;

    /**
     * 構(gòu)造方法執(zhí)行完之后精耐,執(zhí)行的方法
     */
    String initMethod() default "";

    /**
     * 關(guān)閉應用程序上下文時在bean實例上調(diào)用的方法的可選名稱
     */
    String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;

}

? ? ? ?@Bean是一個方法級別上的注解狼速,主要用在@SpringBootConfiguration琅锻、@Configuration注解的配置類里面使用。Spring Boot會幫助把@Bean注解方法的對象添加到Spring IOC容器里面去向胡,供我們在別的地方使用恼蓬。

1.4 @Import

@Target(ElementType.TYPE) // 指明該注解是添加在類上的
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

    /**
     * 需要import的類
     */
    Class<?>[] value();

}

? ? ? ?@Import注解用于幫助把我們需要的類導入到組件類里面去,有時沒有把某個類注入到Spring IOC容器中僵芹,但在某個類使用的時候需要獲取該類對應的Bean处硬,此時就需要用到@Import注解。

1.5 控制配置類的加載順序(@AutoConfigureAfter拇派、@AutoConfigureBefore荷辕、@AutoConfigureOrder)

@AutoConfigureAfter、@AutoConfigureBefore

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE }) // 一般用于添加在類上
@Documented
public @interface AutoConfigureAfter {

    /**
     * Class數(shù)組對應的類加載之后在加載
     */
    Class<?>[] value() default {};

    /**
     * 配置名稱對應的配置類加載之后在加載
     */
    String[] name() default {};

}

@AutoConfigureOrder

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD })
@Documented
public @interface AutoConfigureOrder {

    int DEFAULT_ORDER = 0;

    /**
     * 加載順序件豌,值越小越先加載
     */
    int value() default DEFAULT_ORDER;

}

? ? ? ?@AutoConfigureAfter疮方、@AutoConfigureBefore、@AutoConfigureOrder三個注解用于控制配置類的加載順序茧彤。而且非常重要的一點是這三個注解一定要配合spring.factory文件來一起使用骡显,因為Spring只會對spring.factory文件下的配置類進行排序。所以我們需要在resources/META-INF/spring.factory文件里面寫入需要排序的這些配置類的路徑曾掂。

二 Bean(組件)相關(guān)注解

2.1 申明Bean相關(guān)的注解

? ? ? ?用于把一個類聲明為Bean(組件)惫谤。這樣Spring Boot啟動的時候(注意@ComponentScan注解的使用)就會把這些Bean掃描出來添加到IOC容器里面去。

申明Bean相關(guān)的注解 解釋
@Component 最普通的組件珠洗,可以被注入到Spring容器進行管理溜歪,通用注解
@Service 作用于業(yè)務邏輯層的組件,只是標注該類處于業(yè)務邏輯層
@Repository 作用于持久層(dao)的組件许蓖,并支持自動處理數(shù)據(jù)庫操作產(chǎn)生的異常

@Component蝴猪、@Service、@Repository注解屬性都是一樣的

@Target(ElementType.TYPE) //該注解一般用于添加在方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {

    /**
     * 組件對應的名字(獲取組件的時候可以通過類型獲取蛔糯,也可以通過名字獲日)
     */
    String value() default "";

}

關(guān)于@Repository的作用,這里特別說明下。因為原生java操作數(shù)據(jù)庫所產(chǎn)生的異常只定義了幾種蚁飒,但是產(chǎn)生數(shù)據(jù)庫異常的原因卻有很多種动壤,這樣對于數(shù)據(jù)庫操作的報錯排查造成了一定的影響;而Spring拓展了原生的持久層異常淮逻,針對不同的產(chǎn)生原因有了更多的異常進行描述琼懊。所以阁簸,在注解了@Repository的類上如果數(shù)據(jù)庫操作中拋出了異常哼丈,就能對其進行處理醉旦,轉(zhuǎn)而拋出的是翻譯后的spring專屬數(shù)據(jù)庫異常车胡,方便我們對異常進行排查處理。

? ? ? ?關(guān)于@Component匈棘、@Service丧慈、@Repository的使用,最終只有一個目的主卫,希望咱們一看到@Repository就知道這個是數(shù)據(jù)庫Dao層的代碼逃默,一看到@Service注解就知道是業(yè)務層的代碼。

2.2 Bean屬性相關(guān)注解

? ? ? ?

Bean屬性相關(guān)注解 解釋
@Scope 設(shè)置Spring容器如何新建Bean實例簇搅,一般配合@Bean完域、@Component、@Service馍资、@Repository一起使用
@PostConstruct 在構(gòu)造函數(shù)執(zhí)行完之后執(zhí)行
@PreDestory 在Bean銷毀之前執(zhí)行

2.2.1 @Scope

@Target({ElementType.TYPE, ElementType.METHOD}) // 一般用來添加在類或者方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {

    /**
     * Alias for {@link #scopeName}.
     * @see #scopeName
     */
    @AliasFor("scopeName")
    String value() default "";

    /**
     *
     * 指定要用于帶注釋的組件/ bean的作用域的名稱
     *  可以設(shè)置下面四種值
     *  - ConfigurableBeanFactory.SCOPE_PROTOTYPE: 每次依賴注入時筒主,都會產(chǎn)生新的對象
     *  - ConfigurableBeanFactory.SCOPE_SINGLETON: 單例模式,在整個應用中只能創(chuàng)建一個實例
     *  - org.springframework.web.context.WebApplicationContext.SCOPE_REQUEST: 在一個請求中創(chuàng)建一個實例
     *  - org.springframework.web.context.WebApplicationContext.SCOPE_SESSION: 每次創(chuàng)建一個會話中創(chuàng)建一個實例
     */
    @AliasFor("value")
    String scopeName() default "";

    /**
     * 指定是否應將組件配置為作用域代理
     * 可以設(shè)置為下面幾種值
     * - ScopedProxyMode.DEFAULT:等同于ScopedProxyMode.NO
     * - ScopedProxyMode.NO:(默認)不進行代理
     * - ScopedProxyMode.INTERFACES:創(chuàng)建一個JDK代理模式
     * - ScopedProxyMode.TARGET_CLASS:基于類的代理模式
     */
    ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;

}

? ? ??Scope字面意思是范圍鸟蟹,標志一個注入器/對象的使用范圍乌妙,很多文章說成生命周期也是可以的。比如建钥,單例模式熊经,局部單例模式等等。@Scope注解就是用來聲明一個Bean的生命周期(作用域)然低。

? ? ??@Scope實際使用的時候一般是添加在@Bean修飾的方法上的吨灭。比如如下的實例。

@Configuration
public class ZkConfiguration {

    @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON) // 只有一個實例
    @Bean(initMethod = "init", destroyMethod = "stop")
    public ZkClient zkClient() {
        return new ZkClient();
    }


}

2.2.2 @PostConstruct

@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}

? ? ? ?@PostConstruct用來修飾一個分靜態(tài)并且返回void的方法檩互。該方法只會在構(gòu)造函數(shù)之后執(zhí)行一次薄风。@PostConstruct一般@Component横辆、@Service、@Repository修飾的對象里面使用锌畸。

2.2.3 @PreDestory

@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PreDestroy {
}

? ? ? ?@PreDestroy也是用來修飾一個分靜態(tài)并且返回void的方法幻捏。該方法只會在對象函數(shù)之后執(zhí)行一次。@PreDestory和一樣@PostConstruct一般也是在@Component钝域、@Service迷捧、@Repository修飾的對象里面使用。

2.3 Bean注入相關(guān)注解

? ? ? ?注入注解就是幫助我們自動引入依賴的對象捅位。

Bean注入相關(guān)注解 解釋
@Autowired 先按類型注入焰雕,然后按照名稱注入,都無法找到唯一的一個實現(xiàn)類則報錯
@Inject 在Spring的環(huán)境下,@Inject和@Autowired是相同的
@Resource 先按名字注入郭膛,再按類型注入如捅,都無法找到唯一的一個出現(xiàn)異常
@Qualifier 用于指定Bean的名字己肮,一般配合用來配合@Autowired使用

2.3.1 @Autowired

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

    /**
     * 申明當前對象是否是必須的
     */
    boolean required() default true;

}

? ? ? ?@Autowired Spring提供的工具(由Spring的依賴注入工具(BeanPostProcessor、BeanFactoryPostProcessor)自動注入Bean赤拒。它可以對類成員變量航夺、方法及構(gòu)造函數(shù)進行標注始衅。 通過 @Autowired的使用來消除 set ,get方法彻亲。@Autowired先通過類型去Spring IOC容器里面查找對象宦芦,如果沒有查找到再按照Bean名稱去查找。如果無法找到唯一的Bean并且Bean是必須的則拋出異常。(可以看下@Qualifier的用法)

2.3.2 @Inject

? ? ? ?在Spring的環(huán)境下,@Inject和@Autowired是相同的啤月。

2.3.3 @Resource

@Target({TYPE, FIELD, METHOD}) // 添加在變量或者方法上
@Retention(RUNTIME)
public @interface Resource {
    /**
     * 資源的JNDI名稱
     */
    String name() default "";

    /**
     * 引用指向它的資源的名稱可以使用全局JNDI名稱鏈接到任何兼容的資源
     */

    String lookup() default "";

    /**
     * Bean對應的類型
     */
    Class<?> type() default java.lang.Object.class;

    /**
     * 資源的兩種可能的身份驗證類型
     */
    enum AuthenticationType {
        CONTAINER,
        APPLICATION
    }

    /**
     * 用于此資源的身份驗證類型。
     */
    AuthenticationType authenticationType() default AuthenticationType.CONTAINER;

    /**
     * 指示是否可以在此組件與其他組件之間共享此資源。
     */
    boolean shareable() default true;

    /**
     * 此資源應映射到的產(chǎn)品特定名稱
     */
    String mappedName() default "";

    /**
     * 此資源的描述
     */
    String description() default "";
}

? ? ? ?@Resource有兩個重要屬性:name、type圾亏。@Resource和@Autowired的區(qū)別在于捧杉。@Resource先通過Bean名字去容器里面查找锤悄,如果沒找到在通過類型去容器里面查找淋样。

2.3.4 @Qualifier

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {

    /**
     * 注解對應的名字
     */
    String value() default "";

}

? ? ? ?可能會有這樣一種情況垢粮,當你創(chuàng)建多個具有相同類型的 bean 時嗅虏,并且想要用一個屬性只為它們其中的一個進行裝配裹纳,在這種情況下,我們可以使用@Qualifier注釋和@Autowired注釋通過指定哪一個真正的bean將會被裝配來消除混亂弦讽。比如如下的代碼岳悟。

    private ProductInfo productInfo;

    @Autowired
    @Qualifier(value = "productInfo")
    public void setProductInfo(ProductInfo productInfo) {
        this.productInfo = productInfo;
    }

2.4 Bean延時加載注解(@Lazy)

@Lazy

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Lazy {

    /**
     * 是否懶加載
     */
    boolean value() default true;

}

? ? ? ?@Lazy:用于標識Bean是否需要延遲加載普碎,延時加載就是在第一次使用的時候才加載。@Lazy的主要作用就是用來減少Spring IOC容器啟動的加載時間录平。

2.5 Bean依賴注解(@DependsOn)

@DependsOn

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DependsOn {

    /**
     * 依賴的Bean對應的名稱
     */
    String[] value() default {};

}

? ? ??@DependsOn:控制Bean加載順序麻车。指定先加載@DependsOn對應的Bean。

三 讀取配置文件(.properties斗这、.yam)相關(guān)注解

? ? ? ?讀取配置文件相關(guān)的注解动猬,就是用來幫助我們獲取到配置文件.properties、.yam里面信息的。

讀取配置文件相關(guān)注解 解釋
@EnableConfigurationProperties 讓使用@ConfigurationProperties注解的類生效
@ConfigurationProperties 讀取配置文件的信息璃哟,并自動封裝成實體類
@PropertySource 指定的屬性文件(只能加載*.properties文件户矢,不能加載yaml文件)映射到對象
@ImportResource 導入Spring的*.xml配置文件荠藤,讓xml配置文件里面的內(nèi)容生效

3.1 @EnableConfigurationProperties

@Target(ElementType.TYPE) // 添加在類上的注解
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EnableConfigurationPropertiesImportSelector.class)
public @interface EnableConfigurationProperties {

    /**
     * 對應于添加了@ConfigurationProperties的類,讓他們生效
     */
    Class<?>[] value() default {};

}

? ? ? ?@EnableConfigurationProperties注解的作用是讓使用@ConfigurationProperties注解的類生效。你可以通過在@EnableConfigurationProperties注解中直接簡單的列出屬性類來快捷的注冊@ConfigurationProperties bean的定義。而且@EnableConfigurationProperties我們一般添加在Applicaiton類上面。

3.2 @ConfigurationProperties

@Target({ ElementType.TYPE, ElementType.METHOD }) // 添加在類或者方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ConfigurationProperties {

    /**
     * 屬性前綴
     */
    @AliasFor("prefix")
    String value() default "";
    @AliasFor("value")
    String prefix() default "";

    /**
     * 是否忽視無效的字段
     */
    boolean ignoreInvalidFields() default false;

    /**
     * 是否忽視未知字段
     */
    boolean ignoreUnknownFields() default true;

}

? ? ? ?有時候有這樣子的情景,我們想把配置文件的信息,讀取并自動封裝成實體類哈雏,這樣子,這時候,我們就可以使用@ConfigurationProperties注解,它可以把同類的配置信息自動封裝成實體類。

? ? ? ?我們用一個簡單的實例來說明,比如我們在application.yml里面添加一些自定義的屬性吹零。我們就可以通過@ConfigurationProperties注解來獲取到這些屬性值

application.yml文件里面添加


# 自定義的一些屬性
user:
  info:
    name: tuacy
    age: 27

把這些屬性映射到實體類

@ConfigurationProperties(prefix = "user.info")
public class UserInfo {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

? ? ??最后在Application類上添加@EnableConfigurationProperties(value = {UserInfo.class})。這樣就把配置文件里面的數(shù)據(jù)都映射到UserInfo類上去了,并且UserInfo類已經(jīng)添加到了Spring IOC容器里面去了厦画。

3.3 @PropertySource

@Target(ElementType.TYPE) // 該注解添加在類上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(PropertySources.class)
public @interface PropertySource {

    /**
     * 指示此屬性源的名稱。如果省略蒋畜,將根據(jù)底層資源的描述生成名稱
     */
    String name() default "";

    /**
     * 指示要加載的屬性文件的資源位置
     * 例如声畏,value = "classpath:product.properties"。則表示resource目錄下的product.properties文件
     */
    String[] value();

    /**
     * 指示是否應忽略找不到屬性資源的錯誤
     */
    boolean ignoreResourceNotFound() default false;

    /**
     * 編碼格式
     * 例如姻成,"UTF-8"
     */
    String encoding() default "";

    /**
     * 只是怎么去解析屬性對應的值插龄,比如如果想把 yyyy-mm 轉(zhuǎn)換成Date
     * @see org.springframework.core.io.support.DefaultPropertySourceFactory
     * @see org.springframework.core.io.support.ResourcePropertySource
     */
    Class<? extends PropertySourceFactory> factory() default PropertySourceFactory.class;

}

? ? ? ?@PropertySource注解的作用是加載指定的屬性文件(配置文件),把配置文件映射到對象佣渴。只能加載*.properties文件辫狼,不能加載yaml文件。@PropertySource一般配合@Value一起使用辛润。

? ? ? ?關(guān)于@PropertySource注解使用的一個簡單的實例膨处。

resource目錄下product.properties文件內(nèi)容(配置文件)

# 自定義配置信息
ppid = 1000
mmid = 1
ccid = 10

配置文件映射到Bean

/**
 * 注入resource下product.properties文件里面的信息
 */
@Configuration
@PropertySource(value = "classpath:product.properties", encoding = "utf-8")
public class ProductInfo {

    @Value("${ppid}")
    private int pid;


    @Value("${mmid}")
    private int mid;


    @Value("${ccid}")
    private int cid;

    public int getPid() {
        return pid;
    }

    public void setPid(int pid) {
        this.pid = pid;
    }

    public int getMid() {
        return mid;
    }

    public void setMid(int mid) {
        this.mid = mid;
    }

    public int getCid() {
        return cid;
    }

    public void setCid(int cid) {
        this.cid = cid;
    }
}

3.4 @ImportResource

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE) // 該注解只能添加在類上(我們一般把他添加在主配置類上)
@Documented
public @interface ImportResource {

    /**
     * xml配置文件對應的位置
     */
    @AliasFor("locations")
    String[] value() default {};
    @AliasFor("value")
    String[] locations() default {};

    /**
     *
     * 處理通過屬性指定的資源時使用的實現(xiàn)
     */
    Class<? extends BeanDefinitionReader> reader() default BeanDefinitionReader.class;

}

? ? ? ?導入Spring的xml配置文件见秤,讓xml配置文件里面的內(nèi)容生效。SpringBoot中編寫的Spring配置文件是不能自動識別的真椿。(相當于把Bean放到xml配置文件里面去定義了鹃答。隨著Spring Boot的使用這種方式會越來越少,因為現(xiàn)在大部分都是通過@Configuration來配置的)突硝。

四 @Value注解

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {

    /**
     *
     * 實際值表達式
     * 例如测摔,{@code #{systemProperties.myProp}}.
     */
    String value();

}

? ? ? ?@Value注解用于將外部的值動態(tài)注入到Bean中,大概有如下這么幾種情況:

4.1 注入普通字符串

    /**
     * 注入普通字符串,相當于private String normal = "normal"
     */
    @Value("normal")
    private String normal;

4.2 注入操作系統(tǒng)屬性

    /**
     * 注入操作系統(tǒng)屬性
     */
    @Value("#{systemProperties['os.name']}")
    private String systemPropertiesName;

4.3 注入表達式結(jié)果

    /**
     * 注入表達式結(jié)果,相當于 double randomNumber = java.lang.Math).random() * 100.0
     */
    @Value("#{ T(java.lang.Math).random() * 100.0 }")
    private double randomNumber;

4.4 注入其他Bean屬性

    /**
     * 注入其他Bean屬性:相當于把IOC容器里面valueInject名字對應的對象的name屬性賦值給變量
     */
    @Value("#{valueInject.name}")
    private String fromAnotherBean;

4.5 注入文件資源

    /**
     * 注入文件資源,相當于把resource目錄下valueInjectConfig.txt文件注入進來
     */
    @Value("classpath:valueInjectConfig.txt")
    private Resource valueInjectConfig;

4.6 注入URL資源

    /**
     * 注入URL資源解恰,相當于把http://www.baidu.com對應的資源注入進來
     */
    @Value("http://www.baidu.com")
    private Resource baiduUrl;

4.7 注入配置文件信息

? ? ? ?比如如下的例子我們加載product.properties文件里面的信息(我們也可以加載application.yml文件里面的信息锋八,加載application.yml文件信息的時候可以不加@PropertySource指定路徑)

resource目錄下product.properties文件信息

# 自定義配置信息
ppid = 1000
mmid = 1
ccid = 10

@Value注入

/**
 * 注入resource下product.properties文件里面的信息
 */
@Configuration
@PropertySource(value = "classpath:product.properties", encoding = "utf-8")
public class ProductInfo {

    @Value("${ppid}")
    private int pid;


    @Value("${mmid}")
    private int mid;


    @Value("${ccid}")
    private int cid;

    public int getPid() {
        return pid;
    }

    public void setPid(int pid) {
        this.pid = pid;
    }

    public int getMid() {
        return mid;
    }

    public void setMid(int mid) {
        this.mid = mid;
    }

    public int getCid() {
        return cid;
    }

    public void setCid(int cid) {
        this.cid = cid;
    }
}

五 環(huán)境切換相關(guān)注解

? ? ? ?環(huán)境切換注解說白了就是做到不同的環(huán)境注入不同的Bean。比如常見的有開發(fā)環(huán)境和測試環(huán)境用的數(shù)據(jù)庫配置不一樣护盈。

環(huán)境切換相關(guān)注解 解釋
@Profile 通過設(shè)定Environment的ActiveProfiles來設(shè)定當前Bean是否要添加到Spring IOC容器里面去
@Conditional 按照一定的條件進行判斷挟纱,滿足條件給添加到Spring IOC容器里面去

5.1 @Profiles

@Target({ElementType.TYPE, ElementType.METHOD}) // 該注解用于添加在類或者方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {

    /**
     * profile對應的名字。比如生成環(huán)境有一個名字腐宋,測試環(huán)境有一個名字
     */
    String[] value();

}

? ? ??@Profiles可以實現(xiàn)不同環(huán)境(開發(fā)紊服、測試、部署等)使用不同的配置胸竞。任何@Component或@Configuration都能被@Profile標記欺嗤,從而限制加載它的時機。

5.2 @Conditional

@Target({ElementType.TYPE, ElementType.METHOD}) // 常用于添加在類或者方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

    /**
     * 繼承Condition接口的Class數(shù)組
     * 當所有的Class的matches方法都返回true的時候卫枝,才滿足條件
     */
    Class<? extends Condition>[] value();

}

? ? ??@Conditional注解會按照一定的條件進行判斷煎饼,滿足條件給容器注冊bean。

六 條件注解

條件注解 解釋
@ConditionalOnClass classpath中存在該類時起效
@ConditionalOnMissingClass classpath中不存在該類時起效
@ConditionalOnBean Spring IOC容器中存在該類型Bean時起效
@ConditionalOnMissingBean Spring IOC容器中不存在該類型Bean時起效
@ConditionalOnSingleCandidate DI容器中該類型Bean只有一個或@Primary的只有一個時起效
@ConditionalOnExpression SpEL表達式結(jié)果為true時
@ConditionalOnProperty 參數(shù)設(shè)置或者值一致時起效
@ConditionalOnResource 指定的文件存在時起效
@ConditionalOnJndi 指定的JNDI存在時起效
@ConditionalOnJava 指定的Java版本存在時起效
@ConditionalOnWebApplication Web應用環(huán)境下起效
@ConditionalOnNotWebApplication 非Web應用環(huán)境下起效

? ? ? ?所有的這些條件注解一般和聲明Bean的一些注解(@Bean剃盾、@Component腺占、@Service、@Repository)同時出現(xiàn)痒谴。來控制Bean是否生成衰伯。

七 切面AOP相關(guān)注解

切面AOP相關(guān)注解 解釋
@Aspect 聲明一個切面,只是一個標識作用
@PointCut 聲明切點,在java配置類中使用@EnableAspectJAutoProxy注解開啟Spring對AspectJ代理的支持
@Around 在方法執(zhí)行之前與之后執(zhí)行
@Before 在方法執(zhí)行之前執(zhí)行
@After 在方法執(zhí)行之后執(zhí)行
@AfterReturning 方法正常退出的時候執(zhí)行
@AfterThrowing 方法有異常拋出的時候執(zhí)行

7.1 @Aspect

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE) // 添加在方法上
public @interface Aspect {

    /**
     * @return the per clause expression, defaults to singleton aspect.
     * Valid values are "" (singleton), "perthis(...)", etc
     */
    public String value() default "";
}

? ? ? ?@Aspect注解的作用是把當前類標識為一個切面供Spring容器讀取。@Aspect注解只是一個標識作用积蔚。

7.2 @PointCut

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) // 添加在方法上面
public @interface Pointcut {

    /**
     * 切入點表達式
     */
    String value() default "";

    /**
     * 指定命名切入點方法參數(shù)列表參數(shù)名字意鲸,
     * 可以有多個用“,”分隔尽爆,這些參數(shù)將傳遞給通知方法同名的參數(shù)怎顾,
     * 同時比如切入點表達式“args(param)”將匹配參數(shù)類型為命名切入點方法同名參數(shù)指定的參數(shù)類型。
     */
    String argNames() default "";
}

? ? ? ?@Pointcut:Pointcut是植入Advice的觸發(fā)條件漱贱。每個Pointcut的定義包括2部分槐雾,一是表達式,二是方法簽名幅狮。方法簽名必須是public及void型募强≈昃模可以將Pointcut中的方法看作是一個被Advice引用的助記符,因為表達式不直觀擎值,因此我們可以通過方法簽名的方式為此表達式命名慌烧。因此Pointcut中的方法只需要方法簽名,而不需要在方法體內(nèi)編寫實際代碼鸠儿。

7.3 @Around

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) // 注解用于添加在方法上
public @interface Around {

    /**
     * 切入點表達式屹蚊,一般配合@Pointcut一起使用
     */
    String value();

    /**
     * 用來接收AspectJ表達式中的參數(shù)
     */
    String argNames() default "";

}

? ? ? ?@Around環(huán)繞增強,方法執(zhí)行前和執(zhí)行后都會執(zhí)行。

7.4 @Before

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Before {

    /**
     * 切入點表達式鲫趁,一般配合@Pointcut一起使用
     */
    String value();

    /**
     * 用來接收AspectJ表達式中的參數(shù)
     */
    String argNames() default "";

}

? ? ? ?@Before方法執(zhí)行前執(zhí)行硼讽。

7.5 @After

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface After {

    /**
     * 切入點表達式并齐,一般配合@Pointcut一起使用
     */
    String value();

    /**
     * 用來接收AspectJ表達式中的參數(shù)
     */
    String argNames() default "";

}

? ? ? ?@After方法執(zhí)行后執(zhí)行。

7.6 @AfterReturning

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AfterReturning {

    /**
     * 切入點表達式,一般配合@Pointcut一起使用
     */
    String value() default "";

    /**
     * 切入點表達式炉峰,一般配合@Pointcut一起使用,指定時覆蓋 "value" 
     */
    String pointcut() default "";

    /**
     * 用于綁定返回值的參數(shù)的名稱
     */
    String returning() default "";

    /**
     * 用來接收AspectJ表達式中的參數(shù)
     */
    String argNames() default "";

}

? ? ? ?@AfterReturning方法正常退出的時候執(zhí)行淘邻。

7.7 @AfterThrowing

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AfterThrowing {

    /**
     * 切入點表達式,一般配合@Pointcut一起使用
     */
    String value() default "";

    /**
     * 切入點表達式嗦随,一般配合@Pointcut一起使用,指定時覆蓋 "value"
     */
    String pointcut() default "";

    /**
     * 用于綁定拋出異常的參數(shù)的名稱
     */
    String throwing() default "";

    /**
     * 用來接收AspectJ表達式中的參數(shù)
     */
    String argNames() default "";

}

? ? ? ?@AfterThrowing方法拋出異常的時候執(zhí)行列荔。

八 事件監(jiān)聽注解(@EventListener)

@EventListener

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) // 添加在方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EventListener {

    /**
     * 此偵聽器處理的事件類。具體可以參考ApplicationEvent的用法
     */
    @AliasFor("classes")
    Class<?>[] value() default {};
    @AliasFor("value")
    Class<?>[] classes() default {};

    /**
     * 用來定義所偵聽事件是否處理的前置條件枚尼,這里需要注意的是使用 Spring Expression Language (SpEL)定義條件
     * condition可以實現(xiàn)更加精細的事件監(jiān)聽
     *
     *  比如如下的例子贴浙,監(jiān)聽CustomEvent里面messageEntity對象的code的屬性為‘oKong’的事件
     *  @EventListener(condition = "#customEvent.messageEntity.code == 'oKong'")
     *  public void handleCustomEventByCondition(CustomEvent customEvent) {
     *      //TODO:
     *  }
     */
    String condition() default "";

}

? ? ? ?@EventListener修飾在方法上。用于監(jiān)聽Spring事件署恍。更加具體的用法可以參考ApplicationListener的使用崎溃。

七 異步注解

異步注解 解釋
@EnableAsync 開啟異步方法的支持
@Async 異步方法

7.1 @EnableAsync

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {

    /**
     * 指示要在類或方法級別檢測的“異步”注釋類型,默認是@Async
     */
    Class<? extends Annotation> annotation() default Annotation.class;

    /**
     * 當AdviceModemode為PROXY時盯质,選擇代理是基于接口實現(xiàn)還是cglib實現(xiàn)
     */
    boolean proxyTargetClass() default false;

    /**
     * 代理方式是由JDK實現(xiàn)還是AspectJ實現(xiàn)
     */
    AdviceMode mode() default AdviceMode.PROXY;

    /**
     *
     * 指示AsyncAnnotationBeanPostProcessors的順序
     * 默認值是 Ordered.LOWEST_PRECEDENCE,為了在所有其他后處理器之后運行
     */
    int order() default Ordered.LOWEST_PRECEDENCE;

}

? ? ??@EnableAsync用于開啟異步方法的支持袁串。只有開啟了異步方法的支持才可以使用@Async概而。

7.2 @Async

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Async {

    /**
     *
     * 指定異步操作的限定符值。
     */
    String value() default "";

}

? ? ??@Async可以把某一個方法或者類下面的方法全部變成異步處理的方法囱修。

八 定時任務相關(guān)注解

? ? ? ?

定時任務相關(guān)注解 解釋
@EnableScheduling 在配置類上使用赎瑰,開啟計劃任務的支持
@Scheduled 來申明這是一個任務,包括cron,fixDelay,fixRate等類型

8.1 @EnableScheduling

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(SchedulingConfiguration.class)
@Documented
public @interface EnableScheduling {

}

? ? ? ?@EnableScheduling注解用于開啟定時任務的支持破镰。簡單來說就是如果我們想在應用里面使用@Scheduled就需要添加@EnableScheduling注解餐曼。一般添加在主配置類上。

8.2 @Scheduled

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {

    /**
     * cron表達式
     */
    String cron() default "";

    /**
     * 時區(qū)
     * java.util.TimeZone#ID鲜漩。cron表達式會基于該時區(qū)解析
     */
    String zone() default "";

    /**
     * 上一次執(zhí)行完畢時間點之后多長時間再執(zhí)行
     * @Scheduled(fixedDelay = 5000) //上一次執(zhí)行完畢時間點之后5秒再執(zhí)行
     */
    long fixedDelay() default -1;

    /**
     * 與fixedDelay意思相同源譬,只是使用字符串的形式。唯一不同的是支持占位符
     * @Scheduled(fixedDelayString = "5000") //上一次執(zhí)行完畢時間點之后5秒再執(zhí)行
     */
    String fixedDelayString() default "";

    /**
     * 上一次開始執(zhí)行時間點之后多長時間再執(zhí)行
     * @Scheduled(fixedRate = 5000) //上一次開始執(zhí)行時間點之后5秒再執(zhí)行
     */
    long fixedRate() default -1;

    /**
     * 與fixedRate意思相同孕似,只是使用字符串的形式
     */
    String fixedRateString() default "";

    /**
     * 第一次延遲多長時間后再執(zhí)行
     */
    long initialDelay() default -1;

    /**
     * 與initialDelay意思相同踩娘,只是使用字符串的形式
     */
    String initialDelayString() default "";

}

? ? ? ?@Scheduled用于定義一個定時任務。Spring會幫我們?nèi)ソ馕鲞@個定時任務喉祭,并且按照我們設(shè)置的時間去執(zhí)行這個任務养渴。

九 事務相關(guān)注解

事務相關(guān)注解 解釋
@EnableTransactionManagement 開啟注解式事務的支持
@Transactional 控制事務注解

9.1 @EnableTransactionManagement

@Target(ElementType.TYPE) // 該注解用于添加在類上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

    /**
     * 當AdviceModemode為PROXY時,選擇代理是基于接口實現(xiàn)還是cglib實現(xiàn)
     */
    boolean proxyTargetClass() default false;

    /**
     * 代理方式是由JDK實現(xiàn)還是AspectJ實現(xiàn)
     */
    AdviceMode mode() default AdviceMode.PROXY;

    /**
     *
     * 指示AsyncAnnotationBeanPostProcessors的順序
     * 默認值是 Ordered.LOWEST_PRECEDENCE,為了在所有其他后處理器之后運行
     */
    int order() default Ordered.LOWEST_PRECEDENCE;

}

? ? ? ?@EnableTransactionManagement用于開啟事務的支持泛烙,我們一般在主配置類上添加該注解厚脉。

9.2 @Transactional

@Target({ElementType.METHOD, ElementType.TYPE}) // 添加在類或者方法上
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {

    /**
     * 當在配置文件中有多個 TransactionManager , 可以用該屬性指定選擇哪個事務管理器。
     */
    @AliasFor("transactionManager")
    String value() default "";

    /**
     * 當在配置文件中有多個 TransactionManager , 可以用該屬性指定選擇哪個事務管理器胶惰。
     */
    @AliasFor("value")
    String transactionManager() default "";

    /**
     * 事務的傳播行為,默認值為 REQUIRED
     * 默認 Propagation.REQUIRED
     */
    Propagation propagation() default Propagation.REQUIRED;

    /**
     * 事務的隔離度霞溪,默認值采用 DEFAULT
     */
    Isolation isolation() default Isolation.DEFAULT;

    /**
     * 事務的超時時間孵滞,默認值為-1。如果超過該時間限制但事務還沒有完成鸯匹,則自動回滾事務
     */
    int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;

    /**
     * 指定事務是否為只讀事務坊饶,默認值為 false;為了忽略那些不需要事務的方法殴蓬,比如讀取數(shù)據(jù)匿级,可以設(shè)置 read-only 為 true。
     */
    boolean readOnly() default false;

    /**
     * 用于指定能夠觸發(fā)事務回滾的異常類型染厅,
     */
    Class<? extends Throwable>[] rollbackFor() default {};
    String[] rollbackForClassName() default {};

    /**
     * 拋出 no-rollback-for 指定的異常類型痘绎,不回滾事務。
     */
    Class<? extends Throwable>[] noRollbackFor() default {};
    String[] noRollbackForClassName() default {};

}

? ? ? ?@Transactional注解我們一般添加在Dao層的方法上面肖粮。當數(shù)據(jù)庫操作異常的時候回滾孤页。

十 緩存相關(guān)注解

緩存相關(guān)注解 解釋
@EnableCaching 開啟緩存注解的支持
@CacheConfig 用于統(tǒng)一制定一些配置參數(shù),這樣在其他緩存注解里面就不用重復指定
@Cacheable 如果之前已經(jīng)有緩存數(shù)據(jù)值直接返回緩存數(shù)據(jù)涩馆,否則執(zhí)行方法罐栈,緩存方法的返回結(jié)果
@CachePut 能夠根據(jù)方法的請求參數(shù)對其結(jié)果進行緩存确丢,和 @Cacheable 不同的是极谊,它每次都會觸發(fā)真實方法的調(diào)用
@CacheEvict 能夠根據(jù)一定的條件對緩存進行清空
@Caching 組合多個Cache注解的使用

10.1 @EnableCaching

@Target(ElementType.TYPE) // 該注解一般用于添加類上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {

    /**
     * 當AdviceModemode為PROXY時,選擇代理是基于接口實現(xiàn)還是cglib實現(xiàn)
     */
    boolean proxyTargetClass() default false;

    /**
     * 代理方式是由JDK實現(xiàn)還是AspectJ實現(xiàn)
     */
    AdviceMode mode() default AdviceMode.PROXY;

    /**
     *
     * 指示AsyncAnnotationBeanPostProcessors的順序
     * 默認值是 Ordered.LOWEST_PRECEDENCE,為了在所有其他后處理器之后運行
     */
    int order() default Ordered.LOWEST_PRECEDENCE;

}

? ? ? ?@EnableCaching注解用于開啟緩存的支持稠项,只有開啟了緩存的支持,才有后續(xù)的@Cacheable鲜结、@Caching展运、@CacheEvict、@CachePut轻腺、@CacheConfig的使用乐疆。

10.2 @CacheConfig

@Target(ElementType.TYPE) // 該注解常用于添加在類上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CacheConfig {

    /**
     * 緩存的名稱,必須至少指定一個贬养,我們可以簡單的認為是命名空間挤土。我們一般用項目的名字
     */
    String[] cacheNames() default {};

    /**
     * key生成器,可以實現(xiàn) org.springframework.cache.interceptor.KeyGenerator接口误算,來規(guī)定想要保存的key的格式
     * 設(shè)置自定義的key生成器實現(xiàn)類對應Bean的名字
     */
    String keyGenerator() default "";

    /**
     * 緩存管理器仰美,我們可以實現(xiàn)CacheManager接口來實現(xiàn)緩存管理器
     * 指定自定義的緩存管理器對應的Bean名稱
     */
    String cacheManager() default "";

    /**
     * Cache解析器,用于根據(jù)實際情況來動態(tài)解析使用哪個Cache儿礼,實現(xiàn)CacheResolver接口
     * 指定自定義的Cache解析器對應的Bean名稱
     */
    String cacheResolver() default "";

}

? ? ??當我們需要緩存的地方越來越多咖杂,這個時候我們可以使用@CacheConfig注解來統(tǒng)一制定一些參數(shù)。這樣在@Cacheable蚊夫、@CachePut等這些注解上就可以不用重復去填這些參數(shù)了诉字。

10.3 @Cacheable

@Target({ElementType.METHOD, ElementType.TYPE}) // 該注解用于添加在方法或者類上
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {

    /**
     * 緩存的名稱,必須至少指定一個,緩存的名稱知纷,必須至少指定一個壤圃,我們可以簡單的認為是命名空間。我們一般用項目的名字
     */
    @AliasFor("cacheNames")
    String[] value() default {};
    @AliasFor("value")
    String[] cacheNames() default {};

    /**
     * 緩存的key
     */
    String key() default "";

    /**
     * key生成器琅轧,可以實現(xiàn) org.springframework.cache.interceptor.KeyGenerator接口伍绳,來規(guī)定想要保存的key的格式
     * 設(shè)置自定義的key生成器實現(xiàn)類對應Bean的名字
     */
    String keyGenerator() default "";

    /**
     * 緩存管理器,我們可以實現(xiàn)CacheManager接口來實現(xiàn)緩存管理器
     * 指定自定義的緩存管理器對應的Bean名稱
     */
    String cacheManager() default "";

    /**
     * Cache解析器乍桂,用于根據(jù)實際情況來動態(tài)解析使用哪個Cache冲杀,實現(xiàn)CacheResolver接口
     * 指定自定義的Cache解析器對應的Bean名稱
     */
    String cacheResolver() default "";

    /**
     * 緩存的條件
     */
    String condition() default "";

    /**
     * 否定緩存。當條件結(jié)果為TRUE時睹酌,就不會緩存
     * @Cacheable(value=”testcache”,unless=”#userName.length()>2”)
     */
    String unless() default "";

    /**
     * 是否使用異步模式
     */
    boolean sync() default false;

}

? ? ? ?@Cacheable注解會先查詢是否已經(jīng)有緩存权谁,有會使用緩存,沒有則會執(zhí)行方法并緩存憋沿。

10.4 @CachePut

@Target({ElementType.METHOD, ElementType.TYPE}) // 添加在類或者方法上
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CachePut {

    /**
     * 緩存的名稱闯传,必須至少指定一個,我們可以簡單的認為是命名空間。我們一般用項目的名字
     */
    @AliasFor("cacheNames")
    String[] value() default {};
    @AliasFor("value")
    String[] cacheNames() default {};

    /**
     * 緩存的key
     */
    String key() default "";

    /**
     * key生成器甥绿,可以實現(xiàn) org.springframework.cache.interceptor.KeyGenerator接口字币,來規(guī)定想要保存的key的格式
     * 設(shè)置自定義的key生成器實現(xiàn)類對應Bean的名字
     */
    String keyGenerator() default "";

    /**
     * 緩存管理器,我們可以實現(xiàn)CacheManager接口來實現(xiàn)緩存管理器
     * 指定自定義的緩存管理器對應的Bean名稱
     */
    String cacheManager() default "";

    /**
     * Cache解析器共缕,用于根據(jù)實際情況來動態(tài)解析使用哪個Cache洗出,實現(xiàn)CacheResolver接口
     * 指定自定義的Cache解析器對應的Bean名稱
     */
    String cacheResolver() default "";

    /**
     * 緩存的條件
     */
    String condition() default "";

    /**
     * 否定緩存。當條件結(jié)果為TRUE時图谷,就不會緩存
     * @Cacheable(value=”testcache”,unless=”#userName.length()>2”)
     */
    String unless() default "";

}

? ? ??@CachePut注解的作用主要針對方法配置翩活,能夠根據(jù)方法的請求參數(shù)對其結(jié)果進行緩存,和@Cacheable不同的是便贵,它每次都會觸發(fā)真實方法的調(diào)用 菠镇。簡單來說就是用戶更新緩存數(shù)據(jù)。但需要注意的是該注解的value 和 key 必須與要更新的緩存相同承璃,也就是與@Cacheable相同利耍。

10.5 @CacheEvict

@Target({ElementType.METHOD, ElementType.TYPE}) // 添加在類或者方法上
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CacheEvict {

    /**
     * 緩存的名稱,必須至少指定一個盔粹,我們可以簡單的認為是命名空間隘梨。我們一般用項目的名字
     */
    @AliasFor("cacheNames")
    String[] value() default {};
    @AliasFor("value")
    String[] cacheNames() default {};

    /**
     * 緩存的key
     */
    String key() default "";

    /**
     * key生成器,可以實現(xiàn) org.springframework.cache.interceptor.KeyGenerator接口舷嗡,來規(guī)定想要保存的key的格式
     * 設(shè)置自定義的key生成器實現(xiàn)類對應Bean的名字
     */
    String keyGenerator() default "";

    /**
     * 緩存管理器轴猎,我們可以實現(xiàn)CacheManager接口來實現(xiàn)緩存管理器
     * 指定自定義的緩存管理器對應的Bean名稱
     */
    String cacheManager() default "";

    /**
     * Cache解析器,用于根據(jù)實際情況來動態(tài)解析使用哪個Cache进萄,實現(xiàn)CacheResolver接口
     * 指定自定義的Cache解析器對應的Bean名稱
     */
    String cacheResolver() default "";

    /**
     * 緩存的條件
     */
    String condition() default "";

    /**
     * 是否清空所有緩存內(nèi)容捻脖,缺省為 false,如果指定為 true中鼠,則方法調(diào)用后將立即清空所有緩存
     */
    boolean allEntries() default false;

    /**
     * 是否在方法執(zhí)行前就清空郎仆,缺省為 false,
     * 如果指定為 true兜蠕,則在方法還沒有執(zhí)行的時候就清空緩存,缺省情況下抛寝,如果方法執(zhí)行拋出異常熊杨,則不會清空緩存
     */
    boolean beforeInvocation() default false;

}

? ? ??@CacheEvict能夠根據(jù)一定的條件對緩存進行清空。

10.6 @Caching

@Target({ElementType.METHOD, ElementType.TYPE}) // 添加在類或者方法上
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Caching {

    Cacheable[] cacheable() default {};

    CachePut[] put() default {};

    CacheEvict[] evict() default {};

}

? ? ??@Caching用于組合多個Cache注解的使用盗舰。相當于在一個方法上面添加多個注解晶府。

關(guān)于Spring Boot緩存這部分的內(nèi)容,咱們可以試著去整合redis或者ehcache來使用钻趋。

十一 Spring MVC相關(guān)注解

? ? ? ?

Spring MVC相關(guān)注解 解釋
@Controller 聲明該類為SpringMVC中的Controller,用來處理http請求
@RestController 組合注解川陆,@Controller + @ResponseBody.意味著,該Controller的所有方法都默認加上了@ResponseBody
@RequestMapping 把htt請求映射到方法上去
@PathVariable 用于接收路徑參數(shù)蛮位,比如@RequestMapping(“/hello/{name}”)申明的路徑较沪,將注解放在參數(shù)中前鳞绕,即可獲取該值,通常作為Restful的接口實現(xiàn)方法
@RequestParam 將請求參數(shù)綁定至方法參數(shù)
@RequestBody 用于讀取Request請求的body部分數(shù)據(jù)
@ResponseBody 將Controller的方法返回的對象尸曼,通過適當?shù)腍ttpMessageConverter轉(zhuǎn)換為指定格式后们何,寫入到Response對象的body數(shù)據(jù)區(qū)
@ModelAttribute 主要作用是綁定request或是form參數(shù)到模型(Model)
@InitBinder 用來設(shè)置WebDataBinder,WebDataBinder用來自動綁定前臺請求參數(shù)到Model中
@ExceptionHandler 用于全局處理控制器里的異常
@ControllerAdvice 通過該注解控轿,我們可以將對于控制器的全局配置放置在同一個位置,和@Controller對應
@RestControllerAdvice 同上和@RestController對應

11.1 @Controller

@Target({ElementType.TYPE}) // 該注解用于添加在方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {

    /**
     * 用于顯示指定組件的名稱
     * @Contorller 修飾的類對應的對象也是一個Bean,是一個注解冤竹,
     */
    @AliasFor(annotation = Component.class)
    String value() default "";

}

? ? ? ?@Controller的作用很簡單,就是表示添加了該注解的類是負責處理由DispatcherServlet 分發(fā)的http請求的茬射。

11.2 @RestController

? ? ? ?@RestController是一個組合注解鹦蠕,@Controller+@ResponseBody。關(guān)于@ResponseBody的解釋在抛,我們會在下文講到钟病。

11.3 @RequestMapping

@Target({ElementType.METHOD, ElementType.TYPE}) // 可以作用于類,接口霜定,方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {

    /**
     * 為該映射起一個名字
     */
    String name() default "";

    /**
     * 指定請求的實際地址
     */
    @AliasFor("path")
    String[] value() default {};
    @AliasFor("value")
    String[] path() default {};

    /**
     * 指定請求的method類型档悠, GET、POST望浩、PUT辖所、DELETE等
     */
    RequestMethod[] method() default {};

    /**
     * 指定request中必須包含某些參數(shù)值,才讓該方法處理
     * 1. param1: 表示請求必須包含名為param1的請求參數(shù)
     * 2. !param1: 表示請求不能包含名為param1的請求參數(shù)
     * 3. param1!=value1: 表示請求包含名為param1的請求參數(shù)磨德,但其值不能為 value1
     * 4. {"param1=value1", "param2"}: 請求必須包含名為 param1和param2的兩個請求參數(shù)缘回,且 param1參數(shù)的值必須為 value1
     */
    String[] params() default {};

    /**
     * 指定request中必須包含某些指定的header值,才能讓該方法處理請求典挑。
     * 比如, @RequestMapping(value = "/something", headers = "content-type=text/*")
     * 將會匹配所有請求里面包含 Content-Type of "text/html", "text/plain", etc.
     */
    String[] headers() default {};

    /**
     * 指定處理請求的提交內(nèi)容類型(Content-Type),例如application/json, text/html
     * Examples:
     * consumes = "text/plain"
     * consumes = {"text/plain", "application/*"}
     */
    String[] consumes() default {};

    /**
     * 指定返回的內(nèi)容類型您觉,僅當request請求頭中的(Accept)類型中包含該指定類型才返回
     * Examples:
     * <pre class="code">
     * produces = "text/plain"
     * produces = {"text/plain", "application/*"}
     * produces = MediaType.APPLICATION_JSON_UTF8_VALUE
     * </pre>
     */
    String[] produces() default {};

}

? ? ? ?@RequestMapping是一個用來處理請求地址映射的注解拙寡。該注解可用于類或方法上,用于類上琳水,表示類中的所有響應請求的方法都是以該地址作為父路徑肆糕。@RequestMapping最終的目的就是把http對應的請求映射到對應的方法上。

11.3 @PathVariable

@Target(ElementType.PARAMETER) // 該注解用于添加在參數(shù)上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PathVariable {

    /**
     * Alias for {@link #name}.
     */
    @AliasFor("name")
    String value() default "";

    /**
     * 要綁定的路徑變量的名稱
     */
    @AliasFor("value")
    String name() default "";

    /**
     * 該屬性是否是必須的在孝,如果設(shè)置成必須的诚啃,但是路徑里面沒有傳遞該變量過來就拋出異常
     */
    boolean required() default true;

}

? ? ? ?@PathVariable注解用于從url中獲取數(shù)據(jù)。

11.4 @RequestParam

@Target(ElementType.PARAMETER) // 該注解只能加載參數(shù)上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {

    /**
     * 請求參數(shù)名
     */
    @AliasFor("name")
    String value() default "";
    @AliasFor("value")
    String name() default "";

    /**
     * 是否為必須參數(shù)
     */
    boolean required() default true;

    /**
     * 默認值私沮,沒有匹配到參數(shù)情況下的默認值
     */
    String defaultValue() default ValueConstants.DEFAULT_NONE;

}

? ? ? ?@RequestParam用于將請求參數(shù)綁定至方法參數(shù)始赎。

11.5 @RequestBody

@Target(ElementType.PARAMETER) // 該注解用于添加在參數(shù)上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestBody {

    /**
     * 該參數(shù)是否是必須的(是否非空)
     */
    boolean required() default true;

}

? ? ? ?該注解用于讀取Request請求的body部分數(shù)據(jù),使用系統(tǒng)默認配置的HttpMessageConverter進行解析,然后把相應的數(shù)據(jù)綁定到要返回的對象上造垛。簡單來說就是把Request請求對應的body數(shù)據(jù)映射成參數(shù)里面的對象魔招。

11.6 @ResponseBody

@Target({ElementType.TYPE, ElementType.METHOD}) // 該注解用于添加在類或者方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {

}

? ? ? ?該注解用于將Controller的方法返回的對象,通過適當?shù)腍ttpMessageConverter轉(zhuǎn)換為指定格式后筋搏,寫入到Response對象的body數(shù)據(jù)區(qū)仆百。

11.7 @ModelAttribute

@Target({ElementType.PARAMETER, ElementType.METHOD}) // 該注解用于添加在類或者方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ModelAttribute {

    /**
     * Alias for {@link #name}.
     */
    @AliasFor("name")
    String value() default "";

    /**
     * 要綁定的model屬性的名稱
     */
    @AliasFor("value")
    String name() default "";

    /**
     *
     * 允許直接在ModelAttribute方法參數(shù)或從ModelAttribute方法返回的屬性上聲明數(shù)據(jù)綁定,這兩種方法都會阻止該屬性的數(shù)據(jù)綁定奔脐。
     */
    boolean binding() default true;

}

? ? ? ?@ModelAttribute注解的主要作用是綁定request或是form參數(shù)到模型(Model)對象俄周。可以使用保存在request或session中的對象來組裝模型對象髓迎。注意峦朗,被@ModelAttribute注解的方法會在controller方法(@RequestMapping注解的)之前執(zhí)行。因為模型對象要先于controller方法之前創(chuàng)建排龄。

11.7.1 @ModelAttribute添加在方法上

? ? ? ?@ModelAttribute注解在方法上說明方法的作用是用于添加一個或多個屬性到Model上波势。被@ModelAttribute注釋的方法會在此Controller每個方法執(zhí)行前被執(zhí)行。因此對于一個Controller映射多個URL的用法來說橄维,要謹慎使用尺铣。

11.7.1.1 @ModelAttribute添加在沒有返回值的方法上

? ? ? ?@ModelAttribute添加的方法沒有返回值,一般這個時候我們需要自己去往Model里面添加數(shù)據(jù)了争舞,要不然沒啥意義凛忿。Model 就相當于每次請求的一個背包,我們可以往背包里面放東西竞川。

    /**
     * Model: 就相當于每次請求的一個背包店溢,我們可以往背包里面放東西
     */
    @ModelAttribute
    public void postVoidModelAttribute(@RequestParam String abc, Model model) {
        // 往model里面添加一個屬性
        model.addAttribute("userId0", abc);
    }

11.7.1.2 @ModelAttribute添加在有返回值的方法上

? ? ? ?@ModelAttribute添加在有返回值的方法上,會自動將該返回值放到Model里面去委乌。

其實咱們這里的兩個例子是等效的床牧,都是把@RequestParam對應的值放到Model里面去了。

    /**
     * Model: 就相當于每次請求的一個背包遭贸,我們可以往背包里面放東西
     * @ModelAttribute 添加在有返回值的放的方法上戈咳,會把返回值放到Model里面去
     */
    @ModelAttribute(value = "userId1")
    public String postReturnModelAttribute(@RequestParam String abc) {
        return abc;
    }

11.7.2 @ModelAttribute添加在參數(shù)上

? ? ? ?@ModelAttribute添加在參數(shù)上的時候用于從Model里面獲取數(shù)據(jù)。上面我們已經(jīng)通過把@ModelAttribute添加在方法上往Model里面添加了數(shù)據(jù)了壕吹,是時候取出來了著蛙。

    /**
     * Model: 就相當于每次請求的一個背包,我們可以往背包里面放東西
     * 會在其他添加了@RequestMapping的方法之前執(zhí)行
     */
    @ModelAttribute
    public void postVoidModelAttribute(@RequestParam String abc, Model model) {
        // 往model里面添加一個屬性
        model.addAttribute("userId0", abc);
    }

    /**
     * Model: 就相當于每次請求的一個背包算利,我們可以往背包里面放東西
     * @ModelAttribute 添加在有返回值的放的方法上,會把返回值放到Model里面去
     * 會在其他添加了@RequestMapping的方法之前執(zhí)行
     */
    @ModelAttribute(value = "userId1")
    public String postReturnModelAttribute(@RequestParam String abc) {
        return abc;
    }

    /**
     * 上面我們已經(jīng)通過把@ModelAttribute添加在方法上往Model里面去了泳姐,這個時候我們可以通過把@ModelAttribute添加在參數(shù)上獲取Model里面的值
     */
    @RequestMapping(value = "/text0")
    public String test0(@RequestParam String abc, @ModelAttribute("userId0") String userId) {
        System.out.println(userId);
        return "helloWorld";
    }

    /**
     * 其實我們也可以直接拿到Model
     */
    @RequestMapping(value = "/text1")
    public String helloWorld(@RequestParam String abc, Model model) {
        Map<String, Object> mapList = model.asMap();
        return "helloWorld";
    }

11.8 @InitBinder

@Target({ElementType.METHOD}) // 該注解只能添加在方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface InitBinder {

    /**
     * value,作用是限制對哪些 @RequestMapping 方法起作用,
     * 具體篩選條件就是通過@RequestMapping方法入?yún)砗Y選效拭,
     * 默認不寫就代表對所有@RequestMapping的方法起作用。
     */
    String[] value() default {};

}

? ? ? ?@InitBinder:用于給Binder做初始化,被@InitBinder注解的方法可以對WebDataBinder初始化缎患。WebDataBinder是用于表單到方法的數(shù)據(jù)綁定的慕的。只在添加了@InitBinder注解方法所在的控制器(Controller)里面有效。@InitBinder對應的方法在Controller的請求執(zhí)行映射的方法之前被執(zhí)行挤渔。同時添加了@InitBinder注解的方法返回值必須為null肮街。

? ? ? ?我們用一個具體的實例來說明@InitBinder的用法,可能有這么個場景判导,關(guān)于時間部分我們調(diào)用接口的時候傳遞的是 “2019-09-05” 的格式嫉父,但是我們后天需要Date的格式。這個時候@InitBinder就派上大用場了呀眼刃,我們可以通過@InitBinder配合WebDataBinder的使用幫我們把 “2019-09-05” 轉(zhuǎn)換成Date绕辖。

@RestController
@RequestMapping(path = "/initBinder")
public class InitBinderController {

    /**
     * 對當前控制器的所有請求都有效
     * 前臺傳遞過來的String類型時間,通過下面的初始化綁定擂红,轉(zhuǎn)換成Date類型
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        // 我們前臺傳過來的time字段對應的值可能是“2019-05-06”這樣的仪际,我們可以在這里把他們轉(zhuǎn)換成Date類型的
        binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
    }


    @RequestMapping(value = "/test", method = RequestMethod.POST)
    public String helloWorld(@RequestBody InitBinderTestVo vo) {
        System.out.println(vo.getTime());
        return "success";
    }

}

11.9 @ExceptionHandler

@Target(ElementType.METHOD) // 標記該注解是添加在方法上的
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExceptionHandler {

    /**
     * 當產(chǎn)生了哪些異常,就執(zhí)行當前注解添加的方法
     */
    Class<? extends Throwable>[] value() default {};

}

? ? ? ?@ExceptionHandler用于全局處理控制器里的異常

11.10 @ControllerAdvice昵骤、@RestControllerAdvice

@Target(ElementType.TYPE) // 該注解是添加在類上的
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {

    /**
     * 指定包下的控制器(Controller)
     */
    @AliasFor("basePackages")
    String[] value() default {};
    @AliasFor("value")
    String[] basePackages() default {};

    /**
     * 指定類所在的包和子包里面的控制器(Controller)
     */
    Class<?>[] basePackageClasses() default {};

    /**
     * 直接給定控制器對應的class
     */
    Class<?>[] assignableTypes() default {};

    /**
     * 添加了指定注解的控制器(Controller)
     */
    Class<? extends Annotation>[] annotations() default {};

}

? ? ? ?@ControllerAdvice(@RestControllerAdvice)树碱,Controller增強器”淝兀可以將對于控制器的全局配置(@ExceptionHandler成榜、@InitBinder、@ModelAttribute)放在同一個位置(放到添加了@ControllerAdvice類中去實現(xiàn))伴栓。所有有@ControllerAdvice出現(xiàn)的地方的類的方法里面肯定被@ExceptionHandler伦连、@InitBinder、@ModelAttribute當中的一個修飾钳垮。


? ? ? ?關(guān)于Spring Boot注解的簡單介紹就這么寫,希望能幫助到大家.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末惑淳,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子饺窿,更是在濱河造成了極大的恐慌歧焦,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肚医,死亡現(xiàn)場離奇詭異绢馍,居然都是意外死亡,警方通過查閱死者的電腦和手機肠套,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門舰涌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人你稚,你說我怎么就攤上這事瓷耙≈焯桑” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵搁痛,是天一觀的道長长搀。 經(jīng)常有香客問我,道長鸡典,這世上最難降的妖魔是什么源请? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮彻况,結(jié)果婚禮上谁尸,老公的妹妹穿的比我還像新娘。我一直安慰自己疗垛,他們只是感情好症汹,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著贷腕,像睡著了一般背镇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上泽裳,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天瞒斩,我揣著相機與錄音,去河邊找鬼涮总。 笑死胸囱,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的瀑梗。 我是一名探鬼主播烹笔,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼抛丽!你這毒婦竟也來了谤职?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤亿鲜,失蹤者是張志新(化名)和其女友劉穎允蜈,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蒿柳,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡饶套,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了垒探。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妓蛮。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖圾叼,靈堂內(nèi)的尸體忽然破棺而出蛤克,到底是詐尸還是另有隱情扔仓,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布咖耘,位于F島的核電站,受9級特大地震影響撬码,放射性物質(zhì)發(fā)生泄漏儿倒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一呜笑、第九天 我趴在偏房一處隱蔽的房頂上張望夫否。 院中可真熱鬧,春花似錦叫胁、人聲如沸凰慈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽微谓。三九已至,卻和暖如春输钩,著一層夾襖步出監(jiān)牢的瞬間豺型,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工买乃, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留姻氨,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓剪验,卻偏偏與公主長得像肴焊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子功戚,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

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