1. 程式人生 > >SpringBoot 從application.yml中通過@Value讀取不到屬性值

SpringBoot 從application.yml中通過@Value讀取不到屬性值

catch ack exceptio 進一步 事情 imp 比較 pub true

package cn.exrick.xboot.mqtt;

import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

@Configuration
public
class PubService {

private static final Logger log = LoggerFactory.getLogger(PubService.class);

private MqttConfig mqttConfig;

private static MqttClient client;

// 在構造函數中註入mqttConfig能獲取到mqttConfig從application.yml中獲取到的值
public
PubService(@Autowired MqttConfig mqttConfig) {

this.mqttConfig = mqttConfig;
init();
}

// @Bean
// public
// PubService pubService() {
// return new PubService();
// }

private
void init() {
try {
client = new MqttClient(mqttConfig.host, mqttConfig.clientId, new MemoryPersistence());
// client = new MqttClient("tcp://106.14.181.253:1883", "SmartStreet", new MemoryPersistence());

MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(true);
connOpts.setUserName(mqttConfig.userName);
connOpts.setPassword(mqttConfig.password.toCharArray());
connOpts.setConnectionTimeout(10);
connOpts.setKeepAliveInterval(20);
client.connect(connOpts);
client.setCallback(new PubServiceCallBack(client));
log.trace("Pub service client Connected");
} catch (MqttException e) {
log.error("build Pub service failed " + e.getMessage());
}
}

public
void publishTop() {
MqttMessage message = new MqttMessage();
message.setQos(2);
message.setRetained(true);
message.setPayload("{\"CHx\":\"ON\"}".getBytes());
try {
client.publish("Pub/80001001/CHx", message);
} catch (MqttException e) {
e.printStackTrace();
}
}

public static
void publishTop(String topic, MqttMessage msg) throws MqttException {
try {
client.publish(topic, msg);
} catch (MqttException e) {

log.error("public topic fail: Topic Name:\t" + topic + "fail message: " + e.getMessage());
e.printStackTrace();
throw e;
}
}

}


package cn.exrick.xboot.mqtt;

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

@Configuration
public
class MqttConfig {

@Value("${ssmqtt.host}")
public String host;

@Value("${ssmqtt.server.name}")
public String userName;

@Value("${ssmqtt.server.password}")
public String password;

@Value("${ssmqtt.clientId}")
public String clientId;
}
package cn.exrick.xboot.mqtt;

import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

