其他分享
首页 > 其他分享> > 12. spring-容器: @Value, @PropertySource详解

12. spring-容器: @Value, @PropertySource详解

作者:互联网

在使用Java config配置Bean以前,即xml配置时代,bean的属性值可以通过 <property name=“xxx” value=""/>的形式。 value既可以使用固定值,也可以使用占位符的形式${xxx}。 占位符中的配置的值由一个特殊的bean的解析(MessageSource)。

而到了java config时代,给bean属性配置值,可以使用的方式是@Value,本章就来重点讲下@Value如何使用。

@Value定义

先看源码:

package org.springframework.beans.factory.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Annotation at the field or method/constructor parameter level
 * that indicates a default value expression for the affected argument.
 *
 * <p>Typically used for expression-driven dependency injection. Also supported
 * for dynamic resolution of handler method parameters, e.g. in Spring MVC.
 *
 * <p>A common use case is to assign default field values using
 * <code>#{systemProperties.myProp}</code> style expressions.
 *
 * <p>Note that actual processing of the {@code @Value} annotation is performed
 * by a {@link org.springframework.beans.factory.config.BeanPostProcessor
 * BeanPostProcessor} which in turn means that you <em>cannot</em> use
 * {@code @Value} within
 * {@link org.springframework.beans.factory.config.BeanPostProcessor
 * BeanPostProcessor} or
 * {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessor}
 * types. Please consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}
 * class (which, by default, checks for the presence of this annotation).
 *
 * @author Juergen Hoeller
 * @since 3.0
 * @see AutowiredAnnotationBeanPostProcessor
 * @see Autowired
 * @see org.springframework.beans.factory.config.BeanExpressionResolver
 * @see org.springframework.beans.factory.support.AutowireCandidateResolver#getSuggestedValue
 */
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {

	/**
	 * The actual value expression &mdash; for example, <code>#{systemProperties.myProp}</code>.
	 */
	String value();

}

从源码注释提取一下关键信息:

@Value注解的用法

  1. 不通过配置文件将外部的值动态注入到Bean中
@Value("panda")
private String name;
@Value("#{systemProperties['os.name']}")
private String os;
@Value("#{T(java.lang.Math).random() * 100.0}")
private double randomNumber;
@Value("#{animal.name}")
private String animalName;
@Value("classpath:application.properties")
private Resource classpathResource;
@Value("https://baidu.com")
private Resource urlResource;

示例:

package win.elegentjs.spring.ioc.value;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;

/**
 * 自定义Bean class, 演示了各种通过@Value的注入场景
 * 注:不使用外部配置属性
 */
@Data
public class CustomerValue {

    @Value("panda")
    private String name;

    @Value("#{systemProperties['os.name']}")
    private String os;

    @Value("#{T(java.lang.Math).random() * 100.0}")
    private double randomNumber;

    @Value("#{animal.name}")
    private String animalName;

    @Value("classpath:application.properties")
    private Resource classpathResource;

    @Value("https://baidu.com")
    private Resource urlResource;
}

package win.elegentjs.spring.ioc.value;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * java config 配置类,定义了两个bean,animal会被customerValue依赖
 */
@Configuration
public class CustomerValueConfig {

    @Bean
   public CustomerValue customerValue() {
       return new CustomerValue();
   }

   @Bean
   public Animal animal() {
        Animal animal = new Animal();
        animal.setName("dog");
        return animal;
   }
}

package win.elegentjs.spring.ioc.value;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

@Slf4j
public class CustomerValueSample {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(CustomerValueConfig.class);

        CustomerValue customerValue = context.getBean(CustomerValue.class);

        log.info("==> customerValue: {}", customerValue);

    }
}


