1、@Validated @RequestBody 配合使用

@Validated 和 @RequestBody 都是 Spring Boot 中用于在请求中验证数据的注解。但是,它们的作用和使用方式略有不同。

@Validated 用于在方法参数、URL、请求体、Map中的数据上进行验证,确保数据的有效性。它会在验证失败时抛出异常,并且在验证成功时返回验证结果。

@RequestBody 用于在请求体中传递数据,Spring Boot 会在请求体中查找 @RequestBody 注解标记的参数,并将其转换为 Java 对象。在转换过程中,Spring Boot 会对参数进行验证,确保参数的有效性。

因此,通常情况下,我们会将 @Validated 和 @RequestBody 结合使用,以确保请求体中的数据和参数都是有效的。
eg:
在这里插入图片描述
在这里插入图片描述
.

2、@RequiredArgsConstructor

@RequiredArgsConstructor:作用于类,用于生成包含 final 和 @NonNull 注解的成员变量的构造方法

属性介绍:

  • staticName:使生成的构造方法是私有的
    并且生成一个参数为 final 变量和 @NonNull 注解变量,返回类型为当前对象的静态方法,方法名为 staticName 值。
  • access:设置构造方法的访问修饰符,如果设置了 staticName,那么将设置静态工厂方法的访问修饰符
    共有 PUBLIC、MODULE、PROTECTED、PACKAGE、PRIVATE、NONE。
    MODULE 是 Java 9 的新特性,NONE 表示不生成构造方法也不生成静态方法,即停用注解功能。
  • onConstructor:列出的所有注解都放在生成的构造方法上。
    JDK 7 之前的写法是 onConstructor = @__({@Deprecated}),而 JDK 8 之后的写法是 onConstructor_ = {@Deprecated}

eg:

@RequiredArgsConstructor(staticName = "newInstance", access = AccessLevel.PROTECTED, onConstructor_ = {@Deprecated})
public class ChengXiao {
	private String name;
	
	private final int age;
	
	@NonNull
	private String phone;
}

编译后:

public class ChengXiao {
	private String name;
	
	private final int age;
	
  	@NonNull
  	private String phone;
	
  	@Deprecated
  	private ChengXiao(int age, @NonNull String phone) {
    	if (phone == null)
    		throw new NullPointerException("phone is marked non-null but is null");
    	this.age = age;
    	this.phone = phone;
    }
    
  	protected static ChengXiao newInstance(int age, @NonNull String phone) {
  		return new ChengXiao(age, phone);
  	}
}

当类中没有 final 和 @NonNull 注解的成员变量时会生成一个无参构造方法(因为没有符合要求的参数)
.

3、@ConfigurationProperties

使用@ConfigurationProperties和@Component注解到bean定义类上,这里@Component代指同一类实例化Bean的注解。
eg:

// 将类定义为一个bean的注解,比如 @Component,@Service,@Controller,@Repository
// 或者 @Configuration
@Component
// 表示使用配置文件中前缀为user1的属性的值初始化该bean定义产生的的bean实例的同名属性
// 在使用时这个定义产生的bean时,其属性name会是Tom
@ConfigurationProperties(prefix = "user1")
public class User {
	private String name;
	// 省略getter/setter方法
}

对应application.properties配置文件内容如下:

user1.name=Tom

在此种场景下,当Bean被实例化时,@ConfigurationProperties会将对应前缀的后面的属性与Bean对象的属性匹配。符合条件则进行赋值。
详细见@ConfigurationProperties的三种使用场景
.

Spring @Configuration proxyBeanMethods=?

1、proxyBeanMethods=true,Full 全模式,如不指定则默认为 true,@Bean 修饰的方法会被代理。

2、proxyBeanMethods=false,Lite 轻量级模式,@Bean 修饰的方法不会被代理
.

4、Supplier<T> 接口

Supplier表示结果的提供者,不接受输入参数,只返回结果,是JDK 1.8 新增加的函数式接口

Supplier接口非常简单,只有一个get方法,只要实现这个接口的类都可以成为提供者。

@FunctionalInterface
public interface Supplier<T> {
 
    T get();
}

