通过@Value将外部的值动态注入到Bean中,使用的情况有:
package com.hannpang.model; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component(value = "st")//对student进行实例化操作 public class Student { @Value("悟空") private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } 复制代码
package com.hannpang.model; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; import org.springframework.stereotype.Component; @Component public class SimpleObject { @Value("注入普通字符串") private String normal; //关于属性的KEY可以查看System类说明 @Value("#{systemProperties['java.version']}")//-->使用了SpEL表达式 private String systemPropertiesName; // 注入操作系统属性 @Value("#{T(java.lang.Math).random()*80}")//获取随机数 private double randomNumber; //注入表达式结果 @Value("#{1+2}") private double sum; //注入表达式结果 1+2的求和 @Value("classpath:os.yaml") private Resource resourceFile; // 注入文件资源 @Value("http://www.baidu.com") private Resource testUrl; // 注入URL资源 @Value("#{st.name}") private String studentName; //省略getter和setter方法 @Override public String toString() { return "SimpleObject{" + "normal='" + normal + '/'' + ", systemPropertiesName='" + systemPropertiesName + '/'' + ", randomNumber=" + randomNumber + ", sum=" + sum + ", resourceFile=" + resourceFile + ", testUrl=" + testUrl + ", studentName='" + studentName + '/'' + '}'; } } 复制代码
package com.hannpang; import com.hannpang.model.SimpleObject; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class Demo04BootApplicationTests { @Autowired private SimpleObject so; @Test public void contextLoads() { System.out.println(so); } } 复制代码
运行结果为:SimpleObject{normal='注入普通字符串', systemPropertiesName='1.8.0_172', randomNumber=56.631954541947266, sum=3.0, resourceFile=class path resource [os.yaml], testUrl=URL [http://www.baidu.com], studentName='悟空'} 复制代码
通过@Value将外部配置文件的值动态注入到Bean中。配置文件主要有两类:
在application.properties中加入如下测试代码
app.name=一步教育 复制代码
在resources下面新建第一个属性文件 config.properties
内容如下
book.name=西游记 anotherfile.configinject=system 复制代码
在resources下面新建第二个属性文件 config_system.properties
内容如下
我的目的是想system的值使用第一个属性文件中定义的值
book.name.author=吴承恩 复制代码
下面通过 @Value(“${app.name}”)
语法将属性文件的值注入bean属性值,详细代码见:
package com.hannpang.test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; @Component @PropertySource(value = {"classpath:config.properties","classpath:config_${anotherfile.configinject}.properties"}) public class LoadPropsTest { @Value("${app.name}") private String appName; // 这里的值来自application.properties,spring boot启动时默认加载此文件 @Value("${book.name}") private String bookName; // 注入第一个配置外部文件属性 @Value("${book.name.author}") private String author; // 注入第二个配置外部文件属性 @Autowired private Environment env; // 注入环境变量对象,存储注入的属性值 //省略getter和setter方法 public void setAuthor(String author) { this.author = author; } @Override public String toString(){ StringBuilder sb = new StringBuilder(); sb.append("bookName=").append(bookName).append("/r/n") .append("author=").append(author).append("/r/n") .append("appName=").append(appName).append("/r/n") .append("env=").append(env).append("/r/n") // 从eniroment中获取属性值 .append("env=").append(env.getProperty("book.name.author")).append("/r/n"); return sb.toString(); } } 复制代码
package com.hannpang; import com.hannpang.model.SimpleObject; import com.hannpang.test.LoadPropsTest; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class Demo04BootApplicationTests { @Autowired private LoadPropsTest lpt; @Test public void loadPropertiesTest() { System.out.println(lpt); } } 复制代码
运行结果为: bookName=西游记 author=吴承恩 appName=一步教育 env=StandardEnvironment {activeProfiles=[], defaultProfiles=[default], propertySources=[ConfigurationPropertySourcesPropertySource {name='configurationProperties'}, MapPropertySource {name='Inlined Test Properties'}, MapPropertySource {name='systemProperties'}, OriginAwareSystemEnvironmentPropertySource {name='systemEnvironment'}, RandomValuePropertySource {name='random'}, OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/application.properties]'}, ResourcePropertySource {name='class path resource [config_system.properties]'}, ResourcePropertySource {name='class path resource [config.properties]'}]} env=吴承恩 复制代码
#{...}和${...}
的区别演示 ${…}
的用法 {}里面的内容必须符合SpEL表达式,通过 @Value(“${app.name}”)
可以获取属性文件中对应的值,但是如果属性文件中没有这个属性,则会报错。可以通过赋予默认值解决这个问题,如 @Value("${app.name:胖先森}")
// 如果属性文件没有app.name,则会报错 // @Value("${app.name}") // private String name; // 使用app.name设置值,如果不存在则使用默认值 @Value("${app.name:胖先森}") private String name; 复制代码
#{...}
的用法 // SpEL:调用字符串Hello World的concat方法 @Value("#{'Hello World'.concat('!')}") private String helloWorld; // SpEL: 调用字符串的getBytes方法,然后调用length属性 @Value("#{'Hello World'.bytes.length}") private String helloWorldbytes; 复制代码
#{...}
和 ${...}
混合使用 ${...}和#{...}
可以混合使用,如下文代码执行顺序:通过${server.name}从属性文件中获取值并进行替换,然后就变成了 执行SpEL表达式{‘server1,server2,server3’.split(‘,’)}。
// SpEL: 传入一个字符串,根据","切分后插入列表中, #{}和${}配置使用(注意单引号,注意不能反过来${}在外面,#{}在里面) @Value("#{'${server.name}'.split(',')}") private List<String> servers; 复制代码
在上文中在 #{}外面,${}在里面
可以执行成功,那么反过来是否可以呢 ${}在外面,#{}在里面
,如代码
// SpEL: 注意不能反过来${}在外面,#{}在里面,这个会执行失败 @Value("${#{'HelloWorld'.concat('_')}}") private List<String> servers2; 复制代码
答案是不能。 因为spring执行${}是时机要早于#{}。 在本例中,Spring会尝试从属性中查找#{‘HelloWorld’.concat(‘_’)},那么肯定找到,由上文已知如果找不到,然后报错。所以${}在外面,#{}在里面是非法操作 复制代码
@ConfigurationProperties | @Value | |
---|---|---|
功能 | 批量注入配置文件中的属性 | 一个个指定 |
松散绑定(松散语法) | 支持 | 不支持 |
SpEL | 不支持 | 支持 |
JSR303数据校验 | 支持 | 不支持 |
复杂类型封装 | 支持 | 不支持 |
配置文件yml还是properties他们都能获取到值;
如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value;
如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties;
@Component @ConfigurationProperties(prefix = "person") @Validated public class Person { //lastName必须是邮箱格式 @Email private String lastName; 复制代码
@ImportResource
引入配置文件 不推荐的使用方式
Spring Boot里面没有Spring的配置文件,我们自己编写的配置文件,也不能自动识别;
想让Spring的配置文件生效,加载进来;@ ImportResource 标注在一个配置类上
@ImportResource(locations = {"classpath:beans.xml"}) 导入Spring的配置文件让其生效 复制代码
编写配置文件信息
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="helloService" class="com.hanpang.springboot.service.HelloService"></bean> </beans> 复制代码
大概了解就好,我们基本上不使用这种方式
@Configuration
注解 SpringBoot推荐给容器中添加组件的方式;推荐使用全注解的方式
1、配置类 @Configuration
作用于类上,相当于一个xml配置文件
2、使用 @Bean
给容器中添加组件,作用于方法上
/** * @Configuration:指明当前类是一个配置类;就是来替代之前的Spring配置文件 * * 在配置文件中用<bean><bean/>标签添加组件 * <bean id="helloService" class="com.hanpang.springboot.service.HelloService"></bean> */ @Configuration public class MyAppConfig { //将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名 @Bean public HelloService helloService02(){ System.out.println("配置类@Bean给容器中添加组件了..."); return new HelloService(); } } 复制代码
使用Bean注入太麻烦,我们更加喜欢使用扫描的方式
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import com.wx.dao.IUserDao; import com.wx.dao.UserDaoImpl; //通过该注解来表明该类是一个Spring的配置,相当于一个传统的ApplicationContext.xml @Configuration //相当于配置文件里面的<context:component-scan/>标签,扫描这些包下面的类的注解 @ComponentScan(basePackages="com.hanpang.dao,com.hanpang.service") public class SpringConfig { // 通过该注解来表明是一个Bean对象,相当于xml中的<bean> //bean的id值默认是方法名userDao /* @Bean public HelloService helloService02(){ System.out.println("配置类@Bean给容器中添加组件了..."); return new HelloService(); } */ } 复制代码