详细解析Java中各个注解的作用和使用方式

@Target

  • 作用: 指明了修饰的这个注解的使用范围, 即被描述的注解可以用在哪里
@Target(ElementType.Type)
  • ElementType取值的类型:
    • TYPE: 类,接口或者枚举
    • FIELD: 域,包含枚举常量
    • METHOD: 方法
    • PARAMETER: 参数
    • CONSTRUCTOR: 构造方法
    • LOCAL_VARIABLE: 局部变量
    • ANNOTATION_TYPE: 注解类型
    • PACKAGE:

@Retention

  • 作用: 指明修饰的注解的生存周期, 即会保留到哪个阶段
  • RetentionPolicy的取值类型有三种:
    • SOURCE: 源码级别保留,编译后即丢弃
    • CLASS: 编译级别保留,编译后的class文件中存在,在jvm运行时丢弃,这是默认值
    • RUNTIME: 运行级别保留,编译后的class文件中存在,在jvm运行时保留,可以被反射调用

@Documented

  • 作用: 指明修饰的注解,可以被例如javadoc此类的工具文档化
    • 只负责标记
    • 没有成员取值

@Inherited

  • 作用: 允许子类继承父类中的注解
  • @Inherited需要和@AliasFor一起使用: 在子注解对应的属性使用@AliasFor
    • 注解是可以继承的,但是注解是不能继承父注解的属性
    • 也就是说,在类扫描时的注解的属性值依然是父注解的属性值,而不是自定义注解的属性值
    • 需要在注解的属性上使用@AliasFor

@ComponentScan

  • 作用: 定义扫描的路径从中找出标识了需要装配的类自动装配到spring的bean容器中
  • 默认会扫描该类所在的包下所有的配置类
  • @ComponentScan中的参数类型:
    • value: 用于对指定包的路径进行扫描
    • basePackages: 用于指定包的路径进行扫描,用法和value一样.建议使用value
    • basePackageClasses: 用于对指定某个类的所在的包的路径进行扫描
    • nameGenerator: 用于为Spring容器中的检测到bean组件命名
    • useDefaultFilters: 是否开启对 @Component,@Repository,@Service,@Controller的类进行检测
    • excludeFilters: 按照过滤条件进行排除
      • FilterType.ANNOTATION: 按照注解
      • FilterType.ASSIGNABLE_TYPE: 按照给定的类型
      • FilterType.ASPECTJ: 使用ASPECTJ表达式
      • FilterType.REGEX: 使用正则表达式
      • FilterType.CUSTOM: 按照自定义规则
    • includeFilters: 按照过滤条件进行包含
      • FilterType.ANNOTATION: 按照注解
      • FilterType.ASSIGNABLE_TYPE: 按照给定的类型
      • FilterType.ASPECTJ: 使用ASPECTJ表达式
      • FilterType.REGEX: 使用正则表达式
      • FilterType.CUSTOM: 按照自定义规则

@Filter

  • 作用: 配置过滤条件的过滤器注解
  • @Filter中的参数类型:
    • type
    • class

@interface

  • 作用: 自定义注解
  • 自动继承java.lang.annotation.Annotation接口,由编译程序自动完成其他细节
  • 在定义注解时,不能继承其他的注解或接口
  • @interface用来声明一个注解:
    • 其中的每一个方法实际上是声明一个配置参数
    • 方法的名称就是参数的名称
    • 方法的返回值类型就是参数的类型
    • 返回值类型只能是基本类型,Class,String,enum
    • 可以通过default来声明参数的默认值
  • 定义注解的格式:
public @interface 注解名 {定义体}
  • 注解参数支持的数据类型:
    • 基本数据类型: int,float,boolean,byte,double,char,long,short
    • String类型
    • Class类型
    • enum类型
    • Annotation类型
    • 以上类型组合的数组
  • Annotation类型中参数设定规则:
    • 只能用public或default默认访问权修饰:
    • 参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和String,Enum,Class,annotations等数据类型,以及这一些类型的数组
    • 如果只有一个参数成员,最好把参数名称设为value,后加小括号
  • 注解元素的默认值:
    • 注解元素必须有确定的值
    • 要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null
    • 因此使用空字符串或0作为默认值约束
  • 这个约束使得处理器很难表现一个元素的存在或缺失的状态:
    • 因为每个注解的声明中,所有元素都存在,并且都具有相应的值
  • 为了绕开这个约束,只能定义一些特殊的值(比如空字符串或者负数),表示某个元素不存在