详细见JAVA8 Supplier<T> 接口
【Java 8 新特性】Java BooleanSupplier
.

5、自定义注解—元注解

5.1 运行时注解(RetentionPolicy.RUNTIME)

注解按生命周期来划分可分为3类:

  • 1、RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;
  • 2、RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;
  • 3、RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
    这3个生命周期分别对应于:Java源文件(.java文件) —> .class文件 —> 内存中的字节码

5.2 @Target

@Target用来表示注解作用范围,超过这个作用范围,编译的时候就会报错。

  • @Target:注解的作用目标
  • @Target(ElementType.TYPE)——接口、类、枚举、注解
  • @Target(ElementType.FIELD)——字段、枚举的常量
  • @Target(ElementType.METHOD)——方法
  • @Target(ElementType.PARAMETER)——方法参数
  • @Target(ElementType.CONSTRUCTOR) ——构造函数
  • @Target(ElementType.LOCAL_VARIABLE)——局部变量
  • @Target(ElementType.ANNOTATION_TYPE)——注解
  • @Target(ElementType.PACKAGE)——包,用于记录java文件的package信息

eg:

// 适用类、接口(包括注解类型)或枚举
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ClassInfo {
    String value();
}
// 适用field属性,也包括enum常量
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldInfo {
    int[] value();
}
// 适用方法
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MethodInfo {
    String name() default "long";
    String data();
    int age() default 27;
}

5.3 @Documented

@Documented是元注解,可以修饰其他注解。

作用:如果一个注解@B,被@Documented标注,那么被@B修饰的类,生成文档时,会显示@B。如果@B没有被@Documented标准,最终生成的文档中就不会显示@B。

5.4 @Inherited

被 @Inherited 注解修饰的注解,如果作用于某个类上,其子类是可以继承的该注解的。反之,如果一个注解没有被 @Inherited注解所修饰,那么他的作用范围只能是当前类,其子类是不能被继承的。

详细见元注解@Target、@Retention、@Documented、@Inherited的用法

5.5 @JacksonAnnotationsInside

@JacksonAnnotationsInside注解的作用是将自定义的注解标记在Jackson注解的内部,以便在序列化或反序列化时能够正确处理这些注解。

在使用Jackson进行序列化或反序列化时,Jackson会根据注解的定义来处理对象的属性或字段。如果自定义注解也被用于属性或字段上,则需要使用@JacksonAnnotationsInside注解将其标记为Jackson注解的内部,以确保Jackson能够正确地处理它们。

在自定义注解上添加 @JacksonAnnotationInside 注解,这样Jackson会把被@JacksonAnnotation标注的注解作为一个组合注解,并扫描该注解上的注解,这样我们在该注解上的Jackson相关的注解就会起作用。
eg:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JsonIgnore
@JacksonAnnotationsInside  // 标注为组合注解
public @interface CustomAnnotation {
}

5.6 @JsonSerialize

@JsonSerialize注解是Jackson库中的一个注解,它用于指定序列化和反序列化时使用的转换器。
一般适用于创建一个数据脱敏注解
步骤:

5.6.1 自定义一个Jackson注解

需要自定义一个脱敏注解,一旦有属性被标注,则进行对应得脱敏:

/**
 * 自定义jackson注解,标注在属性上
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveJsonSerializer.class)
public @interface Sensitive {
    //脱敏策略
    SensitiveStrategy strategy();
}

5.6.2 定制脱敏策略

针对项目需求,定制不同字段的脱敏规则,比如手机号中间几位用*替代:

/**
 * 脱敏策略,枚举类,针对不同的数据定制特定的策略
 */
public enum SensitiveStrategy {
    /**
     * 用户名
     */
    USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),
    /**
     * 身份证
     */
    ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1****$2")),
    /**
     * 手机号
     */
    PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),
    /**
     * 地址
     */
    ADDRESS(s -> s.replaceAll("(\\S{3})\\S{2}(\\S*)\\S{2}", "$1****$2****"));
 
 
    private final Function<String, String> desensitizer;
 
    SensitiveStrategy(Function<String, String> desensitizer) {
        this.desensitizer = desensitizer;
    }
 
    public Function<String, String> desensitizer() {
        return desensitizer;
    }
}

