Skip to content

Commit ea6f478

Browse files
committed
read-config-properties
1 parent ea4d1bc commit ea6f478

File tree

18 files changed

+1133
-0
lines changed

18 files changed

+1133
-0
lines changed

docs/basis/Untitled.md

Whitespace-only changes.

docs/basis/read-config-properties.md

+245
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
很多时候我们需要将一些常用的配置信息比如阿里云oss配置、发送短信的相关信息配置等等放到配置文件中。
2+
3+
下面我们来看一下 Spring 为我们提供了哪些方式帮助我们从配置文件中读取这些配置信息。
4+
5+
`application.yml` 内容如下:
6+
7+
```yaml
8+
wuhan2020: 2020年初武汉爆发了新型冠状病毒,疫情严重,但是,我相信一切都会过去!武汉加油!中国加油!
9+
10+
my-profile:
11+
name: Guide哥
12+
email: koushuangbwcx@163.com
13+
14+
library:
15+
location: 湖北武汉加油中国加油
16+
books:
17+
- name: 天才基本法
18+
description: 二十二岁的林朝夕在父亲确诊阿尔茨海默病这天,得知自己暗恋多年的校园男神裴之即将出国深造的消息——对方考取的学校,恰是父亲当年为她放弃的那所。
19+
- name: 时间的秩序
20+
description: 为什么我们记得过去,而非未来?时间“流逝”意味着什么?是我们存在于时间之内,还是时间存在于我们之中?卡洛·罗韦利用诗意的文字,邀请我们思考这一亘古难题——时间的本质。
21+
- name: 了不起的我
22+
description: 如何养成一个新习惯?如何让心智变得更成熟?如何拥有高质量的关系? 如何走出人生的艰难时刻?
23+
24+
```
25+
26+
### 1.通过 `@value` 读取比较简单的配置信息
27+
28+
使用 `@Value("${property}")` 读取比较简单的配置信息:
29+
30+
```java
31+
@Value("${wuhan2020}")
32+
String wuhan2020;
33+
```
34+
35+
> **需要注意的是 `@value`这种方式是不被推荐的,Spring 比较建议的是下面几种读取配置信息的方式。**
36+
37+
### 2.通过`@ConfigurationProperties`读取并与 bean 绑定
38+
39+
> **`LibraryProperties` 类上加了 `@Component` 注解,我们可以像使用普通 bean 一样将其注入到类中使用。**
40+
41+
```java
42+
43+
import lombok.Getter;
44+
import lombok.Setter;
45+
import lombok.ToString;
46+
import org.springframework.boot.context.properties.ConfigurationProperties;
47+
import org.springframework.context.annotation.Configuration;
48+
import org.springframework.stereotype.Component;
49+
50+
import java.util.List;
51+
52+
@Component
53+
@ConfigurationProperties(prefix = "library")
54+
@Setter
55+
@Getter
56+
@ToString
57+
class LibraryProperties {
58+
private String location;
59+
private List<Book> books;
60+
61+
@Setter
62+
@Getter
63+
@ToString
64+
static class Book {
65+
String name;
66+
String description;
67+
}
68+
}
69+
70+
```
71+
72+
这个时候你就可以像使用普通 bean 一样,将其注入到类中使用:
73+
74+
```java
75+
package cn.javaguide.readconfigproperties;
76+
77+
import org.springframework.beans.factory.InitializingBean;
78+
import org.springframework.boot.SpringApplication;
79+
import org.springframework.boot.autoconfigure.SpringBootApplication;
80+
81+
/**
82+
* @author shuang.kou
83+
*/
84+
@SpringBootApplication
85+
public class ReadConfigPropertiesApplication implements InitializingBean {
86+
87+
private final LibraryProperties library;
88+
89+
public ReadConfigPropertiesApplication(LibraryProperties library) {
90+
this.library = library;
91+
}
92+
93+
public static void main(String[] args) {
94+
SpringApplication.run(ReadConfigPropertiesApplication.class, args);
95+
}
96+
97+
@Override
98+
public void afterPropertiesSet() {
99+
System.out.println(library.getLocation());
100+
System.out.println(library.getBooks()); }
101+
}
102+
```
103+
104+
控制台输出:
105+
106+
```
107+
湖北武汉加油中国加油
108+
[LibraryProperties.Book(name=天才基本法, description........]
109+
```
110+
111+
### 3.通过`@ConfigurationProperties`读取并校验
112+
113+
我们先将`application.yml`修改为如下内容,明显看出这不是一个正确的 email 格式:
114+
115+
```yaml
116+
my-profile:
117+
name: Guide哥
118+
email: koushuangbwcx@
119+
```
120+
121+
>**`ProfileProperties` 类没有加 `@Component` 注解。我们在我们要使用`ProfileProperties` 的地方使用`@EnableConfigurationProperties`注册我们的配置bean:**
122+
123+
```java
124+
import lombok.Getter;
125+
import lombok.Setter;
126+
import lombok.ToString;
127+
import org.springframework.boot.context.properties.ConfigurationProperties;
128+
import org.springframework.stereotype.Component;
129+
import org.springframework.validation.annotation.Validated;
130+
131+
import javax.validation.constraints.Email;
132+
import javax.validation.constraints.NotEmpty;
133+
134+
/**
135+
* @author shuang.kou
136+
*/
137+
@Getter
138+
@Setter
139+
@ToString
140+
@ConfigurationProperties("my-profile")
141+
@Validated
142+
public class ProfileProperties {
143+
@NotEmpty
144+
private String name;
145+
146+
@Email
147+
@NotEmpty
148+
private String email;
149+
150+
//配置文件中没有读取到的话就用默认值
151+
private Boolean handsome = Boolean.TRUE;
152+
153+
}
154+
```
155+
156+
具体使用:
157+
158+
```java
159+
package cn.javaguide.readconfigproperties;
160+
161+
import org.springframework.beans.factory.InitializingBean;
162+
import org.springframework.beans.factory.annotation.Value;
163+
import org.springframework.boot.SpringApplication;
164+
import org.springframework.boot.autoconfigure.SpringBootApplication;
165+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
166+
167+
/**
168+
* @author shuang.kou
169+
*/
170+
@SpringBootApplication
171+
@EnableConfigurationProperties(ProfileProperties.class)
172+
public class ReadConfigPropertiesApplication implements InitializingBean {
173+
private final ProfileProperties profileProperties;
174+
175+
public ReadConfigPropertiesApplication(ProfileProperties profileProperties) {
176+
this.profileProperties = profileProperties;
177+
}
178+
179+
public static void main(String[] args) {
180+
SpringApplication.run(ReadConfigPropertiesApplication.class, args);
181+
}
182+
183+
@Override
184+
public void afterPropertiesSet() {
185+
System.out.println(profileProperties.toString());
186+
}
187+
}
188+
189+
```
190+
191+
因为我们的邮箱格式不正确,所以程序运行的时候就报错,根本运行不起来,保证了数据类型的安全性:
192+
193+
```visual basic
194+
Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'my-profile' to cn.javaguide.readconfigproperties.ProfileProperties failed:
195+
196+
Property: my-profile.email
197+
Value: koushuangbwcx@
198+
Origin: class path resource [application.yml]:5:10
199+
Reason: must be a well-formed email address
200+
```
201+
202+
我们把邮箱测试改为正确的之后再运行,控制台就能成功打印出读取到的信息:
203+
204+
```
205+
ProfileProperties(name=Guide哥, email=koushuangbwcx@163.com, handsome=true)
206+
```
207+
208+
### 4.`@PropertySource`读取指定 properties 文件
209+
210+
```java
211+
import lombok.Getter;
212+
import lombok.Setter;
213+
import org.springframework.beans.factory.annotation.Value;
214+
import org.springframework.context.annotation.PropertySource;
215+
import org.springframework.stereotype.Component;
216+
217+
@Component
218+
@PropertySource("classpath:website.properties")
219+
@Getter
220+
@Setter
221+
class WebSite {
222+
@Value("${url}")
223+
private String url;
224+
}
225+
```
226+
227+
使用:
228+
229+
```java
230+
@Autowired
231+
private WebSite webSite;
232+
233+
System.out.println(webSite.getUrl());//https://javaguide.cn/
234+
235+
```
236+
237+
### 5.题外话:Spring加载配置文件的优先级
238+
239+
Spring 读取配置文件也是有优先级的,直接上图:
240+
241+
<img src="https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-11/read-config-properties-priority.jpg" style="zoom:50%;" />
242+
243+
更对内容请查看官方文档:https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config
244+
245+
> 本文源码:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
HELP.md
2+
target/
3+
!.mvn/wrapper/maven-wrapper.jar
4+
!**/src/main/**
5+
!**/src/test/**
6+
7+
### STS ###
8+
.apt_generated
9+
.classpath
10+
.factorypath
11+
.project
12+
.settings
13+
.springBeans
14+
.sts4-cache
15+
16+
### IntelliJ IDEA ###
17+
.idea
18+
*.iws
19+
*.iml
20+
*.ipr
21+
22+
### NetBeans ###
23+
/nbproject/private/
24+
/nbbuild/
25+
/dist/
26+
/nbdist/
27+
/.nb-gradle/
28+
build/
29+
30+
### VS Code ###
31+
.vscode/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
* Copyright 2007-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import java.net.*;
18+
import java.io.*;
19+
import java.nio.channels.*;
20+
import java.util.Properties;
21+
22+
public class MavenWrapperDownloader {
23+
24+
private static final String WRAPPER_VERSION = "0.5.6";
25+
/**
26+
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
27+
*/
28+
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
29+
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
30+
31+
/**
32+
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
33+
* use instead of the default one.
34+
*/
35+
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
36+
".mvn/wrapper/maven-wrapper.properties";
37+
38+
/**
39+
* Path where the maven-wrapper.jar will be saved to.
40+
*/
41+
private static final String MAVEN_WRAPPER_JAR_PATH =
42+
".mvn/wrapper/maven-wrapper.jar";
43+
44+
/**
45+
* Name of the property which should be used to override the default download url for the wrapper.
46+
*/
47+
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
48+
49+
public static void main(String args[]) {
50+
System.out.println("- Downloader started");
51+
File baseDirectory = new File(args[0]);
52+
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
53+
54+
// If the maven-wrapper.properties exists, read it and check if it contains a custom
55+
// wrapperUrl parameter.
56+
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
57+
String url = DEFAULT_DOWNLOAD_URL;
58+
if (mavenWrapperPropertyFile.exists()) {
59+
FileInputStream mavenWrapperPropertyFileInputStream = null;
60+
try {
61+
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
62+
Properties mavenWrapperProperties = new Properties();
63+
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
64+
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
65+
} catch (IOException e) {
66+
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
67+
} finally {
68+
try {
69+
if (mavenWrapperPropertyFileInputStream != null) {
70+
mavenWrapperPropertyFileInputStream.close();
71+
}
72+
} catch (IOException e) {
73+
// Ignore ...
74+
}
75+
}
76+
}
77+
System.out.println("- Downloading from: " + url);
78+
79+
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
80+
if (!outputFile.getParentFile().exists()) {
81+
if (!outputFile.getParentFile().mkdirs()) {
82+
System.out.println(
83+
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
84+
}
85+
}
86+
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
87+
try {
88+
downloadFileFromURL(url, outputFile);
89+
System.out.println("Done");
90+
System.exit(0);
91+
} catch (Throwable e) {
92+
System.out.println("- Error downloading");
93+
e.printStackTrace();
94+
System.exit(1);
95+
}
96+
}
97+
98+
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
99+
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
100+
String username = System.getenv("MVNW_USERNAME");
101+
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
102+
Authenticator.setDefault(new Authenticator() {
103+
@Override
104+
protected PasswordAuthentication getPasswordAuthentication() {
105+
return new PasswordAuthentication(username, password);
106+
}
107+
});
108+
}
109+
URL website = new URL(urlString);
110+
ReadableByteChannel rbc;
111+
rbc = Channels.newChannel(website.openStream());
112+
FileOutputStream fos = new FileOutputStream(destination);
113+
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
114+
fos.close();
115+
rbc.close();
116+
}
117+
118+
}
Binary file not shown.

0 commit comments

Comments
 (0)