// result:
2021-05-31 19:36:06.919 [main] INFO  win.elegentjs.spring.ioc.value.CustomerValueSample-==> customerValue: CustomerValue(name=panda, os=Mac OS X, randomNumber=54.4727006010814, animalName=dog, classpathResource=class path resource [application.properties], urlResource=URL [https://baidu.com])


  1. 通过配置文件注入属性

先通过@PropertySource指定属性配置文件源,@PropertySource源码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(PropertySources.class)
public @interface PropertySource {

	/**
	 * Indicate the name of this property source. If omitted, a name will
	 * be generated based on the description of the underlying resource.
	 * @see org.springframework.core.env.PropertySource#getName()
	 * @see org.springframework.core.io.Resource#getDescription()
	 */
	String name() default "";

	/**
	 * Indicate the resource location(s) of the properties file to be loaded.
	 * <p>Both traditional and XML-based properties file formats are supported
	 * &mdash; for example, {@code "classpath:/com/myco/app.properties"}
	 * or {@code "file:/path/to/file.xml"}.
	 * <p>Resource location wildcards (e.g. *&#42;/*.properties) are not permitted;
	 * each location must evaluate to exactly one {@code .properties} resource.
	 * <p>${...} placeholders will be resolved against any/all property sources already
	 * registered with the {@code Environment}. See {@linkplain PropertySource above}
	 * for examples.
	 * <p>Each location will be added to the enclosing {@code Environment} as its own
	 * property source, and in the order declared.
	 */
	String[] value();

	/**
	 * Indicate if failure to find the a {@link #value() property resource} should be
	 * ignored.
	 * <p>{@code true} is appropriate if the properties file is completely optional.
	 * Default is {@code false}.
	 * @since 4.0
	 */
	boolean ignoreResourceNotFound() default false;

	/**
	 * A specific character encoding for the given resources, e.g. "UTF-8".
	 * @since 4.3
	 */
	String encoding() default "";

	/**
	 * Specify a custom {@link PropertySourceFactory}, if any.
	 * <p>By default, a default factory for standard resource files will be used.
	 * @since 4.3
	 * @see org.springframework.core.io.support.DefaultPropertySourceFactory
	 * @see org.springframework.core.io.support.ResourcePropertySource
	 */
	Class<? extends PropertySourceFactory> factory() default PropertySourceFactory.class;

}

原始的源码注释很长,这里没有贴出来,感兴趣的自己去看一下,总结一下有用信息如下:

 @Configuration
 @PropertySource("classpath:/com/myco/app.properties")
 public class AppConfig {

     @Autowired
     private Environment env;

     @Bean
     public TestBean testBean() {
         TestBean testBean = new TestBean();
         testBean.setName(env.getProperty("testbean.name"));
         return testBean;
     }
 }
@Configuration
@PropertySource("classpath:/com/myco/app.properties")
public class AppConfig {

    @Value("${testbean.name}")
    private String beanName;

   
}

以下是一个简单示例:

weather=sunning
wind=5
package win.elegentjs.spring.ioc.propertysource;

import lombok.ToString;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@PropertySource({"classpath:application.properties"})
@ToString
public class MyPropertySourceConfig {

    @Value("${weather}")
    private String weather;

    @Value("${wind}")
    private Integer wind;
}

package win.elegentjs.spring.ioc.propertysource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

@Slf4j
public class MyPropertySourceSample {

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(MyPropertySourceConfig.class);
        MyPropertySourceConfig config = context.getBean(MyPropertySourceConfig.class);

        log.info("==> config: {}", config);
    }
}

// result:
2021-05-31 19:38:35.508 [main] INFO  w.e.s.ioc.propertysource.MyPropertySourceSample-==> config: MyPropertySourceConfig(weather=sunning, wind=5)

#{…} vs ${…}

${}用于从属性配置文件中获取属性值。
#{}里面可以写SpEL表达式, 如#{T(java.lang.Math.random}, #{‘Hello world’.bytes.length}。 类似于OGNL。

两者可以混用,如:#{${…}.split(’,’)}
但需要注意:必须#{}在外面,${}在里面, 因为${}会优先解析

小结

本节学习了如何使用@Value加载属性值,属性值可以来源于外部资源文件,也可以来自内部的属性,spEL。
学习了如何使用@PropertySource加载外部配置文件。至于背后的原理部分如Environment, PropertySourcesPlaceholderConfigurer等后面会开专门的章节分析。

标签:PropertySource,12,spring,springframework,private,Value,import,org,class
来源: https://blog.csdn.net/qq_25027457/article/details/117420372