5.6.3 定制JSON序列化实现

下面将是重要实现,对标注注解@Sensitive的字段进行脱敏:

/**
 * 序列化注解自定义实现
 * JsonSerializer<String>:指定String 类型,serialize()方法用于将修改后的数据载入
 */
public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {
    private SensitiveStrategy strategy;
 
    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeString(strategy.desensitizer().apply(value));
    }
 
    /**
     * 获取属性上的注解属性
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
 
        Sensitive annotation = property.getAnnotation(Sensitive.class);
        if (Objects.nonNull(annotation)&&Objects.equals(String.class, property.getType().getRawClass())) {
            this.strategy = annotation.strategy();
            return this;
        }
        return prov.findValueSerializer(property.getType(), property);
 
    }
}

5.6.4 定义Person类,对其数据脱敏

使用注解@Sensitive注解进行数据脱敏:

@Data
public class Person {
    /**
     * 真实姓名
     */
    @Sensitive(strategy = SensitiveStrategy.USERNAME)
    private String realName;
    /**
     * 地址
     */
    @Sensitive(strategy = SensitiveStrategy.ADDRESS)
    private String address;
    /**
     * 电话号码
     */
    @Sensitive(strategy = SensitiveStrategy.PHONE)
    private String phoneNumber;
    /**
     * 身份证号码
     */
    @Sensitive(strategy = SensitiveStrategy.ID_CARD)
    private String idCard;
}

5.6.5 模拟接口测试

以上4个步骤完成了数据脱敏的Jackson注解,下面写个controller进行测试:

@RestController
public class TestController {
    @GetMapping("/test")
    public Person test(){
        Person user = new Person();
        user.setRealName("不才陈某");
        user.setPhoneNumber("19796328206");
        user.setAddress("浙江省杭州市....");
        user.setIdCard("4333333333334334333");
        return user;
    }
}

5.7 @JacksonStdImpl

@JacksonStdImpl注解是Jackson库中的一个注解,它用于指定使用标准Java序列化机制(即Java默认的序列化机制)进行序列化和反序列化操作。

当我们使用Jackson库进行序列化和反序列化时,默认情况下,Jackson库会使用自己的序列化机制。但是,如果我们希望使用Java默认的序列化机制,可以使用@JacksonStdImpl注解来指定。

使用@JacksonStdImpl注解的好处在于,它可以避免Jackson库的序列化和反序列化机制与Java默认的序列化机制冲突,从而提高程序的稳定性和可靠性。
.

6、@AutoConfiguration

@AutoConfiguration是Spring Boot中的一个注解,它的作用是启用Spring Boot的自动配置机制。

Spring Boot的自动配置机制是一种快速开发的方式,它可以自动为我们配置各种常用的功能,比如数据库连接、消息队列、缓存等。使用@AutoConfiguration注解可以让Spring Boot自动为我们配置这些功能,从而大大提高了开发效率。

详细见Autoconfiguration详解
.

7、@EnableAspectJAutoProxy(exposeProxy = true)

@EnableAspectJAutoProxy是Spring AOP框架中的一个注解,它的作用是启用Spring AOP框架的自动代理功能。

在Spring AOP中,我们可以使用注解来声明切面,并使用代理对象来实现切面的功能。但是,如果我们想要使用Spring AOP框架的自动代理功能,就需要在配置类上添加@EnableAspectJAutoProxy注解。

  • @EnableAspectJAutoProxy的exposeProxy设为true,是暴露代理对象的意思,也就是可以通过设置这个属性,用AopContext.currentProxy()的方式获取到当前的代理对象,可以解决同一类中两个方法相互调用是aop不生效的问题

  • @EnableAspectJAutoProxy的proxyTargetClass=true的作用是要生成代理对象时强制使用CGLIB的方式。

eg:

/**
 * 程序注解配置
 */
@AutoConfiguration
// 表示通过aop框架暴露该代理对象,AopContext能够访问
@EnableAspectJAutoProxy(exposeProxy = true)
public class ApplicationConfig {

}

.

8、@EnableAsync(proxyTargetClass = true)

使用@EnableAsync即可使用异步方法执行功能,使用@Async即可开启一个线程任务。