@Configuration
public
class PubService {

private static final Logger log = LoggerFactory.getLogger(PubService.class);

// 這種情況下,構造函數調用init方法就不能取到mqttConfig的值
@Autowired
private MqttConfig mqttConfig;

private static MqttClient client;


public
PubService() {
this.mqttConfig = mqttConfig;
init();
}

// @Bean
// public
// PubService pubService() {
// return new PubService();
// }

private
void init() {
try {
client = new MqttClient(mqttConfig.host, mqttConfig.clientId, new MemoryPersistence());
// client = new MqttClient("tcp://106.14.181.253:1883", "SmartStreet", new MemoryPersistence());
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(true);
connOpts.setUserName(mqttConfig.userName);
connOpts.setPassword(mqttConfig.password.toCharArray());
connOpts.setConnectionTimeout(10);
connOpts.setKeepAliveInterval(20);
client.connect(connOpts);
client.setCallback(new PubServiceCallBack(client));
log.trace("Pub service client Connected");
} catch (MqttException e) {
log.error("build Pub service failed " + e.getMessage());
}
}

public
void publishTop() {
MqttMessage message = new MqttMessage();
message.setQos(2);
message.setRetained(true);
message.setPayload("{\"CHx\":\"ON\"}".getBytes());
try {
client.publish("Pub/80001001/CHx", message);
} catch (MqttException e) {
e.printStackTrace();
}
}

public static
void publishTop(String topic, MqttMessage msg) throws MqttException {
try {
client.publish(topic, msg);
} catch (MqttException e) {

log.error("public topic fail: Topic Name:\t" + topic + "fail message: " + e.getMessage());
e.printStackTrace();
throw e;
}
}

}
主要問題的原因就是,構造函數的執行順序先於類屬性的賦值。在構造函數中使用屬性的值且從application.yml通過@Value獲取,此時Spring容器還沒有向屬性賦值。這是Spring Bean的聲明周期的屬性造成的。
1 package com.aomi;
2
3 import java.util.ArrayList;
4 import java.util.Iterator;
5 import java.util.List;
6 import static java.util.stream.Collectors.toList;
7
8 public class Main {
9
10 public static void main(String[] args) {
11 // TODO Auto-generated method stub
12
13 List<Student> stus = getSources();
14
15 Iterator<Student> ite = stus.iterator();
16
17 List<String> names = new ArrayList<>();
18 int limit = 2;
19 while (ite.hasNext() && limit > 0) {
20
21 Student stu = ite.next();
22
23 if (stu.getScore() > 5) {
24
25 names.add(stu.getName());
26 limit--;
27 }
28 }
29
30 for (String name : names) {
31 System.out.println(name);
32 }
33
34 }
35
36 public static List<Student> getSources() {
37 List<Student> students = new ArrayList<>();
38
39 Student stu1 = new Student();
40
41 stu1.setName("lucy");
42 stu1.setSex(0);
43 stu1.setPhone("13700227892");
44 stu1.setScore(9);
45
46 Student stu2 = new Student();
47 stu2.setName("lin");
48 stu2.setSex(1);
49 stu2.setPhone("15700227122");
50 stu2.setScore(9);
51
52 Student stu3 = new Student();
53 stu3.setName("lili");
54 stu3.setSex(0);
55 stu3.setPhone("18500227892");
56 stu3.setScore(8);
57
58 Student stu4 = new Student();
59
60 stu4.setName("dark");
61 stu4.setSex(1);
62 stu4.setPhone("16700555892");
63 stu4.setScore(6);
64
65 students.add(stu1);
66 students.add(stu2);
67 students.add(stu3);
68 students.add(stu4);
69
70 return students;
71 }
72
73 }
復制代碼
如果用流的話是這樣子的。

復制代碼
public static void main(String[] args) {
// TODO Auto-generated method stub

List<Student> stus = getSources();

List<String> names = stus.stream()
.filter(st -> st.getScore() > 5)
.limit(2)
.map(st -> st.getName())
.collect(toList());
for (String name : names) {
System.out.println(name);
}

}
復制代碼
把這倆段代碼相比較主要是為了說明一個概念:以前做法都是在外部叠代,最為體現就是筆者在外面定義了一個集合names 。而流卻什麽也沒有,現在我們應該能清楚感受到流是在內部叠代。也就是說流已經幫你做好了叠代。我們只要傳入相關的函數就可以得到想要的結果。至於內部叠代的好處,筆者沒有辦法親身的感受,唯一的感覺就是代碼變的簡單明了了。但是官方說Stream庫為了我們在內部叠代裏面做了很多優化和充公利用性能的操作。比如並行操作。所以筆者就聽官方了。

事實上,在用流的過程中,我們用到很多方法函數。比如上面的limit方法,filter方法等。這個定義為流操作。但是不管是什麽操作,你必須要有一個數據源吧。總結如下:

數據源:用於生成流的數據,比如集合。
流操作:類似於limit方法,filter方法。
流還有一種特點——部分流操作是沒有執行的。一般都是在collect函數執行的時候,才開始執行個個函數。所以我們可以細分一下流操作:

數據源:用於生成流的數據,比如集合。
中間操作:類似於limit方法,filter方法。這些操作做變了一個操作鏈,有一點流水線的概念。
終端操作:執行上面的操作鏈。比如collect函數。
從上面的講解我們就可以感覺流好像是先收集相關的目標操作,什麽意思呢?就是先把要做的事情計劃一下,最後一聲令下執行。而下這個命令是collect函數。這一點跟.NET的Linq是很像的。同時記得他只能執行一次。也就是說這個流執行一次之後,就不可能在用了。
筆者列一下以前的用到的函數

