自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

SpringBoot一個非常強大的數(shù)據(jù)綁定類

開發(fā) 前端
本篇文章將介紹Spring Boot中一個非常強大且十分重要的類Binder,該類可以將外部配置文件的屬性值綁定到Spring Boot應用程序中的Java對象上。

環(huán)境:SpringBoot3.2.5

1. 簡介

本篇文章將介紹Spring Boot中一個非常強大且十分重要的類Binder,該類可以將外部配置文件的屬性值綁定到Spring Boot應用程序中的Java對象上。在Spring Boot中,通常使用@ConfigurationProperties注解來指定外部配置文件中的屬性前綴,并使用Binder的bind方法將配置值綁定到Java對象上。這樣,Spring Boot應用程序可以方便地讀取和使用配置文件中的屬性配置。

2. 實戰(zhàn)案例

2.1 準備綁定對象

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

配置文件中添加配置屬性

pack:
  person:
   age: 20
   name: 張三

測試綁定組件

@Component
public class BinderComponent implements InitializingBean {
  private final Environment env ;
  // 注入該對象是為了后面我們方便注冊自定義數(shù)據(jù)類型轉(zhuǎn)換
  private final ConversionService conviersionService ;
  public BinderComponent(Environment env, 
    ConversionService conviersionService) {
    this.env = env ;
    this.conviersionService = conviersionService ;
  }
  public void afterPropertiesSet() throws Exception {
    // 綁定測試都將在這里完成
  }
}

后續(xù)案例都將基于上面的環(huán)境

2.2 基礎綁定

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

在該示例中,配置文件中的age屬性能正確的轉(zhuǎn)換為Integer。為什么能進行數(shù)據(jù)類型轉(zhuǎn)換?因為內(nèi)部(調(diào)用Binder#get(env)時)會添加TypeConverterConversionService和ApplicationConversionService兩個類型轉(zhuǎn)換器。

2.3 自定義數(shù)據(jù)類型轉(zhuǎn)換

給Person添加Date類型的字段,如下:

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

在此執(zhí)行上面2.2中代碼,程序拋出了如下異常

圖片圖片

默認的數(shù)據(jù)類型轉(zhuǎn)換器是沒有String到Date轉(zhuǎn)換功能。我們需要添加自定義的類型轉(zhuǎn)換,如下自定義類型轉(zhuǎn)換器:

@Configuration
public 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) ;
        }
      }
    });
  }
}

修改數(shù)據(jù)綁定方式

Iterable<ConfigurationPropertySource> propertySources = ConfigurationPropertySources.get(env) ;
// 不使用默認的類型轉(zhuǎn)換服務,使用自定義(還是自動配置的,只是添加了我們自定義的)
Binder binder = new Binder(propertySources, null, conviersionService) ;
Person result = binder.bindOrCreate("pack.person", Person.class) ;
System.out.println(result) ;

這次成功輸出結(jié)果。

圖片

2.4 數(shù)據(jù)綁定回調(diào)

我們還可以為Binder執(zhí)行綁定時,傳入回調(diào)句柄,這樣在數(shù)據(jù)綁定的各個階段都可以進行相應的處理,如下示例:

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("準備進行數(shù)據(jù)綁定:【%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("準備創(chuàng)建綁定對象:【%s】%n", result) ;
    return result ;
  }
  @Override
  public Object onFailure(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Exception error)
      throws Exception {
    System.out.printf("數(shù)據(jù)綁定失敗:【%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("數(shù)據(jù)綁定完成:【%s】%n", result) ;
    BindHandler.super.onFinish(name, target, context, result) ;
  }
}) ;
System.out.println(result) ;

輸出結(jié)果

圖片圖片

每個屬性在綁定時都會執(zhí)行相應的回調(diào)方法。

3. 都用在哪里?

在SpringBoot環(huán)境中所有的數(shù)據(jù)綁定功能都是通過Binder進行。下面列出幾個非常重要的地方

3.1 SpringBoot啟動時綁定SpringApplication

SpringBoot在啟動時初始化環(huán)境配置Environment時,會將配置文件中的spring.main.*下的配置屬性綁定到當前的SpringApplication對象上。

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有如下配置:

圖片圖片

3.2 綁定使用@ConfigurationProperties類

@ConfigurationProperties注解的類是通過BeanPostProcessor處理器執(zhí)行綁定(不管是類上使用該注解,還是@Bean注解的方法都是通過該處理器進行綁定)。

public class ConfigurationPropertiesBindingPostProcessor {
  // 該類是由SpringBoot自動配置
  private ConfigurationPropertiesBinder binder;
  // 實例化bean,執(zhí)行初始化方法之前
  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對象。接下來執(zhí)行bind方法:

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

執(zhí)行綁定

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綁定的原理。

3.3 SpringCloud Gateway綁定路由謂詞&過濾器

當一個路由請求過來時,會查詢相應的路由,而這個查找過程中就會通過路由的定義信息轉(zhuǎn)換為Route對象。以下是大致過程(詳細還需要自行閱讀源碼)

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配置中定義的路由轉(zhuǎn)換為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)
      ...
      // 該方法執(zhí)行綁定動作
      .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;
  }
}

以上源碼比較粗略,大家只要知道原理即可,沒必要任何一個點都搞的清清楚楚。

責任編輯:武曉燕 來源: Spring全家桶實戰(zhàn)案例源碼
相關推薦

2024-02-19 08:26:59

wxPython界面庫開發(fā)

2015-03-30 12:20:07

DemoStoryboard

2023-01-08 21:05:45

數(shù)據(jù)預警模型

2014-05-23 10:37:37

聊天程序PHP聊天程序

2020-09-29 15:08:47

Go UI框架開發(fā)

2024-07-02 11:29:28

Typer庫Python命令

2022-03-03 08:02:55

數(shù)據(jù)集成平臺

2009-12-29 10:41:30

Ubuntu 9.10

2020-11-15 18:20:44

GnuCash開源會計軟

2024-04-30 08:20:54

代理工廠類Spring

2025-01-08 06:00:00

Argus開源安全檢查工具

2025-01-07 13:00:00

日志分析平臺Graylog網(wǎng)絡安全

2023-10-10 08:22:12

Tesseract庫開源

2021-03-06 07:00:00

awk文本分析工具Linux

2024-09-06 12:52:59

2023-12-16 13:22:00

JaVers控制框架

2022-06-07 10:39:57

SpringBoot

2011-03-24 09:34:41

SPRING

2013-04-23 14:32:28

創(chuàng)業(yè)創(chuàng)業(yè)者Mark Suster

2021-06-28 13:45:10

KTorrentBitTorrentLinux
點贊
收藏

51CTO技術棧公眾號