@EnableAsync(proxyTargetClass=true)用于开启对异步任务的支持,proxyTargetClass属性值决定是基于接口的还是基于类的代理被创建,如果是true,那么基于类的代理将起作用(这时需要cglib库),如果是fasle,那么标准的JDK 基于接口的代理,这个值默认为false。

详细见Spring异步线程池配置与使用
.

异步注解@Async:@Async的作用就是异步处理任务。

  • 在方法上添加@Async,表示此方法是异步方法;
  • 在类上添加@Async,表示类中的所有方法都是异步方法;
  • 使用此注解的类,必须是Spring管理的类;
  • 需要在启动类或配置类中加入@EnableAsync注解,@Async才会生效

详细见异步注解@Async详解
.

9、@Deprecated

  • @Deprecated: 用于表示某个程序元素(类,方法等)已过时
  • 如果使用 Deprecated 去修饰一个类,表示这个类已经过时了,但过时不代表不能用了,即不推荐使用,仍然可以使用。但以后此类或方法都不会再更新、后期可能会删除,建议后来人不要调用此方法。
  • @Deprecated的作用可以做到新旧版本的兼容和过渡
  • 此注解可用于类上、方法上、属性上。
    详细见Deprecated 注解

.

10、@NestedConfigurationProperty

@NestedConfigurationProperty :嵌套配置属性

  • 当配置类的数据结构比较复杂时,比如说一层嵌套一层,或者有List,Map这种结构的
  • 如果在绑定属性文件的类中 的属性是外部的类(不是在本类中), 那么就可以使用这个嵌套属性类解决

详细见@NestedConfigurationProperty的作用
.

11、@EnableConfigurationProperties

@EnableConfigurationProperties的作用:是将让使用了 @ConfigurationProperties 注解的配置类生效,将该类注入到 IOC 容器中,交由 IOC 容器进行管理,此时则不用再配置类上加上@Component。

详细见@EnableConfigurationProperties的使用方式以及作用
.

12、@ConditionalOnProperty

@ConditionalOnProperty该注解的作用是可以通过配置文件中的属性值来判定configuration是否被注入,这样就可以灵活的配置组件的启用。

详细见详解Springboot@ConditionalOnProperty注解
@ConditionalOnProperty的用法
.

13、@ConditionalOnMissingBean

@ConditionalOnMissingBean注解作用在@bean定义上,它的作用就是在容器加载它作用的bean时,检查容器中是否存在目标类型(ConditionalOnMissingBean注解的value值)的bean了,如果存在这跳过原始bean的BeanDefinition加载动作

@ConditionalOnMissingBean,它是修饰bean的一个注解,主要实现的是,当你的bean被注册之后,如果而注册相同类型的bean,就不会成功,它会保证你的bean只有一个,即你的实例只有一个,当你注册多个相同的bean时,会出现异常,以此来告诉开发人员

@ConditionalOnMissingBean // 当给定的在bean不存在时,则实例化当前Bean,感觉这个是在多态环境下使用,当一个接口有多个实现类时,如果只希望它有一个实现类,那就在各个实现类上加上这个注解

详细见ConditionalOnBean、ConditionalOnMissingBean注解
.

14、@Activate

@Activate称为自动激活扩展点注解,主要使用在有多个扩展点实现、需要同时根据不同条件被激活的场景中,如Filter需要多个同时激活,因为每个Filter实现的是不同的功能。

在这里插入图片描述
eg:

@Activate(group = {CONSUMER, PROVIDER}, value = CACHE_KEY)
public class CacheFilter implements Filter {
    ......
}

group = {CONSUMER, PROVIDER} 表示客户端和和服务端都会加载,value表示url中有CACHE_KEY的时候对扩展点激活。

详细见Dubbo扩展点注解之@Activate,常用于dubbo日志过滤器
.

15、@RefreshScope

SpringCloud新增了一个自定义的作用域:refresh(可以理解为“动态刷新”),同样用了一种独特的方式改变了Bean的管理方式,使得其可以通过外部化配置(.properties)的刷新,在应用不需要重启的情况下热加载新的外部化配置的值。