@AliasFor

  • 作用: 为注解的属性添加别名
  • 在同一个注解内,对两个不同的属性一起使用,互为别名:
    • 无论为哪个属性名设置属性值,另一个属性名也是同样的属性值
    • 互为别名的属性值必须相同,否则会报错
    • 属性必须要有默认的属性值
public @interface RequestMapping {
   
    @AliasFor("path")           // 此时path和value值必须是一样的,否则会报错
    String[] value() default {};

    @AliasFor("value")          // 此时path和value值必须是一样的,否则会报错
    String[] path() default {};
    
}
  • 显式的覆盖元注解中的属性:
    • 显式的为元注解的属性设置别名
    • 属性类型,属性默认值必须相同
    • @AliasFor只能为作为当前注解的元注解起别名
  • 示例:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AopConfig.class)
public class AopUtilsTest {}

要想替换 @ContextConfiguration(classes = AopConfig.class) 注解,可以这样定义一个标签:

@Retention(RetentionPolicy.RUNTIME)
@ContextConfiguration
public @interface Context {
    @AliasFor(value = "classes", annotation = ContextConfiguration.class)
    Class<?>[] cs() default {};
}
  1. 因为 @ContextConfiguration注解本身被定义为 @Inherited的,所以Context注解即可理解为继承 @ContextConfiguration注解
  2. cs属性等同于 @ContextConfiguration属性中的classes属性.使用了 @AliasFor标签,分别设置:
    1. value: 作为哪个属性的别名
    2. annotation: 作为哪个注解的别名

使用Context标签的可以达到同样效果:

@RunWith(SpringJUnit4ClassRunner.class)
@STC(cs = AopConfig.class)
public class AopUtilsTest {}
  • 在一个注解中隐式声明别名:
 @ContextConfiguration
 public @interface MyTestConfig {

    @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    String[] value() default {};

    @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    String[] groovyScripts() default {};

    @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    String[] xmlFiles() default {};
 }

这就是在统一注解中隐式声明别名:

  1. MyTestConfig注解中 ,value,groovyScripts,xmlFiles都定义为@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")的别名
  2. 在这个注解中 ,value,groovyScripts和xmlFiles也互为别名
  • 别名的传递:
    • @AliasFor注解是允许别名之间的传递的:
      • 如果A是B的别名,并且B是C的别名,那么A是C的别名
@MyTestConfig
 public @interface GroovyOrXmlTestConfig {

    @AliasFor(annotation = MyTestConfig.class, attribute = "groovyScripts")
    String[] groovy() default {};

    @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    String[] xml() default {};
 }
  1. GroovyOrXmlTestConfig@MyTestConfig作为元注解
  2. 定义了groovy属性,并作为MyTestConfig中的groovyScripts属性的别名
  3. 定义了xml属性,并作为ContextConfiguration中的locations属性的别名
  4. 因为MyTestConfig中的groovyScripts属性本身就是ContextConfiguration中的locations属性的别名,所以xml属性和groovy属性也互为别名
  • @Alias中的属性:
    • annotation: 类类型,别名属性的类的类型,即别名的属性属于哪个注解类
    • attribute: 需要别名的属性
    • value: 属性的别名

@Import

  • @Import支持导入普通的Java类,并声明为一个Bean
  • @Import使用场景:
    • @Import主要用在基于Java代码显式创建bean的过程中
    • @Import用于将多个分散的Java Config配置类融合成一个完整的config类
  • 配置类的组合主要发生在跨模块或者跨包的配置类引用过程中: 将多个按功能或者按业务划分的配置文件导入到单个配置文件中,避免将所有配置写在一个配置中
  • @Import与@ImportResource注解的作用类似
  • 使用@ImportResource和@Value可以进行资源文件的读取

SpringBoot

@SpringBootApplication

  • 包含:
    • @Configuration
    • @EnableAutoConfiguration
    • @ComponentScan
  • 通常用在主类上