復制代碼
forEach:終端
collect:終端
count:終端
limit:中間
filter:中間
map:中間
sorted:中間
復制代碼
到目前為止我們用到的流都是通過集合來建一個流。筆者對此從來沒有講過。現在筆者來講些構建流的方式。
在stream庫裏面為我們提供了這樣子一個方法——Stream.of

復制代碼
package com.aomi;

import java.util.Optional;
import java.util.stream.Stream;

public class Main {

public static void main(String[] args) {
// TODO Auto-generated method stub

Stream stream = Stream.of("I", "am", "aomi");

Optional<String> firstWord = stream.findFirst();

if(firstWord.isPresent())
{
System.out.println("第一個字:"+firstWord.get());
}
}

}
復制代碼
運行結果:

去看一下of方法的代碼。如下

public static<T> Stream<T> of(T... values) {
return Arrays.stream(values);
}
說明我們可能指定一個類型來建一個流。上面可以修改為

Stream<String> stream = Stream.of("I", "am", "aomi");
findFirst函數用於表示返回第一個值。那就是可能數據源是一個空呢?所以他有可以會返回null。所以就是用一個叫Optional類的表示可以為空。這樣子我們就可以用Optional類的方法進一步做安全性的操作。比如判斷有沒有值(isPresent())
筆者想要建一個int類型的數組流玩玩。為了方便筆者便試給一下上面的代碼。卻發現報錯了。

如果我把int改為Integer呢?沒有問題了。所以註意要用引用類型的。int類型對應為Integer類型。

復制代碼
1 package com.aomi;
2
3 import java.util.Optional;
4 import java.util.stream.Stream;
5
6 public class Main {
7
8 public static void main(String[www.shengyunyule.cn] args) {
9 // TODO Auto-generated method stub
10
11 Stream<Integer> stream = Stream.of(1, 2, 9);
12
13 Optional<Integer> firstWord = stream.findFirst();
14
15 if(firstWord.isPresent(www.gaozhuoyiqi.com))
16 {
17 System.out.println("第一個字:"+firstWord.get());
18 }
19
20 }
21
22 }
復制代碼
運行結果:

那想要用int類型呢?什麽辦呢?改改

復制代碼
1 package com.aomi;
2
3 import java.util.OptionalInt;
4 import java.util.stream.IntStream;
5
6 public class Main {
7
8 public static void main(String[] args) {
9 // TODO Auto-generated method stub
10
11 IntStream stream = IntStream.of(1, 2, 9);
12
13 OptionalInt firstWord = stream.findFirst();
14
15 if(firstWord.isPresent())
16 {
17 System.out.println("第一個字:"+firstWord.getAsInt());
18 }
19
20 }
21
22 }
復制代碼
運行結果:

我們以上面的例子來一個猜測:是不是Double類型,只要修改為DoubleStream就行呢?試試。

復制代碼
1 package com.aomi;
2
3 import java.util.OptionalDouble;
4 import java.util.stream.DoubleStream;
5
6 public class Main {
7
8 public static void main(String[www.hengtongyoule.com] args) {
9 // TODO Auto-generated method stub
10
11 DoubleStream stream = DoubleStream.of(1.3, 2.3, 9.5);
12
13 OptionalDouble firstWord = stream.findFirst();
14
15 if(firstWord.isPresent())
16 {
17 System.out.println("第一個字:"+firstWord.getAsDouble());
18 }
19
20 }
21
22 }
復制代碼
運行結果:

結果很明顯,我們的猜測是對的。所以見意如果你操作的流是一個int或是double的話,請進可能的用XxxStream 來建流。這樣子在流的過程中不用進行拆裝和封裝了。必竟這是要性能的。在看一下如果數據源是一個數組的情況我們如何生成流呢?

復制代碼
1 public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,
2 CharSequence prefix,
3 CharSequence suffix) {
4 return new CollectorImpl<www.yongshiyule178.com>(
5 () -> new StringJoiner(delimiter, prefix, suffix),
6 StringJoiner::add, StringJoiner::merge,
7 StringJoiner::toString, CH_NOID);
8 }
復制代碼
在看一個叫toList函數的代碼。