使用 @RefreshScope 注解的 bean,不仅会生成一个beanName的bean,默认情况下同时会生成 scopedTarget.beanName的 bean。

详细见SpringCloud配置动态刷新@RefreshScope注解
.

16、Mybatis拦截器注解@Intercepts与@Signature注解

@Signature 注解参数说明:

  • type:就是指定拦截器类型(ParameterHandler ,StatementHandler,ResultSetHandler )
  • method:是拦截器类型中的方法,不是自己写的方法
  • args:是method中方法的入参

eg:
在这里插入图片描述
在这里插入图片描述

详细见Mybatis拦截器注解@Intercepts与@Signature注解属性说明
.

17、@SneakyThrows

@SneakyThrows的作用:
普通Exception类,也就是我们常说的受检异常或者Checked Exception会强制要求抛出它的方法声明throws,调用者必须显示的去处理这个异常。设计的目的是为了提醒开发者处理一些场景中必然可能存在的异常情况。比如网络异常造成IOException。

但是现实大部分情况下的异常,我们都是一路往外抛了事。所以渐渐的java程序员处理Exception的常见手段就是外面包一层RuntimeException,接着往上丢

try{
}catch(Exception e){
throw new RuntimeException(e);
}

而Lombok的@SneakyThrows就是为了消除这样的模板代码。
使用注解后不需要担心Exception的处理


 import lombok.SneakyThrows;

public class SneakyThrowsExample implements Runnable {
  @SneakyThrows(UnsupportedEncodingException.class)
  public String utf8ToString(byte[] bytes) {
    return new String(bytes, "UTF-8");
  }
  
  @SneakyThrows
  public void run() {
    throw new Throwable();
  }
}

起通过编译器生成真正的代码:

import lombok.Lombok;

public class SneakyThrowsExample implements Runnable {
  public String utf8ToString(byte[] bytes) {
    try {
      return new String(bytes, "UTF-8");
    } catch (UnsupportedEncodingException e) {
      throw Lombok.sneakyThrow(e);
    }
  }
  
  public void run() {
    try {
      throw new Throwable();
    } catch (Throwable t) {
      throw Lombok.sneakyThrow(t);
    }
  }
}

.

18、XXL-JOB

XXL-JOB是一个分布式任务调度平台,做定时任务
详细见XXL-JOB详解
.

19、@LoadBalancerClients-----Spring Cloud LoadBalancer指定负载均衡策略

@LoadBalancerClients是阿里巴巴Java开发框架Dubbo的一个注解,它的作用是用于指定Dubbo服务调用的客户端。

在Dubbo中,我们可以使用@LoadBalancerClients注解来指定Dubbo服务调用的客户端。当我们使用Dubbo服务时,Dubbo会根据@LoadBalancerClients注解来选择合适的客户端来进行服务调用。

eg:

@LoadBalancerClients(defaultConfiguration = CustomLoadBalanceClientConfiguration.class)
public interface MyService {
    // 服务方法
}

在上面的示例中,我们使用了@LoadBalancerClients注解来指定Dubbo服务调用的客户端,并将defaultConfiguration属性设置为CustomLoadBalanceClientConfiguration.class。这意味着如果没有指定@LoadBalancerClients注解,Dubbo会使用CustomLoadBalanceClientConfiguration.class来作为默认的客户端配置

详细见[Spring Cloud LoadBalancer–指定负载均衡策略–方法/实例](https://blog.csdn.net/feiying0canglang/article/details/126823676?ops_request_misc=&request_id=&biz_id=102&utm_term=@LoadBalancerClients(defaultCo&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-1-126823676.142v92control&spm=1018.2226.3001.4187)
.

20、@EventListener

@EventListener是spring中用于声明监听器的注解,spring声明监听器有两种方式:

  • 1.实现ApplicationListener接口
  • 2.使用@EventListener声明在某个方法上。

比如我们做一个电商系统,用户下单支付成功后,我们一般要发短信或者邮箱给用户提示什么的,这时候就可以把这个通知业务做成一个单独事件监听,等待通知就可以了;把它解耦处理。

详细见@EventListener注解使用及源码解析
.

Logo

快速构建 Web 应用程序

更多推荐