当前位置:首页 > 科技  > 软件

SpringBoot一个非常强大的数据绑定类

来源: 责编: 时间:2024-05-09 09:25:56 327观看
导读环境:SpringBoot3.2.51. 简介本篇文章将介绍Spring Boot中一个非常强大且十分重要的类Binder,该类可以将外部配置文件的属性值绑定到Spring Boot应用程序中的Java对象上。在Spring Boot中,通常使用@ConfigurationPropert

环境:SpringBoot3.2.5n8b28资讯网——每日最新资讯28at.com

1. 简介

本篇文章将介绍Spring Boot中一个非常强大且十分重要的类Binder,该类可以将外部配置文件的属性值绑定到Spring Boot应用程序中的Java对象上。在Spring Boot中,通常使用@ConfigurationProperties注解来指定外部配置文件中的属性前缀,并使用Binder的bind方法将配置值绑定到Java对象上。这样,Spring Boot应用程序可以方便地读取和使用配置文件中的属性配置。n8b28资讯网——每日最新资讯28at.com

2. 实战案例

2.1 准备绑定对象

public class Person {  private Integer age ;  private String name ;  // getter, setter}

配置文件中添加配置属性n8b28资讯网——每日最新资讯28at.com

pack:  person:   age: 20   name: 张三

测试绑定组件n8b28资讯网——每日最新资讯28at.com

@Componentpublic class BinderComponent implements InitializingBean {  private final Environment env ;  // 注入该对象是为了后面我们方便注册自定义数据类型转换  private final ConversionService conviersionService ;  public BinderComponent(Environment env,     ConversionService conviersionService) {    this.env = env ;    this.conviersionService = conviersionService ;  }  public void afterPropertiesSet() throws Exception {    // 绑定测试都将在这里完成  }}

后续案例都将基于上面的环境n8b28资讯网——每日最新资讯28at.com

2.2 基础绑定

// 这里的pack.person是配置文件中的前缀BindResult<Person> result = Binder.get(env).bind("pack.person", Person.class) ;Person person = result.get() ;System.out.println(person) ;

在该示例中,配置文件中的age属性能正确的转换为Integer。为什么能进行数据类型转换?因为内部(调用Binder#get(env)时)会添加TypeConverterConversionService和ApplicationConversionService两个类型转换器。n8b28资讯网——每日最新资讯28at.com

2.3 自定义数据类型转换

给Person添加Date类型的字段,如下:n8b28资讯网——每日最新资讯28at.com

public class Person {  private Integer age ;  private String name ;  private Date birthday ;  // getter, setter}// 配置文件中添加birthday属性pack:  person:    birthday: 2000-01-01

在此执行上面2.2中代码,程序抛出了如下异常n8b28资讯网——每日最新资讯28at.com

图片图片n8b28资讯网——每日最新资讯28at.com

默认的数据类型转换器是没有String到Date转换功能。我们需要添加自定义的类型转换,如下自定义类型转换器:n8b28资讯网——每日最新资讯28at.com

@Configurationpublic class DataTypeConvertConfig implements WebMvcConfigurer {  @Override  public void addFormatters(FormatterRegistry registry) {    registry.addConverter(new Converter<String, Date>() {      @Override      public Date convert(String source) {        try {          return new SimpleDateFormat("yyyy-MM-dd").parse(source) ;        } catch (ParseException e) {          throw new RuntimeException(e) ;        }      }    });  }}

修改数据绑定方式n8b28资讯网——每日最新资讯28at.com

Iterable<ConfigurationPropertySource> propertySources = ConfigurationPropertySources.get(env) ;// 不使用默认的类型转换服务,使用自定义(还是自动配置的,只是添加了我们自定义的)Binder binder = new Binder(propertySources, null, conviersionService) ;Person result = binder.bindOrCreate("pack.person", Person.class) ;System.out.println(result) ;

这次成功输出结果。n8b28资讯网——每日最新资讯28at.com

图片n8b28资讯网——每日最新资讯28at.com

2.4 数据绑定回调

我们还可以为Binder执行绑定时,传入回调句柄,这样在数据绑定的各个阶段都可以进行相应的处理,如下示例:n8b28资讯网——每日最新资讯28at.com

Iterable<ConfigurationPropertySource> propertySources = ConfigurationPropertySources.get(env) ;Binder binder = new Binder(propertySources, null, conviersionService) ;Person result = binder.bindOrCreate("pack.person", Bindable.of(Person.class), new BindHandler() {  @Override  public <T> Bindable<T> onStart(ConfigurationPropertyName name, Bindable<T> target, BindContext context) {    System.out.printf("准备进行数据绑定:【%s】%n", name) ;    return target ;  }  @Override  public Object onSuccess(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Object result) {    System.out.printf("对象绑定成功:【%s】%n", result) ;    return result ;  }  @Override  public Object onCreate(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Object result) {    System.out.printf("准备创建绑定对象:【%s】%n", result) ;    return result ;  }  @Override  public Object onFailure(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Exception error)      throws Exception {    System.out.printf("数据绑定失败:【%s】%n", error.getMessage()) ;    return BindHandler.super.onFailure(name, target, context, error);  }  @Override  public void onFinish(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Object result)      throws Exception {    System.out.printf("数据绑定完成:【%s】%n", result) ;    BindHandler.super.onFinish(name, target, context, result) ;  }}) ;System.out.println(result) ;

输出结果n8b28资讯网——每日最新资讯28at.com

图片图片n8b28资讯网——每日最新资讯28at.com

每个属性在绑定时都会执行相应的回调方法。n8b28资讯网——每日最新资讯28at.com

3. 都用在哪里?

在SpringBoot环境中所有的数据绑定功能都是通过Binder进行。下面列出几个非常重要的地方n8b28资讯网——每日最新资讯28at.com

3.1 SpringBoot启动时绑定SpringApplication

SpringBoot在启动时初始化环境配置Environment时,会将配置文件中的spring.main.*下的配置属性绑定到当前的SpringApplication对象上。n8b28资讯网——每日最新资讯28at.com

public class SpringApplication {  public ConfigurableApplicationContext run(String... args) {    ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);  }  private ConfigurableEnvironment prepareEnvironment(...) {    // ...    bindToSpringApplication(environment);      }    protected void bindToSpringApplication(ConfigurableEnvironment environment) {    try {      Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));    }  }}

spring.main有如下配置:n8b28资讯网——每日最新资讯28at.com

图片图片n8b28资讯网——每日最新资讯28at.com

3.2 绑定使用@ConfigurationProperties类

@ConfigurationProperties注解的类是通过BeanPostProcessor处理器执行绑定(不管是类上使用该注解,还是@Bean注解的方法都是通过该处理器进行绑定)。n8b28资讯网——每日最新资讯28at.com

public class ConfigurationPropertiesBindingPostProcessor {  // 该类是由SpringBoot自动配置  private ConfigurationPropertiesBinder binder;  // 实例化bean,执行初始化方法之前  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {    // 绑定;    bind(ConfigurationPropertiesBean.get(this.applicationContext, bean, beanName));    return bean;  }}

上面的ConfigurationPropertiesBean.get方法会处理当前bean实例是独立的一个Bean对象且类上有@ConfigurationProperties注解,或者是当前的bean实例是通过@Bean定义且方法上有@ConfigurationProperties注解。不管是哪种定义的bean只要满足条件,都会被包装成ConfigurationPropertiesBean对象。接下来执行bind方法:n8b28资讯网——每日最新资讯28at.com

private void bind(ConfigurationPropertiesBean bean) {  try {    this.binder.bind(bean);  }}

执行绑定n8b28资讯网——每日最新资讯28at.com

class ConfigurationPropertiesBinder {  BindResult<?> bind(ConfigurationPropertiesBean propertiesBean) {    Bindable<?> target = propertiesBean.asBindTarget();    ConfigurationProperties annotation = propertiesBean.getAnnotation();    BindHandler bindHandler = getBindHandler(target, annotation);    return getBinder().bind(annotation.prefix(), target, bindHandler);  }}

以上就是@ConfigurationProperties注解的类或方法对象通过Binder绑定的原理。n8b28资讯网——每日最新资讯28at.com

3.3 SpringCloud Gateway绑定路由谓词&过滤器n8b28资讯网——每日最新资讯28at.com

当一个路由请求过来时,会查询相应的路由,而这个查找过程中就会通过路由的定义信息转换为Route对象。以下是大致过程(详细还需要自行阅读源码)n8b28资讯网——每日最新资讯28at.com

public class RoutePredicateHandlerMapping {  protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {    return lookupRoute(exchange)... ;  }  protected Mono<Route> lookupRoute(...) {    // 查找路由    return this.routeLocator.getRoutes()... ;  }}public class RouteDefinitionRouteLocator {  public Flux<Route> getRoutes() {    // 将在yaml配置中定义的路由转换为Route对象    Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions().map(this::convertToRoute);  }  private Route convertToRoute(RouteDefinition routeDefinition) {    AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);    // 获取配置过滤器    List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);    return ... ;  }  private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {    List<GatewayFilter> filters = new ArrayList<>();    if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {      // loadGatewayFilters方法中进行配置的绑定      filters.addAll(loadGatewayFilters(routeDefinition.getId(),          new ArrayList<>(this.gatewayProperties.getDefaultFilters())));    }  }  List<GatewayFilter> loadGatewayFilters(...) {    Object configuration = this.configurationService.with(factory)      ...      // 该方法执行绑定动作      .bind();  }  public T bind() {    T bound = doBind();  }  protected T doBind() {    Bindable<T> bindable = Bindable.of(this.configurable.getConfigClass());    T bound = bindOrCreate(bindable, this.normalizedProperties, this.configurable.shortcutFieldPrefix(),        /* this.name, */this.service.validator.get(), this.service.conversionService.get());    return bound;  }}

以上源码比较粗略,大家只要知道原理即可,没必要任何一个点都搞的清清楚楚。n8b28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-87490-0.htmlSpringBoot一个非常强大的数据绑定类

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 使用Ollama和Go基于文本嵌入模型实现文本向量化

下一篇: RabbitMQ如何保证消息可靠性?

标签:
  • 热门焦点
  • MIX Fold3包装盒泄露 新机本月登场

    小米的全新折叠屏旗舰MIX Fold3将于本月发布,近日该机的真机包装盒在网上泄露。从图上来看,新的MIX Fold3包装盒在外观设计方面延续了之前的方案,变化不大,这也是目前小米旗舰
  • 官方承诺:K60至尊版将会首批升级MIUI 15

    全新的MIUI 15今天也有了消息,在官宣了K60至尊版将会搭载天玑9200+处理器和独显芯片X7的同时,Redmi给出了官方承诺,K60至尊重大更新首批升级,会首批推送MIUI 15。也就是说虽然
  • 小米平板5 Pro 12.4简评:多专多能 兼顾影音娱乐的大屏利器

    疫情带来了网课,网课盘活了安卓平板,安卓平板市场虽然中途停滞了几年,但好的一点就是停滞的这几年行业又有了新的发展方向,例如超窄边框、高刷新率、多摄镜头组合等,这就让安卓
  • 6月iOS设备性能榜:M2稳居榜首 A系列只能等一手3nm来救

    没有新品发布,自然iOS设备性能榜的上榜设备就没有什么更替,仅仅只有跑分变化而产生的排名变动,毕竟苹果新品的发布节奏就是这样的,一年下来也就几个移动端新品,不会像安卓厂商,一
  • JavaScript 混淆及反混淆代码工具

    介绍在我们开始学习反混淆之前,我们首先要了解一下代码混淆。如果不了解代码是如何混淆的,我们可能无法成功对代码进行反混淆,尤其是使用自定义混淆器对其进行混淆时。什么是混
  • “又被陈思诚骗了”

    作者|张思齐 出品|众面(ID:ZhongMian_ZM)如今的国产悬疑电影,成了陈思诚的天下。最近大爆电影《消失的她》票房突破30亿断层夺魁暑期档,陈思诚再度风头无两。你可以说陈思诚的
  • 华为发布HarmonyOS 4:更好玩、更流畅、更安全

    在8月4日的华为开发者大会2023(HDC.Together)大会上,HarmonyOS 4正式发布。自2019年发布以来,HarmonyOS一直以用户为中心,经历四年多的发展HarmonyOS已
  • 自研Exynos回归!三星Galaxy S24系列将提供Exynos和骁龙双版本

    年初,全新的三星Galaxy S23系列发布,包含Galaxy S23、Galaxy S23+和Galaxy S23 Ultra三个版本,全系搭载超频版骁龙8 Gen 2,虽同样采用台积电4nm工艺制
  • 英特尔Xe-HP项目终止,将专注Xe-HPC/HPG系列显卡

    据10 月 31 日消息报道,英特尔高级副总裁兼加速计算系统和图形事业部总经理 表示,Xe-HP“ Arctic Sound” 系列服务器 GPU 已经应用于 oneAPI devcloud 云服
Top