復制代碼
1 public static <T>
2 Collector<T, ?, List<T>> toList(www.gouyiflb.cn) {
3 return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
4 (left, right) -> { left.addAll(right); return left; },
5 CH_ID);
6 }
復制代碼
我們發現他會共同的返回一個Collector類型。從上面我們就可以知道他的任務就是用去處理最後數據。我們把他定為收集器。讓我們看一下收集器的接口代碼吧;

復制代碼
1 public interface Collector<T, A, R> {
2
3 Supplier<A> supplier();
4
5 BiConsumer<A, T> accumulator();
6
7 BinaryOperator<A> combiner();
8
9 Function<A, R> finisher();
10
11 Set<Characteristics> characteristics();
12 }
復制代碼
光看前面四個方法是不是有一點熟悉的感覺。想要說明這個五個方法的作用。就必須明白一個概念——並行歸約。前面筆者講過流是一個內部叠代,也說Stream庫為我們做一個很多優化的事情。其中一個就是並行。他用到了JAVA 7引入的功能——分支/合並框架。也就是說流會以遞歸的方式拆分成很多子流,然後子流可以並行執行。最後在倆倆的子流的結果合並成一個最終結果。而這倆倆合並的行為就叫歸約 。如圖下。引用於《JAVA8實戰》

我們必須根據圖上的意思來走。子流的圖裏面會調用到Collector類的三個方法。

supplier方法:用創建數據存儲的地方。
accumulator方法:用於子流執行過程的叠代工作。即是遍歷每一項都會執行。所以可以這裏做一些工作。
finisher方法:返回最後的結果,你可以在這裏進一步處理結果。
每一個子流結束這之後,就是倆倆合並。這個時候就要看流的機制圖了。

combiner方法:會傳入每一個子流的結果過來,我們就可以在這裏在做一些工作。
finisher方法:返回最後的結果。同上面子流的一樣子。
好像沒有characteristics什麽事情。不是這樣子的。這個方法是用來說明當前這個流具備哪些優化。這樣子執行流的時候,就可以很清楚的知道要以什麽樣子的方式執行了。比如並行。
他是一個enum類。值如下

UNORDERED:這個表示執行過程中結果不受歸約和遍歷的影響
CONCURRENT:表示可以多個線和調用accumulator方法。並且可以執行並行。當然前無序數據的才並行。除非收集器標了UNORDERED。
IDENTITY_FINISH:表示這是一個恒等函數,就是做了結果也一樣子。不用做了可以跳過了。
由了上面的講說明,我們在來寫一個自己的收集器吧——去除相同的單詞
DistinctWordCollector類:

復制代碼
1 package com.aomi;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.EnumSet;
6 import java.util.List;
7 import java.util.Set;
8 import java.util.function.BiConsumer;
9 import java.util.function.BinaryOperator;
10 import java.util.function.Function;
11 import java.util.function.Supplier;
12 import java.util.stream.Collector;
13
14 public class DistinctWordCollector implements Collector<String, List<String>, List<String>> {
15
16 @Override
17 public Supplier<List<String>> supplier() {
18 // TODO Auto-generated method stub
19 return () -> new ArrayList<String>();
20 }
21
22 /**
23 * 子流的處理項的過程
24 */
25 @Override
26 public BiConsumer<List<String>, String> accumulator() {
27 // TODO Auto-generated method stub
28 return (List<String> src, String val) -> {
29
30 if (!src.contains(val)) {
31 src.add(val);
32 }
33 };
34 }
35
36 /**
37 * 倆倆並合的執行函數
38 */
39 @Override
40 public BinaryOperator<List<String>> combiner() {
41 // TODO Auto-generated method stub
42 return (List<String> src1, List<String> src2) -> {
43 for (String val www.yunshenpt.com: src2) {
44 if (!src1.contains(val)) {
45 src1.add(val);
46 }
47 }
48 return src1;
49 };
50 }
51
52 @Override
53 public Function<List<String>, List<String>> finisher() {
54 // TODO Auto-generated method stub
55 return Function.identity();
56 }
57
58 @Override
59 public Set<Characteristics> characteristics() {
60 // TODO Auto-generated method stub
61 return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH, Characteristics.CONCURRENT));

SpringBoot 從application.yml中通過@Value讀取不到屬性值