@ConfigurationProperties和@value都是将外部属性注入到对象
@ConfigurationProperties很方便使用。 比用@value注解好吗? 在特定的方案中是的,这只是一个选择问题
@EnableConfigurationProperties //开启属性注入,有此注解就可以通过@autowired注入, 是配合@ConfigurationProperties使用的。
如果没有@EnableConfigurationProperties,则使用@ConfigurationProperties注解的class上面还需要添加@Component(@Component的包装注解,譬如
@Configuration、@Service也可以。但本质还是注解@Component)
@EnableAutoConfiguration在Spring boot中是启动自动配置的(Auto-configuration tries to be as intelligent as possible and will back-away as you define more of your own configuration.)
yml:
map结构:
myProps: #自定义的属性和值
simpleProp: simplePropValue
arrayProps: 1,2,3,4,5
listProp1: #List中的元素是Map
- name: abc
value: abcValue
- name: efg
value: efgValue
listProp2:
- config2Value1
- config2Vavlue2
mapProps:
key1: value1
key2: value2
@Component
@ConfigurationProperties(prefix="myProps") //接收application.yml中的myProps下面的属性
public class MyProps {
private String simpleProp;
private String[] arrayProps;
private List<Map<String, String>> listProp1 = new ArrayList<>(); //接收prop1里面的属性值,List中的元素是Map
private List<String> listProp2 = new ArrayList<>(); //接收prop2里面的属性值
private Map<String, String> mapProps = new HashMap<>(); //接收prop1里面的属性值
public String getSimpleProp() {
return simpleProp;
}
//String类型的一定需要setter来接收属性值;maps, collections, 和 arrays 不需要
public void setSimpleProp(String simpleProp) {
this.simpleProp = simpleProp;
}
public List<Map<String, String>> getListProp1() {
return listProp1;
}
public List<String> getListProp2() {
return listProp2;
}
public String[] getArrayProps() {
return arrayProps;
}
public void setArrayProps(String[] arrayProps) {
this.arrayProps = arrayProps;
}
public Map<String, String> getMapProps() {
return mapProps;
}
public void setMapProps(Map<String, String> mapProps) {
this.mapProps = mapProps;
}
}
Take a look at the javadoc for ConfigurationProperties for more information on its various configuration options. For example, you can set a prefix to divide your configuration into a number of different namespaces:
@ConfigurationProperties(prefix="foo")
For the binding to work, you'd then have to use the same prefix on the properties declared in application.properties:
foo.users.alice=alpha
foo.users.bob=bravo
注入到Map类型的users字段中, alice和bob是map结构的key,等号后面的是value
一、@ConfigurationProperties注解的使用
看配置文件,我的是yaml格式的配置:
// file application.yml
my:
servers:
- dev.bar.com
- foo.bar.com - jiaobuchong.com
下面我要将上面的配置属性注入到一个Java Bean类中,看码:
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component //不加这个注解的话, 使用@Autowired 就不能注入进去了 @ConfigurationProperties(prefix = "my") // 配置文件中的前缀 public class MyConfig { private List<String> servers = new ArrayList<String>(); public List<String> getServers() { return this.servers; } }
下面写一个Controller来测试一下:
@RequestMapping("/test")
@RestController
public class HelloController { @Autowired private MyConfig myConfig; @RequestMapping("/config") public Object getConfig() { return myConfig.getServers(); } }
下面运行Application.java的main方法跑一下看看:
@SpringBootApplication public class Application { public static void main(String[] args) { // 启动Spring Boot项目的唯一入口 SpringApplication app = new SpringApplication(Application.class); app.setBannerMode(Banner.Mode.OFF); app.run(args); }
在浏览器的地址栏里输入:
localhost:8080/test/config 得到:
[“dev.bar.com”,”foo.bar.com”,”jiaobuchong.com”]
@EnableAutoConfiguration
/**
* Enable auto-configuration of the Spring Application Context, attempting to guess and configure beans that you are likely to need. Auto-configuration classes are usually
* applied based on your classpath and what beans you have defined. For example, If you
* have {@code tomcat-embedded.jar} on your classpath you are likely to want a
* {@link TomcatEmbeddedServletContainerFactory} (unless you have defined your own
* {@link EmbeddedServletContainerFactory} bean).
* <p>
* Auto-configuration tries to be as intelligent as possible and will back-away as you
* define more of your own configuration. You can always manually {@link #exclude()} any
* configuration that you never want to apply (use {@link #excludeName()} if you don't
* have access to them). You can also exclude them via the
* {@code spring.autoconfigure.exclude} property. Auto-configuration is always applied
* after user-defined beans have been registered.
* <p>
* The package of the class that is annotated with {@code @EnableAutoConfiguration} has
* specific significance and is often used as a 'default'. For example, it will be used
* when scanning for {@code @Entity} classes. It is generally recommended that you place
* {@code @EnableAutoConfiguration} in a root package so that all sub-packages and classes
* can be searched.
* <p>
* Auto-configuration classes are regular Spring {@link Configuration} beans. They are
* located using the {@link SpringFactoriesLoader} mechanism (keyed against this class).
* Generally auto-configuration beans are {@link Conditional @Conditional} beans (most
* often using {@link ConditionalOnClass @ConditionalOnClass} and
* {@link ConditionalOnMissingBean @ConditionalOnMissingBean} annotations).
*
* @author Phillip Webb
* @author Stephane Nicoll
* @see ConditionalOnBean
* @see ConditionalOnMissingBean
* @see ConditionalOnClass
* @see AutoConfigureAfter
*/
@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
二、@ConfigurationProperties和@EnableConfigurationProperties注解结合使用
在spring boot中使用yaml进行配置的一般步骤是,
1、yaml配置文件,这里假设:
my:
webserver:
#HTTP 监听端口
port: 80
#嵌入Web服务器的线程池配置
threadPool:
maxThreads: 100 minThreads: 8 idleTimeout: 60000
2、
//file MyWebServerConfigurationProperties.java
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "my.webserver") //没有使用@Component或@Confinguration,因此此对象不会注册到Spring容器中,需要@EnableConfigurationProperties引用
public class MyWebServerConfigurationProperties {
private int port;
private ThreadPool threadPool;
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public ThreadPool getThreadPool() {
return threadPool;
}
public void setThreadPool(ThreadPool threadPool) {
this.threadPool = threadPool;
}
public static class ThreadPool {
private int maxThreads;
private int minThreads;
private int idleTimeout;
public int getIdleTimeout() {
return idleTimeout;
}
public void setIdleTimeout(int idleTimeout) {
this.idleTimeout = idleTimeout;
}
public int getMaxThreads() {
return maxThreads;
}
public void setMaxThreads(int maxThreads) {
this.maxThreads = maxThreads;
}
public int getMinThreads() {
return minThreads;
}
public void setMinThreads(int minThreads) {
this.minThreads = minThreads;
}
}
}
3、
// file: MyWebServerConfiguration.java
import org.springframework.context.annotation.Configuration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@Configuration
@EnableConfigurationProperties(MyWebServerConfigurationProperties.class)
public class MyWebServerConfiguration {
@Autowired
private MyWebServerConfigurationProperties properties;
/**
*下面就可以引用MyWebServerConfigurationProperties类 里的配置了
*/
public void setMyconfig() {
String port = properties.getPort();
// ...........
}
}
The @EnableConfigurationProperties annotation is automatically applied to your project so that any beans annotated with @ConfigurationProperties will be configured from the Environment properties. This style of configuration works particularly well with the SpringApplication external YAML configuration.(引自spring boot官方手册)
三、@Bean配置第三方组件(Third-party configuration)
创建一个bean类:
// file ThreadPoolBean.java
public class ThreadPoolBean {
private int maxThreads;
private int minThreads;
private int idleTimeout;
public int getMaxThreads() {
return maxThreads;
}
public void setMaxThreads(int maxThreads) {
this.maxThreads = maxThreads;
}
public int getMinThreads() {
return minThreads;
}
public void setMinThreads(int minThreads) {
this.minThreads = minThreads;
}
public int getIdleTimeout() {
return idleTimeout;
}
public void setIdleTimeout(int idleTimeout) {
this.idleTimeout = idleTimeout;
}
}
引用前面第二部分写的配置类:MyWebServerConfiguration.java和MyWebServerConfigurationProperties.java以及yaml配置文件,现在修改MyWebServerConfiguration.java类:
import com.jiaobuchong.springboot.domain.ThreadPoolBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration //这是一个配置类,与@Service、@Component的效果类似。spring会扫描到这个类,@Bean才会生效,将ThreadPoolBean这个返回值类注册到spring上下文环境中 @EnableConfigurationProperties(MyWebServerConfigurationProperties.class) //通过这个注解, 将MyWebServerConfigurationProperties这个类的配置到上下文环境中,本类中使用的@Autowired注解注入才能生效 public class MyWebServerConfiguration { @SuppressWarnings("SpringJavaAutowiringInspection") //加这个注解让IDE 不报: Could not autowire @Autowired private MyWebServerConfigurationProperties properties; @Bean //@Bean注解在方法上,返回值是一个类的实例,并声明这个返回值(返回一个对象)是spring上下文环境中的一个bean public ThreadPoolBean getThreadBean() { MyWebServerConfigurationProperties.ThreadPool threadPool = properties.getThreadPool(); ThreadPoolBean threadPoolBean = new ThreadPoolBean(); threadPoolBean.setIdleTimeout(threadPool.getIdleTimeout()); threadPoolBean.setMaxThreads(threadPool.getMaxThreads()); threadPoolBean.setMinThreads(threadPool.getMinThreads()); return threadPoolBean; } }
被@Configuration注解标识的类,通常作为一个配置类,这就类似于一个xml文件,表示在该类中将配置Bean元数据,其作用类似于Spring里面application-context.xml的配置文件,而@Bean标签,则类似于该xml文件中,声明的一个bean实例。
写一个controller测试一下:
import com.jiaobuchong.springboot.domain.ThreadPoolBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/first")
@RestController
public class HelloController {
@Autowired
private ThreadPoolBean threadPoolBean;
@RequestMapping("/testbean")
public Object getThreadBean() {
return threadPoolBean;
}
}
运行Application.java的main方法,
在浏览器里输入:http://localhost:8080/first/testbean
得到的返回值是:
{“maxThreads”:100,”minThreads”:8,”idleTimeout”:60000}
el最常用的几种使用场景:
- 从配置文件中读取属性
- 缺失值情况下,配置默认值
- el内部字符串使用String的方法
- 三目运算符
- 正则表达式
- 注入系统属性(system properties)
- 调用系统原有函数
- 直接注入文件进行操作
- 读取另一个bean的函数的返回值
1、从配置文件中读取属性
application.properties
name=\u8D75\u8BA1\u521A
1 @Value("${name}")//这里必须使用$,使用#是不行的
2 private String name;
3 @RequestMapping(value = "/name", method = RequestMethod.GET)
4 public String getName() {
5 return name;
6 }
注意:记住下边三句话
- ${}不支持表达式(三目表达式不算表达式);#{}支持
- ${}读取属性文件的值
- ${}读取最后一个满足条件的值;#{}读取所有满足条件的值
2、缺失值情况下,配置默认值
1 @Value("${name2:'刚子'}")//这里必须使用$,使用#是不行的
2 private String name2;
3 @RequestMapping(value = "/name2", method = RequestMethod.GET)
4 public String getName2() {
5 return name2;
6 }
3、el内部字符串使用String的方法
1 name.list=\u8D75\u8BA1\u521A,\u738B\u5A1C
1 @Value("#{'${name.list}'.split(',')}")
2 private List<String> nameList;
3 @RequestMapping(value = "/nameList", method = RequestMethod.GET)
4 public List<String> getNameList() {
5 return nameList;
6 }
4、三目运算符
1 name.three=\u6768\u8FC7
1 @RequestMapping(value = "/nameThree", method = RequestMethod.GET)
2 public String getNameThree(@Value("${name.three!='杨过'?'黄蓉':'小龙女'}") String nameThree) {
3 return nameThree;
4 }
注意:@value可以直接作为入参
5、正则表达式
1 @Value("#{'100' matches '\\d+'}")//这里必须使用#,使用$是不行的
2 private boolean isDigital;
3 @RequestMapping(value = "/nameRegEx", method = RequestMethod.GET)
4 public boolean getNameRegEx() {
5 return isDigital;
6 }
6、注入系统属性
1 @Value("#{systemProperties['os.name']}")//这里必须使用#,使用$是不行的
2 private String osName;
3 @RequestMapping(value = "/osName", method = RequestMethod.GET)
4 public String getOsName() {
5 return osName;
6 }
7、调用系统原有函数
1 @Value("#{T(java.lang.Math).random() * 10}")//注意:这里只生成一次,之后你无论调用多少次getRandomValue(),都返回同一个值
2 private String randomValue;
3 @RequestMapping(value = "/randomValue", method = RequestMethod.GET)
4 public String getRandomValue() {
5 return randomValue;
6 }
8、直接注入文件进行操作
testfile/testEl.txt
1 乔峰--降龙十八掌 2 杨过--黯然销魂掌
1 @Value("classpath:testfile/testEl.txt")
2 private Resource txtResource;
3 @RequestMapping(value = "/resource", method = RequestMethod.GET)
4 public String getResource() {
5 try {
6 return IOUtils.toString(txtResource.getInputStream(), "UTF-8");
7 } catch (IOException e) {
8 ExceptionUtils.getStackTrace(e);
9 }
10 return StringUtils.EMPTY;
11 }
注意:这个很重要,操作文件使用Apache.commons.io.IOUtils来操作。
9、读取另一个bean的函数的返回值
1 @Component("eLComponent")
2 public class ELComponent {
3 public String getNameBean(){
4 return "乔峰";
5 }
6 }
1 @Value("#{eLComponent.getNameBean()}")//这里必须使用#,使用$是不行的
2 private String nameBean;
3 @RequestMapping(value = "/nameBean", method = RequestMethod.GET)
4 public String getNameBean() {
5 return nameBean;
6 }
注意:被调用bean最好指定一下beanName。
application.properties中的配置:
db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/mydb?characterEncoding=utf-8&useSSL=false
db.username=xxx
db.password=xxx
import java.beans.PropertyVetoException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import com.mchange.v2.c3p0.ComboPooledDataSource;
@Configuration
public class DBconfig {
@Autowired
private Environment env;
@Bean(name="dataSource")
public ComboPooledDataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(env.getProperty("db.driverClassName"));
dataSource.setJdbcUrl(env.getProperty("db.url"));
dataSource.setUser(env.getProperty("db.username"));
dataSource.setPassword(env.getProperty("db.password"));
dataSource.setMaxPoolSize(20);
dataSource.setMinPoolSize(5);
dataSource.setInitialPoolSize(10);
dataSource.setMaxIdleTime(300);
dataSource.setAcquireIncrement(5);
dataSource.setIdleConnectionTestPeriod(60);
return dataSource;
}
}