Spring注解驱动之@Value详解

概述

本文介绍了@Value各种使用方法。

普通变量获取配置信息

可以通过@Value注解在字段上给字段赋值,@Value与bean标签中的value配置作用一致,因此用法也一致。
示例:

@Component
public class Person {
    /**
     * 1. @Value类似于bean标签中的value配置;
     * <bean id = "person" class="xxxxx">
     *     <property name="address" value="xxx"></property>
     * </bean>
     * 2. bean中的value可以配置:字面量;${key}获取环境变量、配置文件中的key值,#{SpEl}spring的EL表达式;
     * 因此@Value也可以配置上面的三种值。
     * 3. @Value获取配置信息,可以不写get/set方法。
     */
    @Value("小明")
    private String name;
    @Value("#{11*2}")
    private int age;
    @Value("${person.address}")
    private String address;
    private List<Object> like;
    private Map<String, Object> maps;
    private Dog dog;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public List<Object> getLike() {
        return like;
    }
    public void setLike(List<Object> like) {
        this.like = like;
    }
    public Map<String, Object> getMaps() {
        return maps;
    }
    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }
    public Dog getDog() {
        return dog;
    }
    public void setDog(Dog dog) {
        this.dog = dog;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                ", like=" + like +
                ", maps=" + maps +
                ", dog=" + dog +
                '}';
    }
}
  • 获取结果
    在这里插入图片描述

@Value注解配置默认值

@Value在注解模式下读取配置文件注入属性值
示例:

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

但是,如果配置文件中没有设置name的值,spring在启动的时候会报错。这时需要给name配置默认值,代码如下:

	@Value("${name:bob}")
	private String name;

除了String类型外,其他类型也可配置默认值:

	@Value("${age:18}")
	private int age;

@Value注入列表或者数组

可以使用split()方法在一行中注入“列表”。
配置如下:
config.properties

server.name=hydra,zeus
server.id=100,102,103

AppConfigTest.java

package com.mkyong.analyzer.test;
 
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
 
@Configuration
@PropertySource(value="classpath:config.properties")
public class AppConfigTest {
	
	@Value("#{'${server.name}'.split(',')}")
	private List<String> servers;
	
	@Value("#{'${server.id}'.split(',')}")
	private List<Integer> serverId;
	
	//To resolve ${} in @Value
	@Bean
	public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
		return new PropertySourcesPlaceholderConfigurer();
	}

}

注意如果配置项已逗号分隔,无需使用split方法,spring默认支持逗号的分隔。

可以指定默认值,下面的3种写法Spring都是支持的。

	@Value("#{'${server.id:127.0.0.1,192.168.1.18}'.split(',')}")
	private List<String> serverId;
 
	@Value("${server.id:127.0.0.1,192.168.1.18}")
	private List<String> serverId;
	
	@Value("${server.id:127.0.0.1,192.168.1.18}")
	private String[] serverId;

@Value给静态变量注入值

  • @Value不能直接给静态变量赋值,即使编译不报错,但是结果赋值不成功。
    @Value("${fastdfs.cache.redis.expireTime:86400}")
    public static int EXPIRE_TIME;

可以看到结果为0,没有赋值成功。
在这里插入图片描述

  • 静态变量赋值,@Value注解需要放在方法上
    类上加上@Component注解,方法名(例如setExpireTime,方法名可以随便写,通常以set开头)和参数名(例如expireTime,参数名也可以随便写),如下所示:
    /**
     * 缓存过期时间,单位秒
     */
    public static int EXPIRE_TIME;

    /**
     * 
     * @param expireTime 过期时间
     */
    @Value("${fastdfs.cache.redis.expireTime:86400}")
    public void setExpireTime(int expireTime) {
        EXPIRE_TIME = expireTime;
    }

测试结果,赋值成功。
在这里插入图片描述

@Value其他用法举例

  • 注入操作系统属性
@Value("#{systemProperties['os.name']}")
private String systemPropertiesName; // 注入操作系统属性
  • 注入其他bean中属性的值
@Value("#{person.name}")
private String username; // 注入其他bean中属性的值,即注入person对象的name属性中的值
  • 注入文件资源
@Value("classpath:/config.properties")
private Resource resourceFile; // 注入文件资源
  • 注入URL资源
@Value("http://www.baidu.com")
private Resource url; // 注入URL资源

@ConfigurationProperties与@Value的区别

@ConfigurationProperties@Value
功能可以批量注入配置文件中的属性只能一个个的指定
松散语法绑定(对象中的小驼峰命名与配置文件中-命令相互转换,比如:字段:lastName,可以在配置文件中写出last-name/last_name)支持不支持
SPEL表达式(Spring 表达式)不支持支持
JSR303数据校验(Java Specification Requests,JSR-303 是JAVA EE 6 中的一项子规范,叫做Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint。)支持不支持
复杂类型获取(对象、Map、数组)支持不支持

配置文件yaml或者properties格式都行。

如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value;
如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties;

  • JSR303数据校验
    示例:校验name的数据类型是Email格式,实际上配置文件中并不是Email格式,属性值绑定报错。
    在这里插入图片描述
  • 结果报错
    在这里插入图片描述

@PropertySource注解通过配置文件注入属性

首先,我们可以在项目的src/main/resources目录下新建一个属性文件,例如person.properties,其内容如下:

person.nickName=美美侠