@ConfigurationProperties

  • 可以使用 @ConfigurationProperties获取大量配置在application.propertiesapplication.yml中参数的参数值
  • @ConfigurationProperties的使用: 要为每个捕获的外部属性提供一个带有字段的类
    • 前缀prefix定义的相关的外部属性要绑定到类的字段上
    • 根据SpringBoot宽松的绑定规则,类属性的名称必须与外部属性名称匹配
      • 可以将类类型的bean使用@Bean注解的方法注入到另一个bean中,那么这个bean可以以类型安全的方式访问外部配置的参数值
    • 可以简单地用一个值初始化一个字段来定义一个默认值. 最好与配置文件中的值相同
    • 类本身可以是包私有的
    • 类的字段必须有公共setter方法
  • 激活@ConfigurationProperties:
    • 通过添加 @Component注解让ComponentScan扫描到
    • 只有当该类所在的包被Spring的@ComponentScan扫描到才会生效.默认情况下,该注解会扫描在主应用类下所有包结构
    @Component
    @ConfigurationProperties(prefix = "spring.logger")
    class LogProperties {
      ...
    }
    
    • 通过SpringJava Configuration特性激活@ConfigurationProperties
    • 只要MailModuleConfiguration类被SpringBoot应用扫描到,就可以在应用上下文中访问MailModuleProperties bean
    @Configuration
    class PropertiesConfig {
      @Bean 
      public LogModuleProperties logModuleProperties() {
          return new logModuleProperties();
      }
    }
    
  • 同时可以使用 @EnableConfigurationProperties注解使得SpringBoot找到这个类. 这个注解用了 @Import(EnableConfigurationPropertiesImportSelector.class) 实现
@Configuration
@EnableConfigurationProperties(LogModuleProperties.class)
class PropertiesConfig {
}

激活一个 @ConfigurationProperties类时最好模块化应用程序,并让每个模块提供自己的 @ConfigurationProperties类,只提供模块需要的属性.这样可以使得在不影响其他模块的情况下重构一个模块中的属性变得更加方便.因此不建议在程序类本身上使用 @EnableConfigurationProperties, 应该在特定模块的 @Configuration类上使用 @EnableConfigurationProperties, 该类也可以利用包私有的可见性对特定应用程序其余部分隐藏属性

  • @ConfigurationProerties中无法转换的属性:
    • 当为 @ConfigurationProperties中的属性配置错误的值时,又不希望SpringBoot应用启动失败.可以设置ignoreInvalidFields注解属性为true, 默认为false
@ConfigurationProperties(prefix = "spring.logger", ignoreInvalidFields = true)
public class LogModuleProperties {
    private Boolean enabled = Boolean.True;
}

SpringBoot将会设置enable字段为设定好的默认值. 如果没有设定默认值 ,enabled的值将为null, 因为这里定义的是boolean的包装类Boolean

  • @ConfigurationProperties中未知的属性:
    • 默认情况下,SpringBoot会忽略不能绑定到 @ConfigurationProperties类字段的属性
    • 当配置文件中又一个属性实际没有绑定到 @ConfigurationProperties类时,希望SpringBoot启动失败
    • 或者是以前使用过这个属性,但已经被删除了,希望被触发告知手动从application.properties删除这个属性
    • 这是需要设置ignoreUnknownFields注解属性为false, 默认为true
@ConfigurationProperties(prefix = "spring.logger", ignoreUnknownFields = false)
class LogModuleProperties {
    private Boolean enabled = Boolean.TRUE;
    private String defaultSubject;
}

对于ignoreUnkownFields, 在SpringBoot中可能有两个带有@ConfigurationProperties的类,同时绑定到了同一个命名空间 (namespace) 上,其中一个类可能知道某个属性,另一个类却不知道某个属性,这样会导致启动失败.所以这个属性不再使用

  • 启动时校验@ConfigurationProperties:
    • 如果希望配置参数在传入到应用中是有效的,可以通过在字段上添加bean validation注解,同时在类上添加 @Validated注解
@ConfigurationProperties(prefix = "spring.logger")
@Validated
@Data
class LogModuleProperties {
    @NotNull private Boolean enabled;
    @NotEmty private String defaultSubject;
} 

