日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

2.SpringBoot学习(二)——Spring Boot ConfigurationProperties

發布時間:2023/12/8 javascript 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 2.SpringBoot学习(二)——Spring Boot ConfigurationProperties 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.簡介

1.1 概述

Annotation for externalized configuration. Add this to a class definition or a @Bean method in a @Configuration class if you want to bind and validate some external Properties (e.g. from a .properties file).

Binding is either performed by calling setters on the annotated class or, if @ConstructorBinding is in use, by binding to the constructor parameters.

Note that contrary to @Value, SpEL expressions are not evaluated since property values are externalized.

一個外部化配置的注解。如果您要綁定和驗證某些外部屬性(例如,來自.properties文件),則將其添加到類定義或 @Configuration 類中的 @Bean 方法中。

綁定可以通過在帶注釋的類上調用setter來執行,或者,如果正在使用 @ConstructorBinding,則可以通過綁定到構造函數參數來執行。

請注意,與@Value相反,由于屬性值是外部化的,因此不評估SpEL表達式。

1.2 特點

@Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ConfigurationProperties {String value() default "";String prefix() default "";boolean ignoreInvalidFields() default false;boolean ignoreUnknownFields() default true; }

1.3 對比 @Value

@Configuration@Value
功能批量注入配置文件中的屬性一個個指定
松散綁定(松散語法)支持不支持
SPEL語法不支持支持
JSR303數據校驗支持不支持
復雜類型封裝支持不支持