新建MainConfigOfPropertyValues配置类,并在该类上使用@PropertySource注解读取外部配置文件中的key/value并保存到运行环境时环境变量中。

package com.meimeixia.config;

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

import com.meimeixia.bean.Person;

@PropertySource(value={"classpath:/person.properties"})
@Configuration
public class MainConfigOfPropertyValues {

	@Bean
	public Person person() {
		return new Person();
	}
}

加载完配置文件后,我们就可以使用${key}取出配置文件中key所对应的值,并将其注入到bean的属性中。

package com.meimeixia.bean;

import org.springframework.beans.factory.annotation.Value;

public class Person {
	
	@Value("李阿昀")
	private String name;
	@Value("#{20-2}")
	private Integer age;
	
	@Value("${person.nickName}")
	private String nickName; // 昵称
	
	public String getNickName() {
		return nickName;
	}
	public void setNickName(String nickName) {
		this.nickName = nickName;
	}
	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;
	}
	public Person(String name, Integer age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Person() {
		super();
		// TODO Auto-generated constructor stub
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", nickName=" + nickName + "]";
	}	
}

@Value中#{…}和${…}的区别

我们在这里提供一个测试属性文件,例如advance_value_inject.properties,大致的内容如下所示。

server.name=server1,server2,server3
author.name=liayun

然后,新建一个AdvanceValueInject类,并在该类上使用@PropertySource注解读取外部属性文件中的key/value并保存到运行的环境变量中,即加载外部的advance_value_inject.properties属性文件。

package com.meimeixia.bean;

import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

@Component
@PropertySource(value={"classpath:/advance_value_inject.properties"})
public class AdvanceValueInject {
	// ···	
}

以上准备工作做好之后,下面我们就来看看${···}的用法。

${…}的用法

{}里面的内容必须符合SpEL表达式,通过@Value(“${spelDefault.value}”),我们可以获取属性文件中对应的值,但是如果属性文件中没有这个属性,就会报错。不过,我们可以通过赋予默认值来解决这个问题。

@Value("${author.name:meimeixia}")
private String name;

上述代码的含义是表示向bean的属性中注入属性文件中的author.name属性所对应的值,如果属性文件中没有author.name这个属性,那么便向bean的属性中注入默认值meimeixia。

#{…}的用法

{}里面的内容同样也必须是符合SpEL表达式。

// SpEL:调用字符串Hello World的concat方法
@Value("#{'Hello World'.concat('!')}")
private String helloWorld;

// SpEL:调用字符串的getBytes方法,然后再调用其length属性
@Value("#{'Hello World'.bytes.length}")
private String helloWorldBytes;

${…}和#{…}的混合使用

${…}和#{…}可以混合使用,例如:

// SpEL:传入一个字符串,根据","切分后插入列表中, #{}和${}配合使用时,注意不能反过来${}在外面,而#{}在里面
@Value("#{'${server.name}'.split(',')}")
private List<String> severs;

上面片段的代码执行顺序:通过KaTeX parse error: Expected 'EOF', got '#' at position 88: …lit(',')}。 在上文中#̲{}在外面,{}在里面可以执行成功,那么反过来是否可以呢?

// SpEL:注意不能反过来,${}在外面,而#{}在里面,因为这样会执行失败
@Value("${#{'HelloWorld'.concat('_')}}")
private List<String> severs2;

答案是不能。因为Spring执行KaTeX parse error: Expected 'EOF', got '#' at position 9: {}的时机要早于#̲{},当Spring执行外层的{}时,内部的#{}为空,所以会执行失败!

小结

  • #{…}:用于执行SpEL表达式,并将内容赋值给属性。
  • ${…}:主要用于加载外部属性文件中的值。
  • KaTeX parse error: Expected 'EOF', got '#' at position 7: {...}和#̲{}可以混合使用,但是必须#{…{}在里面。

参考

Spring注解驱动开发第18讲——如何使用@Value注解为bean的属性赋值呢?

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring是一个Java开发框架,提供了许多注解来简化开发。下面是Spring中常用的注解详解: 1. @Autowired:自动装配,用于自动注入依赖项。 2. @Component:用于标记一个类为Spring容器管理的组件。 3. @Controller:用于标记一个类为Spring MVC控制器。 4. @Service:用于标记一个类为服务层组件。 5. @Repository:用于标记一个类为数据访问层组件。 6. @RequestMapping:用于映射请求到处理程序方法。 7. @PathVariable:用于获取请求URL中的变量值。 8. @RequestParam:用于获取请求参数的值。 9. @ResponseBody:用于将返回值直接写入响应体中。 10. @RestController:用于标记一个类为Spring MVC控制器,并且默认所有方法都返回JSON格式的数据。 11. @Configuration:用于标记一个类为配置类,相当于一个XML配置文件。 12. @Bean:用于在配置类中声明一个Bean。 13. @Value:用于获取配置文件中的属性值。 14. @Qualifier:用于指定自动装配时使用的Bean名称。 15. @Scope:用于指定Bean的作用域,例如singleton、prototype等。 16. @Transactional:用于标记一个方法为事务方法。 17. @Async:用于标记一个方法为异步方法。 18. @PostConstruct:用于标记一个方法为Bean初始化方法。 19. @PreDestroy:用于标记一个方法为Bean销毁方法。 以上是Spring中常见的注解详解,使用这些注解可以使开发更加简单和高效。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

融极

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值