如果这些默认的验证注解不能满足验证要求的,可以自定义注解. 如果验证逻辑很特殊,可以实现一个方法,并用 @PostConstruct标记,如果验证失败,方法抛出异常即可

  • 复杂属性类型:
    • 多数情况下,传递给应用的参数是基本字符串或者数字,有时又需要传递比如List的数据类型
    • List和Set:
      • 有两种方式让SpringBoot自动填充List属性:
        • application.properties文件中以数组形式书写
        spring.logger.smtpServers[0]=server1
        spring.logger.smtpServers[1]=server1
        
        • application.yml本身支持List类型,可以在application.yml文件中添加
        spring:
          mail:
              smtpServers:
                  - server1
                  - server2
        
      • set集合也是使用同样的配置方式
    • 推荐使用YML做数据配置,能够更好的阅读,层次分明
  • Duration:
    • SpringBoot内置支持从配置参数中解析duration(持续时间):
    @Data
    @ConfigurationProperties(prefix = "spring.logger")
    class loggerModuleProperties {
      private Duration pauseBetweenLogs;
    }
    
    • 既可以配置毫秒数值,也可以配置带有单位的文本:
    spring.logger.pause-between-logs=5s
    
    • 如果配置duration没有写单位,默认按照毫秒来指定,也可以通过 @DurationUnit来指定单位:
    @Data
    @ConfigurationProperties(prefix = "spring.logger")
    class loggerModuleProperties {
      @DurationUnit(ChronoUnit.SECONDS)
      private Duration pauseBetweenLogs;
    }
    
    • 常用单位如下:
      • ns: NANOSECONDS - 纳秒
      • us: MICROSECONDS - 微秒
      • ms: MILLISECONDS - 毫秒
      • s: SECONDS - 秒
      • m: MINUTES - 分
      • h: HOURS - 时
      • d: DAYS - 天
  • DataSize:
    • 与Duration用法一样,默认单位是byte(字节) , 可以通过@DataSizeUnit单位指定
    @Data
    @ConfigurationProperties(prefix = "spring.logger")
    class loggerMailModuleProperties {
      @DataSizeUnit(DataUnit.MEGABYTES)
      private DataSize maxAttachmentSize = DataSize.ofMegebytes(2);
    } 
    
    • 添加配置:
    spring.logger.max-attachment-size=1MB
    
    输出的结果都是以B(bytes) 为单位显示的
    • 常见单位如下:
      • B: BYTES
      • KB: KILOBYTES
      • MB: MEGEBYTES
      • GB: GIGABYTES
      • TB: TERABYTES
  • 自定义类型:
    • 有时候,想解析配置参数到自定义的对象类型上,比如自定义物品重量:
    spring.logger.max-attachment-weight=5kg
    
    • MailModuleProeprties中添加Weight属性:
    @Data
    @ConfigurationProperties(prefix = "spring.logger")
    class MailModuleProperties {
      private Weight maxAttachmentWeight;
    }
    
    • 创建自定义转换器converter:
    class WeightConverter implements Convert<String, Object> {
      @Override
      public Weight convert(String source) {
          // 根据String类型的source创建并返回一个Weight类型的对象
      }
    }
    
    • 将自定义转换器converter注册到SpringBoot上下文中
    @Configuration
    class PropertiesConfig {
      @Bean
      @ConfigurationPropertiesBinding
      public WeightConverter weightConverter() {
          return new WeightConverter();
      }
    }
    
    @ConfigurationPropertiesBinding注解是让SpringBoot使用该转换器做数据绑定
  • 标记配置属性为Deprecated:
@DeprecatedConfigurationProperty(reason = "change name", replacement = "none")
public String getDefaultSubject() {
    return defaultSubject;
}

可以通过添加 @DeprecatedConfigurationProperty注解到字段的getter方法上,来标示该字段为deprecated

  • SpringBoot@ConfigurationProperties注解在绑定类型安全的Java Bean时是非常强大的
  • 可以配合其注解属性和 @DeprecatedConfigurationProperty注解让配置更加模块化
  • 如果使用SpEL表达式,只能选择 @Value注解

@Repository

  • 用于标注数据访问组件,即DAO组件

@Service

  • 用于标注业务层组件

@RestController

  • 用于标注控制层组件
  • 包含:
    • @Controller
    • @ResponseBody

@Controller

  • 用于标注控制层组件
  • 需要返回页面时要使用 @Controller而不是 @RestController

@ControllerAdvice

  • 用于定义 @ExceptionHandler, @InitBinder, @ModelAttribute, 并且应用到所有 @RequestMapping
    • @InitBinder: 在执行之前初始化数据绑定器
    • @ModelAttribute: 把值绑定到Model中,可以获取到该值
    • @ExceptionHandler: 全局异常捕捉处理

@Component

  • 泛指组件
  • 当组件无法归类时,可以使用这个注解进行标注

@ResponseBody

  • 表示该方法的返回结果直接被写入http response body
    • 一般在异步获取数据时使用
  • 在使用 @RequestMapping后,返回值通常解析为跳转路径
  • 比如:
    • 加上 @ResponseBody后返回结果不会被解析为跳转路径,而是直接写入HTTP Response Body
    • 异步获取json数据,加上 @ResponseBody后,会直接返回json数据