2.環境

  • JDK 1.8.0_201
  • Spring Boot 2.2.0.RELEASE
  • 構建工具(apache maven 3.6.3)
  • 開發工具(IntelliJ IDEA )
  • 3.代碼

    3.1 代碼結構

    3.2 maven 依賴

    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency> </dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins> </build>

    3.3 配置文件

    application.properties

    user.prop.name=zhangsan user.prop.age=20

    3.4 java代碼

    UserProperties.java

    @Component @Validated // JSR303數據校驗 @ConfigurationProperties(prefix = "user.prop") public class UserProperties {@NotBlankprivate String name;@Range(min = 1, max = 200)private Integer age;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;} }

    UserProps.java

    @Component public class UserProps {@Value("${user.prop.name}")private String name;// SPEL 表達式@Value("#{10 * 2}")private Integer age;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;} }

    UserController.java

    @RestController public class UserController {@Autowiredprivate UserProperties userProperties;@Autowiredprivate UserProps userProps;@GetMapping("/user/get/1")public String getUser1() {return userProperties.getName() + "'s age is " + userProperties.getAge();}@GetMapping("/user/get/2")public String getUser2() {return userProps.getName() + "'s age is " + userProps.getAge();} }

    3.5 git 地址

    spring-boot/spring-boot-02-config

    4.結果

    啟動 SpringBoot02ConfigApplication.main 方法,在 spring-boot-02-config.http 訪問如下兩個地址,輸出 “zhangsan’s age is 20” 表示請求成功

    5.源碼分析

    5.1 @ConfigurationProperties 原理分析

    @SpringBootApplication 注解是一個復合注解,它里面包含一個 @ConfigurationPropertiesScan,這個里面又有一個 @EnableConfigurationProperties,@ConfigurationProperties 的作用與它有關。

    @ConfigurationProperties 中通過 @Import 引入一個 EnableConfigurationPropertiesRegistrar,它里面有一個 registerBeanDefinitions 方法

    @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {registerInfrastructureBeans(registry);ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);getTypes(metadata).forEach(beanRegistrar::register); }

    registerBeanDefinitions 調用一個 registerInfrastructureBeans ,這個方法將 屬性綁定后置處理器、bean 校驗器、元數據注入到 registry 中,這里的 registry 保存了所有 bean 信息。

    static void registerInfrastructureBeans(BeanDefinitionRegistry registry) {ConfigurationPropertiesBindingPostProcessor.register(registry);ConfigurationPropertiesBeanDefinitionValidator.register(registry);ConfigurationBeanFactoryMetadata.register(registry); }

    通過查看類圖可以知道,ConfigurationPropertiesBindingPostProcessor 是 BeanPostProcessor 的一個實現類

    它在 bean 實例化的時候發生作用,BeanPostProcessor 提供了 postProcessBeforeInitialization 和

    postProcessAfterInitialization 兩個方法

    public interface BeanPostProcessor {@Nullabledefault Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Nullabledefault Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;} }

    在 ConfigurationPropertiesBindingPostProcessor 的 postProcessBeforeInitialization 方法中提供了對于屬性值的注入

    @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 屬性綁定bind(ConfigurationPropertiesBean.get(this.applicationContext, bean, beanName));return bean; }

    在 bind 方法中,通過 ConfigurationPropertiesBinder 來綁定 ConfigurationProperties 中屬性

    BindResult<?> bind(ConfigurationPropertiesBean propertiesBean) {Bindable<?> target = propertiesBean.asBindTarget();// 獲取目標 bean 上的 @ConfigurationProperties 注解ConfigurationProperties annotation = propertiesBean.getAnnotation();// 獲取 BindHandlerBindHandler bindHandler = getBindHandler(target, annotation);// 通過配置的 prefix 和 BindHandler 進行屬性綁定return getBinder().bind(annotation.prefix(), target, bindHandler); }

    到這里已經比較清晰了,后面的就是從 應用上下文中獲取屬性值,然后轉換成對應的類型,再將屬性值設置給目標對象。

    5.2 @Value 原理分析

    這個流程中,doCreateBean 前面的流程實際上是 spirng bean 的初始化流程,在初始化過程中,會對 bean 的依賴和字段進行填充;BeanPostProcessor 也是在這個階段發生作用

    for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {return;}}pvs = pvsToUse;} }

    使用注解進行 bean 注入的時候,會有一個 AutowiredAnnotationBeanPostProcessor 的處理類,它里面有一個 postProcessProperties 方法

    @Override public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);try {metadata.inject(bean, beanName, pvs);}catch (BeanCreationException ex) {throw ex;}catch (Throwable ex) {throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);}return pvs; }

    InjectionMetadata 是類的注入元數據,這里通過它來對 bean 中的屬性進行注入,它里面提供了多種注入元件,而 ConfigurationProperties 主要通過字段屬性進行注入

    AutowiredFieldElement 的 inject 方法實現如下

    @Override protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Field field = (Field) this.member;Object value;// 判斷是否已緩存,如果緩存了,直接獲取if (this.cached) {value = resolvedCachedArgument(beanName, this.cachedFieldValue);}else {// 如果沒有緩存,需要從 beanFactory 中獲取具體值,然后緩存起來DependencyDescriptor desc = new DependencyDescriptor(field, this.required);desc.setContainingClass(bean.getClass());Set<String> autowiredBeanNames = new LinkedHashSet<>(1);Assert.state(beanFactory != null, "No BeanFactory available");TypeConverter typeConverter = beanFactory.getTypeConverter();try {value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);}catch (BeansException ex) {throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);}synchronized (this) {if (!this.cached) {if (value != null || this.required) {this.cachedFieldValue = desc;registerDependentBeans(beanName, autowiredBeanNames);if (autowiredBeanNames.size() == 1) {String autowiredBeanName = autowiredBeanNames.iterator().next();if (beanFactory.containsBean(autowiredBeanName) &&beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {// 將獲取到的值緩存起來this.cachedFieldValue = new ShortcutDependencyDescriptor(desc, autowiredBeanName, field.getType());}}}else {this.cachedFieldValue = null;}// 修改標記this.cached = true;}}}if (value != null) {// 最終將獲取到的值,通過反射進行注入ReflectionUtils.makeAccessible(field);field.set(bean, value);} }

    接下來調用流程是 resolveDependency -> doResolveDependency -> resolveEmbeddedValue

    @Override @Nullable public String resolveEmbeddedValue(@Nullable String value) {if (value == null) {return null;}String result = value;for (StringValueResolver resolver : this.embeddedValueResolvers) {result = resolver.resolveStringValue(result);if (result == null) {return null;}}return result; }

    最后調用到 PropertyPlaceholderConfigurer,通過解析配置文件獲取到最終值

    @Override @Nullable public String resolveStringValue(String strVal) throws BeansException {String resolved = this.helper.replacePlaceholders(strVal, this.resolver);if (trimValues) {resolved = resolved.trim();}return (resolved.equals(nullValue) ? null : resolved); }

    6.參考

  • @ConfigurationProperties與@Value的區別
  • springboot中@Value的工作原理
  • 總結

    以上是生活随笔為你收集整理的2.SpringBoot学习(二)——Spring Boot ConfigurationProperties的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。