@RequestBody

  • 参数前加上这个注解,表示该参数必填
  • 表示接收json字符串转为对象List

@ComponentScan

  • 组件扫描
  • 扫描到有 @Component, @Cotroller, @Service等这些注解的类,就会把这些类注册为bean*

@Configuration

  • 表示该类是Bean的信息源
  • 相当于XML中的,一般标注在主类上

@ConditionOnProperty

  • 控制Configuration在条件成立时生效
  • 属性:
    • value: 数组,获取对应property的名称,与name不可以同时使用
    • prefix: property名称的前缀,可有可无
    • name: 数组 ,property完整名称或者部分名称(与prefix组合使用,组成完整的property名称),不可以与value同时使用
    • havingValue: 可与name组合使用,比较获取到的属性值与havingValue给定的值是否相同,相同才加载配置
    • matchMissing: 缺少该property时是否可以加载. 如果为true, 没有该property也会正常加载. 如果为false, 则没有该property时则会报错,默认为false
    • relaxedNames: 是否支持松散匹配

@Bean

  • 相当于XML中的,标注在方法上
  • 表示生成一个bean, 并交给Spring管理

@EnableAutoConfiguration

  • 使SpringBoot根据应用所声明的依赖来对Spring框架进行配置
  • 一般加在主类上

@Autowired

  • byType方式
  • 使用已经配置好的Bean, 完成属性,方法的组装
  • 可以对类成员,方法以及构造函数进行标注,完成自动装配的工作
  • 如果加上 @Autowired(required = false), 当找不到bean时也不会报错

@Qualifier

  • 当有多个同一类型的Bean时,可以使用 @Qualifier("name") 来指定
  • 需要和 @Autowired一起使用

@Resource

  • @Resource(name = "name", type = "type")
  • 如果没有属性的话,默认为byName,@Autowired功能类似

@RequestMapping

  • @RequestMapping是一个用来处理请求地址映射的注解,可以使用在类或者方法上
  • 用在类上时,表示类中所有响应请求的方法都以该地址作为父路径
  • @RequestMapping有六个属性:
    • params: 指定request中必须包含某些参数值,才让该方法处理请求
    • headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求
    • value: 指定请求的实际地址. 指定的地址可以是URI Template模式
    • method: 指定请求的method类型 ,GET, POST, PUT,DELETE
    • consumes: 指定处理请求的提交内容类型 - Content-Type. 比如: application,json,text,html
    • produces: 指定返回的内容类型,仅当request请求头中的 (Accept) 类型中包含该指定类型才返回

@GetMapping

  • @GetMapping, @PostMapping是组合注解
  • 相当于 @RequestMapping(value = "/", method = RequestMethod.Get(Post, Put, Delete))

@RequestParam

  • 用在方法的参数前面
  • 相当于 request.getParameter

@PathVariable

  • 路径变量: RequestMapping("user/get/mac/{macAddress}")
public String getByMacAddress(@PathVariable("macAddress") String macAddress) {}

参数与大括号里的名字相同的话,注解后括号里的内容可以不填

全局异常处理

@ControllerAdvice

  • 包含 @Component
  • 可以被扫描到
  • 统一异常处理

@ExceptionHandler

  • @Exceptionhandler(Exception.class)
    • 用在方法上面,表示遇到这个异常就执行这个方法

SpringCloud

@EnableEurekaServer

  • 用在SpringBoot启动类上
  • 表示这是一个Eureka服务注册中心

@EnableDiscoveryClient

  • 用在SpringBoot启动类上
  • 表示这是一个服务,可以被注册中心找到

@LoadBalanced

  • 开启负载均衡能力

@EnableCircuitBreaker

  • 用在SpringBoot启动类上
  • 开启断路器功能

HystrixCommand

  • @HystrixCommand(fallbackMethod = "backMethod")
  • 用在方法上,表示fallbackMethod指定断路回调方法

@EnableConfigServer

  • 用在SpringBoot启动类上
  • 表示这是一个配置中心,开启Config Server

@EnableZuulProxy

  • 用在SpringBoot启动类上
  • 表示开启zuul路由

@SpringCloudApplication

  • 微服务注解集合,包含:
    • @SpringBootApplication: SpringBoot注解
    • @EnableDiscoveryClient: 注册服务中心Eureka注解
    • @EnableCircuitBreaker: 断路器注解
  • 这是每一个微服务必须应该有的注解
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容