-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
3852 lines (3597 loc) · 984 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>Hello World</title>
<url>/2020/08/15/hello-world/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>
]]></content>
<categories>
<category>demo</category>
</categories>
<tags>
<tag>demo</tag>
</tags>
</entry>
<entry>
<title>cmake的使用记录</title>
<url>/2023/07/11/C_Learn/cmake%E7%9A%84%E4%BD%BF%E7%94%A8%E8%AE%B0%E5%BD%95/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>cmake 在 win 中的编译需要使用的一些配置,主要是记录曾经使用情况</p>
<h2 id="Release-生成PDB"><a href="#Release-生成PDB" class="headerlink" title="Release 生成PDB"></a>Release 生成PDB</h2><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi")</span><br><span class="line">set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")</span><br><span class="line">set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")</span><br></pre></td></tr></table></figure>
<p>cmake原生中的配置</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")</span><br><span class="line">set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")</span><br><span class="line">set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}")</span><br></pre></td></tr></table></figure>
<ul>
<li><p><code>CMAKE_CXX_FLAGS_RELEASE</code>: <code>/MD /O2 /Ob2 /DNDBUG </code></p>
</li>
<li><p><code>CMAKE_CXX_FLAGS_RELWITHDEBINFO</code>: <code>/MD /O2 /Ob1 /DNDBUG /Zi </code></p>
</li>
<li><p><code>CMAKE_SHARED_LINKER_FLAGS_RELEASE</code>: <code>/INCREMENTAL:NO</code></p>
</li>
<li><p><code>CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO</code>: <code>/debug /INCREMENTAL</code></p>
</li>
<li><p><code>/Zi</code>: 调试信息不包含在对象文件或可执行文件中,这使得这些文件最小</p>
</li>
<li><p><code>/MD</code>: 动态运行时依赖库, /MT 是静态运行时库</p>
</li>
<li><p><code>/O2</code>: O2 会尝试更多的寄存器级的优化以及指令级的优化,它会在编译期间占用更多的内存的编译时间</p>
</li>
<li><p><code>/O1</code>: O1 优化会消耗少得多的编译时间。主要对代码的分支,常量以及表达式等进行优化</p>
</li>
<li><p><code>/O3</code>: 在 O2 基础上进行更多的优化,例如使用伪寄存器网络,普通函数的内联以及针对循环的更多优化</p>
</li>
<li><p><code>/O0</code>: 不做任何优化,默认编译选项</p>
</li>
<li><p><code>/OPT:REF</code>: 清除从未引用的函数和数据</p>
</li>
<li><p><code>/OPT:ICF</code>: 从链接器中删除冗余的 COMAT</p>
</li>
<li><p><code>/INCREMENTAL</code>: debug 的情况下默认是这个选项</p>
</li>
</ul>
]]></content>
<categories>
<category>cmake</category>
</categories>
<tags>
<tag>cmake</tag>
</tags>
</entry>
<entry>
<title>opus编解码相关介绍</title>
<url>/2023/03/21/codec/opus%E7%BC%96%E8%A7%A3%E7%A0%81%E7%9B%B8%E5%85%B3%E4%BB%8B%E7%BB%8D/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>本文主要讲解在实际开发中遇到的关于Opus的编解码问题</p>
<h2 id="SDP中OPUS介绍"><a href="#SDP中OPUS介绍" class="headerlink" title="SDP中OPUS介绍"></a>SDP中OPUS介绍</h2><p>在 SDP 中,任何其它采样率都不起作用,在 rtp 传输时默认采用 48000, 可以在 <a href="https://www.rfc-editor.org/rfc/rfc7587">rfc7587 Section 4.1</a> 中查看<br>如下所示:</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Opus supports 5 different audio bandwidths, which can be adjusted</span><br><span class="line">during a stream. The RTP timestamp is incremented with a 48000 Hz</span><br><span class="line">clock rate for all modes of Opus and all sampling rates. The unit</span><br><span class="line">for the timestamp is samples per single (mono) channel. The RTP</span><br><span class="line">timestamp corresponds to the sample time of the first encoded sample</span><br><span class="line">in the encoded frame. For data encoded with sampling rates other</span><br><span class="line">than 48000 Hz, the sampling rate has to be adjusted to 48000 Hz.</span><br></pre></td></tr></table></figure>
<p>如果想要降低带宽,那么可以使用 <code>maxplaybackrate</code> 和 <code>maxaveragebitrate </code>,标准文档如下所示</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">3.1.1. Recommended Bitrate</span><br><span class="line"></span><br><span class="line"> For a frame size of 20 ms, these are the bitrate "sweet spots" for Opus in various configurations:</span><br><span class="line"></span><br><span class="line"> o 8-12 kbit/s for NB speech,</span><br><span class="line"> o 16-20 kbit/s for WB speech,</span><br><span class="line"> o 28-40 kbit/s for FB speech,</span><br><span class="line"> o 48-64 kbit/s for FB mono music, and</span><br><span class="line"> o 64-128 kbit/s for FB stereo music.</span><br></pre></td></tr></table></figure>
<p>例如:如果想要使用 8000HZ 的 OPUS,那么 SDP 应该如下所示:</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">m=audio 54312 RTP/AVP 101</span><br><span class="line">a=rtpmap:101 opus/48000/2</span><br><span class="line">a=fmtp:101 maxplaybackrate=8000; sprop-maxcapturerate=8000; maxaveragebitrate=12000</span><br></pre></td></tr></table></figure>
<h2 id="WebRTC-中非对称采样率工作"><a href="#WebRTC-中非对称采样率工作" class="headerlink" title="WebRTC 中非对称采样率工作"></a>WebRTC 中非对称采样率工作</h2><p>WebRTC 支持通信双方以非对称采样率工作。比如:A和B通话,A的采样率为48000,B的采样率为8000。如下所示</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">A-->B OfferSDP</span><br><span class="line">a=rtpmap:111 opus/48000/2</span><br><span class="line">a=rtcp-fb:111 transport-cc</span><br><span class="line">a=fmtp:111 minptime=10;useinbandfec=1;maxplaybackrate=16000</span><br></pre></td></tr></table></figure>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">B-->A AnswerSDP</span><br><span class="line">a=rtpmap:111 opus/48000/2</span><br><span class="line">a=rtcp-fb:111 transport-cc</span><br><span class="line">a=fmtp:111 minptime=10;useinbandfec=1;maxplaybackrate=48000</span><br></pre></td></tr></table></figure>
<p>最终,A 采样率为48000,B 采用率为 16000</p>
<h2 id="WebRTC-中声道数与编码器的关系"><a href="#WebRTC-中声道数与编码器的关系" class="headerlink" title="WebRTC 中声道数与编码器的关系"></a>WebRTC 中声道数与编码器的关系</h2><p>当声道数 2 时,OPUS 编码内部将使用 celt ,代码如下:</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="comment">///FIXME 暂时未查阅到</span></span><br><span class="line">config.application = config.num_channels == <span class="number">1</span> ? AudioEncoderOpus::kVoip : AudioEncoderOpus::kAudio;</span><br></pre></td></tr></table></figure>
<h2 id="OPUS编解码"><a href="#OPUS编解码" class="headerlink" title="OPUS编解码"></a>OPUS编解码</h2><p>OPUS代码的时候使用 <a href="https://github.com/xiph/opus">opus</a> 进行编解码,可以使用 <code>opus/doc/trivial_example.c</code> 进行测试</p>
<h2 id="引用"><a href="#引用" class="headerlink" title="引用"></a>引用</h2><p><a href="https://stackoverflow.com/questions/60580526/linphone-opus-codec-sampling-rate">Linphone opus codec sampling rate</a></p>
]]></content>
<categories>
<category>codec</category>
</categories>
<tags>
<tag>opus</tag>
</tags>
</entry>
<entry>
<title>C与FS中内存分配简析</title>
<url>/2021/06/03/freeswitch/C%E4%B8%8EFS%E4%B8%AD%E5%86%85%E5%AD%98%E5%88%86%E9%85%8D%E7%AE%80%E6%9E%90/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>本文将会讲解C标准库中内存分配在不同平台的不同实现方式,以及fs对标准的一个工具化封装。主要是对fs的内存分配有一个简单的认识。</p>
<h2 id="C中的内存分配"><a href="#C中的内存分配" class="headerlink" title="C中的内存分配"></a>C中的内存分配</h2><p>C中的内存分配主要有以下三个方法。此处只是对其做简单的介绍,我发现一篇文章写得很好,可以阅读<a href="https://blog.csdn.net/weibo1230123/article/details/81503135">calloc、malloc、realloc函数的区别及用法!</a>一文</p>
<ul>
<li><p><code>malloc</code>:其原型为<code>void *malloc(unsigned int num_bytes)</code>,其中此处的num_bytes不是Bytes,所以需要将c语言中的基础类型<code>sizeof</code>求值</p>
</li>
<li><p><code>calloc</code>:其原型为<code>void *calloc(size_t n, size_t size)</code>,这个本质还是malloc进行分配,分配完后并进行了初始化。可以看引用中<a href="https://www.cnblogs.com/mfrbuaa/p/5383026.html">malloc和calloc的差别</a>一文</p>
</li>
<li><p><code>realloc</code>:其原型为<code>void *realloc(void *ptr, size_t new_Size)</code>,就是对空间进行扩充。扩充过程中如果比较大,那么会重新开辟空间并将原来空间内容拷贝过去,并将以前的空间释放。此处的大以系统为准,在以前的地址申请,如果能够申请那么大就直接返回以前的地址。</p>
<blockquote>
<p> 注意:ptr不能NULL</p>
</blockquote>
</li>
</ul>
<h2 id="引用"><a href="#引用" class="headerlink" title="引用"></a>引用</h2><p><a href="https://www.cnblogs.com/mfrbuaa/p/5383026.html">malloc和calloc的差别</a></p>
<p><a href="https://blog.csdn.net/weibo1230123/article/details/81503135">calloc、malloc、realloc函数的区别及用法!</a></p>
]]></content>
<categories>
<category>freeswitch</category>
</categories>
<tags>
<tag>内存分配</tag>
</tags>
</entry>
<entry>
<title>FreeSWITCH中mod的状态变化</title>
<url>/2023/03/23/freeswitch/FreeSWITCH%E4%B8%ADmod%E7%9A%84%E7%8A%B6%E6%80%81%E5%8F%98%E5%8C%96/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>本文主要讲述在 endpoint 的 mod 在启动关闭与呼叫、挂断等其中的状态变化内容</p>
<h2 id="mod-的启动关闭"><a href="#mod-的启动关闭" class="headerlink" title="mod 的启动关闭"></a>mod 的启动关闭</h2><p>此处的状态变化最为简单,只有两个回调函数,分别如下所示:</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line">SWITCH_MODULE_LOAD_FUNCTION(mod_test_load);</span><br><span class="line">SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_test_shutdown);</span><br><span class="line">SWITCH_MODULE_DEFINITION(mod_test, mod_test_load, mod_test_shutdown, <span class="literal">NULL</span>); <span class="comment">// mod_test_runtime</span></span><br></pre></td></tr></table></figure>
<p>一般 runtime 都没用,暂时不明白作用。有个这个定义后,再实现相应的启动关闭函数,如下所示:</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line">SWITCH_MODULE_LOAD_FUNCTION(mod_test_load) {</span><br><span class="line"> <span class="comment">/// 你想要实现内容,宏展开后有如下参数</span></span><br><span class="line"> <span class="comment">/// switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool</span></span><br><span class="line">}</span><br><span class="line">SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_janus_shutdown) {</span><br><span class="line"> <span class="comment">/// 你想要实现内容,宏展开后是个 void,没有参数值</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="channel-的状态变化"><a href="#channel-的状态变化" class="headerlink" title="channel 的状态变化"></a>channel 的状态变化</h2><p>channel 的状态变化较为复杂,此处先沿着外呼的流程走一遍所有流程,并会标明调用什么函数发生状态变化,以及状态变化涉及的含义。</p>
<p>此处先展示所有涉及的状态以及它们分别所属结构体</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="keyword">switch_state_handler_table_t</span> test_state_handlers = {</span><br><span class="line"> <span class="comment">/*.on_init */</span> channel_on_init,</span><br><span class="line"> <span class="comment">/*.on_routing */</span> channel_on_routing,</span><br><span class="line"> <span class="comment">/*.on_execute */</span> channel_on_execute,</span><br><span class="line"> <span class="comment">/*.on_hangup */</span> channel_on_hangup,</span><br><span class="line"> <span class="comment">/*.on_exchange_media */</span> channel_on_exchange_media,</span><br><span class="line"> <span class="comment">/*.on_soft_execute */</span> channel_on_soft_execute,</span><br><span class="line"> <span class="comment">/*.on_consume_media */</span> <span class="literal">NULL</span>,</span><br><span class="line"> <span class="comment">/*.on_hibernate */</span> <span class="literal">NULL</span>,</span><br><span class="line"> <span class="comment">/*.on_reset */</span> <span class="literal">NULL</span>,</span><br><span class="line"> <span class="comment">/*.on_park */</span> <span class="literal">NULL</span>,</span><br><span class="line"> <span class="comment">/*.on_reporting */</span> <span class="literal">NULL</span>,</span><br><span class="line"> <span class="comment">/*.on_destroy */</span> channel_on_destroy};</span><br><span class="line"></span><br><span class="line"><span class="keyword">switch_io_routines_t</span> test_io_routines = {</span><br><span class="line"> <span class="comment">/*.outgoing_channel */</span> channel_outgoing_channel,</span><br><span class="line"> <span class="comment">/*.read_frame */</span> channel_read_frame,</span><br><span class="line"> <span class="comment">/*.write_frame */</span> channel_write_frame,</span><br><span class="line"> <span class="comment">/*.kill_channel */</span> channel_kill_channel,</span><br><span class="line"> <span class="comment">/*.send_dtmf */</span> channel_send_dtmf,</span><br><span class="line"> <span class="comment">/*.receive_message */</span> channel_receive_message,</span><br><span class="line"> <span class="comment">/*.receive_event */</span> channel_receive_event};</span><br><span class="line"></span><br><span class="line"><span class="comment">//...</span></span><br><span class="line"></span><br><span class="line">test_endpoint_interface->io_routines = &test_io_routines;</span><br><span class="line">test_endpoint_interface->state_handler = &test_state_handlers;</span><br></pre></td></tr></table></figure>
<ul>
<li><p>外呼 –> channel_outgoing_channel:</p>
<ul>
<li><p>参数如下所示:</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">switch_call_cause_t</span> <span class="title">channel_outgoing_channel</span><span class="params">(<span class="keyword">switch_core_session_t</span> *session, <span class="keyword">switch_event_t</span> *var_event,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">switch_caller_profile_t</span> *outbound_profile,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">switch_core_session_t</span> **new_session, <span class="keyword">switch_memory_pool_t</span> **pool,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">switch_originate_flag_t</span> flags, <span class="keyword">switch_call_cause_t</span> *cancel_cause)</span> </span>{</span><br><span class="line"></span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
</li>
<li><p>作用:创建媒体流、创建channel、初始化参数等</p>
</li>
<li><p>状态变化函数:<code>switch_channel_set_state(channel, CS_INIT);</code></p>
</li>
<li><p>未知作用函数:<code>switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND);</code></p>
</li>
</ul>
</li>
<li><p>channel_outgoing_channel –> channel_on_init:</p>
<ul>
<li><p>参数如下所示:</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">switch_status_t</span> <span class="title">channel_on_init</span><span class="params">(<span class="keyword">switch_core_session_t</span> *session)</span></span></span><br></pre></td></tr></table></figure>
</li>
<li><p>作用:一般用户初始化该通呼叫所需要的一些初始化参数</p>
</li>
<li><p>返回值:状态值为 <code>SWITCH_STATUS_SUCCESS</code> 将自动进入下个状态,否则将跳过该此呼叫</p>
</li>
<li><p>状态变化函数:无</p>
</li>
<li><p>未知作用函数:<code>switch_set_flag_locked(tech_pvt, TFLAG_IO);</code></p>
</li>
</ul>
</li>
<li><p>channel_on_init –> channel_on_routing:</p>
<ul>
<li><p>参数如下所示:</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">switch_status_t</span> <span class="title">channel_on_routing</span><span class="params">(<span class="keyword">switch_core_session_t</span> *session)</span></span></span><br></pre></td></tr></table></figure>
</li>
<li><p>作用:一般在此处进行路由相关处理,准备编解码器、创建媒体流端口、生成sdp并与被叫方建立连接等工作</p>
</li>
<li><p>返回值:状态值为 <code>SWITCH_STATUS_SUCCESS</code> 将自动进入下个状态,否则将跳过该此呼叫</p>
</li>
<li><p>状态变化函数:<code>switch_channel_pre_answer(channel)</code> 和 <code>switch_channel_answer(channel)</code></p>
</li>
<li><p>未知作用函数:<code>switch_channel_set_flag(channel, CF_AUDIO);</code></p>
</li>
</ul>
</li>
<li><p>channel_on_routing –> channel_on_execute: (可略)</p>
</li>
<li><p>channel_on_hangup:</p>
<ul>
<li><p>参数如下所示:</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">switch_status_t</span> <span class="title">channel_on_hangup</span><span class="params">(<span class="keyword">switch_core_session_t</span> *session)</span></span></span><br></pre></td></tr></table></figure>
</li>
<li><p>作用:呼叫中断的时候,此处的函数就会被回调,无论是 a-leg 还是 b-leg, 一般用于销毁信令上的一些内容</p>
</li>
<li><p>返回值:状态值为 <code>SWITCH_STATUS_SUCCESS</code> 将自动进入下个状态,否则将跳过该此呼叫</p>
</li>
<li><p>状态变化函数:<code>switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);</code></p>
</li>
</ul>
</li>
<li><p>channel_on_hangup –> channel_on_destroy:</p>
<ul>
<li><p>参数如下所示:</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">switch_status_t</span> <span class="title">channel_on_destroy</span><span class="params">(<span class="keyword">switch_core_session_t</span> *session)</span></span></span><br></pre></td></tr></table></figure>
</li>
<li><p>作用:在呼叫被 hangup 完成后被回调,用于销毁初始化的媒体流、端口等</p>
</li>
<li><p>返回值:状态值为 <code>SWITCH_STATUS_SUCCESS</code> 将自动进入下个状态,否则将跳过该此呼叫</p>
</li>
</ul>
</li>
</ul>
]]></content>
<categories>
<category>FreeSWTICH</category>
</categories>
<tags>
<tag>channels</tag>
</tags>
</entry>
<entry>
<title>FreeSWITCH中管理依赖下载方式</title>
<url>/2022/01/23/freeswitch/FreeSWITCH%E4%B8%AD%E7%AE%A1%E7%90%86%E4%BE%9D%E8%B5%96%E4%B8%8B%E8%BD%BD%E6%96%B9%E5%BC%8F/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>由于本人不是纯正的 VS 开发人员,本人一直很疑惑 FreeSWITCH 是如何管理它的所有依赖下载的,<br>以及下载后的依赖如何编译进入 FreeSWWITCH 的整体项目中的。</p>
<p>因而这里记录下在我实际开发过程中,发现的 FreeSWITCH 的管理依赖的方式。</p>
<h2 id="依赖下载"><a href="#依赖下载" class="headerlink" title="依赖下载"></a>依赖下载</h2><p>我们首先要确定 FreeSWITCH 都有哪些依赖内容,他们的依赖内容是什么样子的。</p>
<p>FreeSWITCH 依赖的都是例如 ffmpeg、libyuv 等这种成熟的项目,因而肯定需要从外部进行下载,<br>这些从外部的下载肯定有具体的配置位置。</p>
<p>开发中发现本地的依赖项目都是通过 vs 的属性管理器进行依赖管理,这个属于 vs 的依赖管理,因而很容易<br>就思考到是否也是采用同样的方式进行远程的这种依赖。</p>
<p>那么,我们就要在属性管理器中看下这些依赖是否在这里配置,很显然属性配置器中无法看到具体的下载内容。<br>我们立即想到去看源文件。</p>
<p>最终,我们可以在 w32 中发现各种标有 download 开头的 props 文件,直接打开文件就可以看到里面的<br>带有 http 下载链接的属性</p>
<h2 id="依赖如何打包进-FS-中"><a href="#依赖如何打包进-FS-中" class="headerlink" title="依赖如何打包进 FS 中"></a>依赖如何打包进 FS 中</h2><p>从上面我们已经知道了 FS 中的依赖下载,下面我们来看下 FS 是如何将第三方内容依赖进 FS 中的</p>
]]></content>
<categories>
<category>FreeSWTICH</category>
</categories>
<tags>
<tag>依赖</tag>
</tags>
</entry>
<entry>
<title>FreeSWITCH中xml_rpc的使用技巧</title>
<url>/2023/03/27/freeswitch/FreeSWITCH%E4%B8%ADxml-rpc%E7%9A%84%E4%BD%BF%E7%94%A8%E6%8A%80%E5%B7%A7/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>本文主要讲解在实际开发中,可能遇到的使用 xml_rpc 命令过程中的一些内容</p>
<h2 id="查询-api-的命令"><a href="#查询-api-的命令" class="headerlink" title="查询 api 的命令"></a>查询 api 的命令</h2><p>查看 xml_rpc 中的命令通过如下方式即可,在浏览器中打开如下链接:<code>http://127.0.0.1:8080/webapi/help</code></p>
<h2 id="调试命令"><a href="#调试命令" class="headerlink" title="调试命令"></a>调试命令</h2><ul>
<li>通过 curl 调用 lua 程序,并传递参数,其中空格需要用 %20 替换 <figure class="highlight shell"><figcaption><span>script</span></figcaption><table><tr><td class="code"><pre><span class="line">curl --user yw:yw@123 http://127.0.0.1:7652/webapi/luarun?call_phone.lua%20var</span><br></pre></td></tr></table></figure></li>
<li></li>
</ul>
]]></content>
<categories>
<category>FreeSWTICH</category>
</categories>
<tags>
<tag>xml_rpc</tag>
</tags>
</entry>
<entry>
<title>FreeSWITCH在Linux下编译模块编译</title>
<url>/2023/03/22/freeswitch/FreeSWITCH%E5%9C%A8Linux%E4%B8%8B%E7%BC%96%E8%AF%91%E6%A8%A1%E5%9D%97%E7%BC%96%E8%AF%91/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>本文主要讲解在 Linux 环境下编译 FreeSWITCH 模块时的配置以及所遇到的问题</p>
<h2 id="Linux-下编译-MOD-的配置"><a href="#Linux-下编译-MOD-的配置" class="headerlink" title="Linux 下编译 MOD 的配置"></a>Linux 下编译 MOD 的配置</h2><ul>
<li>在 configure.ac 中配置需要编译模块的 makefile文件,例如:src/mod/endpoints/mod_verto/Makefile <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">PKG_CHECK_MODULES([HIREDIS], [hiredis >= 0.10.0],[</span><br><span class="line">AM_CONDITIONAL([HAVE_HIREDIS],[true])],[</span><br><span class="line">AC_MSG_RESULT([no]); AM_CONDITIONAL([HAVE_HIREDIS],[false])])</span><br><span class="line"></span><br><span class="line">PKG_CHECK_MODULES([REDIS_PLUS], [redis++ >= 1.3.10],[</span><br><span class="line">AM_CONDITIONAL([HAVE_REDIS_PLUS],[true])],[</span><br><span class="line">AC_MSG_RESULT([no]); AM_CONDITIONAL([HAVE_REDIS_PLUS],[false])])</span><br><span class="line"></span><br><span class="line">src/mod/applications/mod_redis_plus/Makefile</span><br></pre></td></tr></table></figure></li>
<li>在 modules.conf 中配置允许编译的模块,例如:endpoints/mod_verto</li>
<li>运行 <code>autoreconf -fiv</code> 重新生成 m4 文件</li>
<li>通过 rebootstrap.sh or bootstrap.sh 重新生成 configure 编译文件</li>
</ul>
<h2 id="关于-Linux-下模块的-Makefile-am-编写事项"><a href="#关于-Linux-下模块的-Makefile-am-编写事项" class="headerlink" title="关于 Linux 下模块的 Makefile.am 编写事项"></a>关于 Linux 下模块的 Makefile.am 编写事项</h2><h2 id="失败问题总结"><a href="#失败问题总结" class="headerlink" title="失败问题总结"></a>失败问题总结</h2><ul>
<li>无法生成 Makefile.in 文件<ul>
<li>注意模块位置不要写错了,否则无法生成</li>
</ul>
</li>
</ul>
]]></content>
<categories>
<category>FreeSWTICH</category>
</categories>
<tags>
<tag>mod</tag>
</tags>
</entry>
<entry>
<title>FreeSWITCH问题分析</title>
<url>/2023/04/27/freeswitch/FreeSWITCH%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>本文主要讲解在实际运维过程中容易出现的问题现象以及导致其出现问题的根本原因,可能附带有解决方法</p>
<h2 id="30s挂断"><a href="#30s挂断" class="headerlink" title="30s挂断"></a>30s挂断</h2><p>呼叫通没问题,但是会出现 30s 挂断。一般原因有以下几个方面:</p>
<ul>
<li>外网端口与内网端口没有一对一映射:端口错误,导致客户端与 FS 的沟通出现网络无法连接问题,可能是 ACK 问题。<ul>
<li>解决方案:将接口一对一映射</li>
</ul>
</li>
</ul>
<h2 id="FS与opensip使用tls对接时,2分钟-tcp-断连"><a href="#FS与opensip使用tls对接时,2分钟-tcp-断连" class="headerlink" title="FS与opensip使用tls对接时,2分钟 tcp 断连"></a>FS与opensip使用tls对接时,2分钟 tcp 断连</h2><p>opensips 本身有个参数 <code>tcp_connection_lifetime</code> 用于控制 tcp 的存活时长,此存活时长只能通过与服务端发送数据来延长时间,无法通过 tcp 本身的 <code>keepalive</code> 来进行保活。</p>
<p>最后,必须通过 fs 端发送 option 来延长 tcp 的存活时间。<br>想要实现在通话中发送 option,那么必须使用 gateway ,并在 gateway 中配置 <code>ping</code> 来发送 option。</p>
<p>其中,option 存在问题还没开始通话就有 option 进行发送,其中的端口与通话的端口有什么关系呢?根据抓包发现:当前没通话,有新的呼叫创建情况下,有option,那就直接用option的端口。因而网关的option没通话时的option与新来通话后的option是同一个端口。</p>
<blockquote>
<p>注意:目前仅仅测试通过了 fs 作为 fresher 进行刷新保活,服务器作为 refresher 时,其 update 无法发送到 fs</p>
</blockquote>
<h2 id="修改FS的contact"><a href="#修改FS的contact" class="headerlink" title="修改FS的contact"></a>修改FS的contact</h2><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"><param name="apply-nat-acl" value="nat.auto"/></span><br><span class="line"><action application="export" data="sip_contact_user=${sip_from_user}" /></span><br></pre></td></tr></table></figure>
<h2 id="FS-修改由客户端刷新-session"><a href="#FS-修改由客户端刷新-session" class="headerlink" title="FS 修改由客户端刷新 session"></a>FS 修改由客户端刷新 session</h2><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">param</span> <span class="attr">name</span>=<span class="string">"enable-timer"</span> <span class="attr">value</span>=<span class="string">"true"</span>/></span></span><br><span class="line"><span class="tag"><<span class="name">param</span> <span class="attr">name</span>=<span class="string">"session-timeout"</span> <span class="attr">value</span>=<span class="string">"1800"</span>/></span></span><br></pre></td></tr></table></figure>
<h2 id="FS-修改语音舒适噪音问题"><a href="#FS-修改语音舒适噪音问题" class="headerlink" title="FS 修改语音舒适噪音问题"></a>FS 修改语音舒适噪音问题</h2><p>防止hold后一直播放铃音,导致无法unhold。sdp 中也有 cng 相关配置,具体请看 sdp</p>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">param</span> <span class="attr">name</span>=<span class="string">"suppress-cng"</span> <span class="attr">value</span>=<span class="string">"true"</span>/></span></span><br></pre></td></tr></table></figure>
<h2 id="FS-回复指定的SIP错误信息"><a href="#FS-回复指定的SIP错误信息" class="headerlink" title="FS 回复指定的SIP错误信息"></a>FS 回复指定的SIP错误信息</h2><pre><code class="lua">local response_code = "500" -- 响应码为500,表示Internal Server Error
local reason_phrase = "Internal Server Error" -- 响应原因短语
session:execute("respond", response_code .. " " .. reason_phrase)
···</code></pre>
]]></content>
<categories>
<category>FreeSWTICH</category>
</categories>
<tags>
<tag>Question</tag>
</tags>
</entry>
<entry>
<title>FreeSWITCH解析originate命令</title>
<url>/2022/01/20/freeswitch/FreeSWITCH%E8%A7%A3%E6%9E%90originate%E5%91%BD%E4%BB%A4/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>我们在实现任何外部呼叫能力的时候无论如何都绕不开 originate 命令或者说 bridge。</p>
<p>当然为了简单起见,我这里先跟着 originate 进行源代码分析。 </p>
<h2 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h2><table>
<thead>
<tr>
<th>环境名</th>
<th>版本</th>
</tr>
</thead>
<tbody><tr>
<td>WIN</td>
<td>WIN10</td>
</tr>
<tr>
<td>FS</td>
<td>1.10.0</td>
</tr>
<tr>
<td>VS</td>
<td>vs2017</td>
</tr>
</tbody></table>
<h2 id="originate-function"><a href="#originate-function" class="headerlink" title="originate_function"></a><code>originate_function</code></h2><p>mod_commands 这个模块,集成 FreeSWITCH 大部分的命令,而 originate 命令就是其中的一个命令。位于 mod_commands.c 中,</p>
<p>其中代码如下 :</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> ORIGINATE_SYNTAX \</span></span><br><span class="line"> <span class="string">"<call url> <exten>|&<application_name>(<app_args>) [<dialplan>] [<context>] [<cid_name>] [<cid_num>] "</span> \</span><br><span class="line"> <span class="string">"[<timeout_sec>]"</span></span><br><span class="line">SWITCH_STANDARD_API(originate_function)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">switch_channel_t</span> *caller_channel;</span><br><span class="line"> <span class="keyword">switch_core_session_t</span> *caller_session = <span class="literal">NULL</span>;</span><br><span class="line"> <span class="comment">// 定义解析命令参数的内容</span></span><br><span class="line"> <span class="keyword">char</span> *mycmd = <span class="literal">NULL</span>, *argv[<span class="number">10</span>] = {<span class="number">0</span>};</span><br><span class="line"> <span class="keyword">int</span> i = <span class="number">0</span>, x, argc = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">char</span> *aleg, *exten, *dp, *context, *cid_name, *cid_num;</span><br><span class="line"> <span class="keyword">uint32_t</span> timeout = <span class="number">60</span>;</span><br><span class="line"> <span class="keyword">switch_call_cause_t</span> cause = SWITCH_CAUSE_NORMAL_CLEARING;</span><br><span class="line"> <span class="keyword">switch_status_t</span> status = SWITCH_STATUS_SUCCESS;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (zstr(cmd)) {</span><br><span class="line"> stream->write_function(stream, <span class="string">"-USAGE: %s\n"</span>, ORIGINATE_SYNTAX);</span><br><span class="line"> <span class="keyword">return</span> SWITCH_STATUS_SUCCESS;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 判断是否曾经已经建立过连接(此处 session 是通过 SWITCH_STANDARD_API 扩展函数名得到)</span></span><br><span class="line"> <span class="comment">/* log warning if part of ongoing session, as we'll block the session */</span></span><br><span class="line"> <span class="keyword">if</span> (session) {</span><br><span class="line"> switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE,</span><br><span class="line"> <span class="string">"Originate can take 60 seconds to complete, and blocks the existing session. Do not confuse "</span></span><br><span class="line"> <span class="string">"with a lockup.\n"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 拷贝命令行参数并根据空格进行字符串分割</span></span><br><span class="line"> mycmd = strdup(cmd);</span><br><span class="line"> switch_assert(mycmd);</span><br><span class="line"> argc = switch_separate_string(mycmd, <span class="string">' '</span>, argv, (<span class="keyword">sizeof</span>(argv) / <span class="keyword">sizeof</span>(argv[<span class="number">0</span>])));</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (argc < <span class="number">2</span> || argc > <span class="number">7</span>) {</span><br><span class="line"> stream->write_function(stream, <span class="string">"-USAGE: %s\n"</span>, ORIGINATE_SYNTAX);</span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (x = <span class="number">0</span>; x < argc && argv[x]; x++) {</span><br><span class="line"> <span class="keyword">if</span> (!strcasecmp(argv[x], <span class="string">"undef"</span>)) { argv[x] = <span class="literal">NULL</span>; }</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 参数赋值到变量中</span></span><br><span class="line"> aleg = argv[i++];</span><br><span class="line"> exten = argv[i++];</span><br><span class="line"> dp = argv[i++];</span><br><span class="line"> context = argv[i++];</span><br><span class="line"> cid_name = argv[i++];</span><br><span class="line"> cid_num = argv[i++];</span><br><span class="line"></span><br><span class="line"> switch_assert(exten);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!dp) { dp = <span class="string">"XML"</span>; }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!context) { context = <span class="string">"default"</span>; }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (argv[<span class="number">6</span>]) { timeout = atoi(argv[<span class="number">6</span>]); }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 发起呼叫</span></span><br><span class="line"> <span class="keyword">if</span> (switch_ivr_originate(<span class="literal">NULL</span>, &caller_session, &cause, aleg, timeout, <span class="literal">NULL</span>, cid_name, cid_num, <span class="literal">NULL</span>, <span class="literal">NULL</span>,</span><br><span class="line"> SOF_NONE, <span class="literal">NULL</span>, <span class="literal">NULL</span>) != SWITCH_STATUS_SUCCESS ||</span><br><span class="line"> !caller_session) {</span><br><span class="line"> stream->write_function(stream, <span class="string">"-ERR %s\n"</span>, switch_channel_cause2str(cause));</span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> caller_channel = switch_core_session_get_channel(caller_session);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 如果参数中包含 & ,表明是命令形式,那么将命令的解析。否则将进行 session 转移</span></span><br><span class="line"> <span class="keyword">if</span> (*exten == <span class="string">'&'</span> && *(exten + <span class="number">1</span>)) {</span><br><span class="line"> <span class="keyword">switch_caller_extension_t</span> *extension = <span class="literal">NULL</span>;</span><br><span class="line"> <span class="keyword">char</span> *app_name = switch_core_session_strdup(caller_session, (exten + <span class="number">1</span>));</span><br><span class="line"> <span class="keyword">char</span> *arg = <span class="literal">NULL</span>, *e;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ((e = <span class="built_in">strchr</span>(app_name, <span class="string">')'</span>))) { *e = <span class="string">'\0'</span>; }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ((arg = <span class="built_in">strchr</span>(app_name, <span class="string">'('</span>))) { *arg++ = <span class="string">'\0'</span>; }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ((extension = switch_caller_extension_new(caller_session, app_name, arg)) == <span class="number">0</span>) {</span><br><span class="line"> switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, <span class="string">"Memory Error!\n"</span>);</span><br><span class="line"> <span class="built_in">abort</span>();</span><br><span class="line"> }</span><br><span class="line"> switch_caller_extension_add_application(caller_session, extension, app_name, arg);</span><br><span class="line"> switch_channel_set_caller_extension(caller_channel, extension);</span><br><span class="line"> switch_channel_set_state(caller_channel, CS_EXECUTE);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> switch_ivr_session_transfer(caller_session, exten, dp, context);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> stream->write_function(stream, <span class="string">"+OK %s\n"</span>, switch_core_session_get_uuid(caller_session));</span><br><span class="line"></span><br><span class="line"> switch_core_session_rwunlock(caller_session);</span><br><span class="line"></span><br><span class="line">done:</span><br><span class="line"> switch_safe_free(mycmd);</span><br><span class="line"> <span class="keyword">return</span> status;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>上诉函数主要做了两件事情,其一:解析命令参数,其二:根据命令参数发起呼叫。</p>
<ul>
<li>解析命令参数:参数的赋值这里不做赘述,这里简单描述下各个参数的含义,帮助初学者理解 <figure class="highlight c"><table><tr><td class="code"><pre><span class="line">aleg = argv[i++]; <span class="comment">// aleg 就是呼叫 url。例如:sofia/internal/[email protected]</span></span><br><span class="line">exten = argv[i++]; <span class="comment">// exten 是 session 转移的参数或者其它命令配置。</span></span><br><span class="line"> <span class="comment">// 其中 session 转移是修改呼叫方的 caller_number</span></span><br><span class="line"> <span class="comment">// 至于其它命令可以参考 &hold()</span></span><br><span class="line">dp = argv[i++]; <span class="comment">// 呼叫形式: 对应与 mod_dialplan_xml、mod_dialplan_directory、mod_dialplan_asterisk</span></span><br><span class="line">context = argv[i++]; <span class="comment">// context 一般对应 config/dialplan 中的 default 或 public</span></span><br><span class="line">cid_name = argv[i++]; <span class="comment">// 呼叫方显示到被叫方的名字</span></span><br><span class="line">cid_num = argv[i++]; <span class="comment">// 呼叫方显示到被叫方的号码</span></span><br></pre></td></tr></table></figure></li>
<li>根据命令参数发发起呼叫:这里的主要执行是 <code>switch_ivr_originate()</code> 函数,通过此函数我们获取到一个通话的 session。<br>下面我将详细讲解此函数中执行内容。</li>
</ul>
<h2 id="switch-ivr-originate"><a href="#switch-ivr-originate" class="headerlink" title="switch_ivr_originate"></a><code>switch_ivr_originate</code></h2><p>此函数位于 switch_ivr_originate.c 中,此函数的实现内容为发起呼叫的功能,这其中的代码非常复杂。</p>
<p>这里分成各个阶段分别分析其中的内容。</p>
<h3 id="传入参数"><a href="#传入参数" class="headerlink" title="传入参数"></a>传入参数</h3><p>以下是此函数的传入参数的解释,主要位于 switch_ivr.h 中:</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">/*!</span></span><br><span class="line"><span class="comment"> \brief Make an outgoing call</span></span><br><span class="line"><span class="comment"> \param session originating session</span></span><br><span class="line"><span class="comment"> \param bleg B leg session</span></span><br><span class="line"><span class="comment"> \param cause a pointer to hold call cause</span></span><br><span class="line"><span class="comment"> \param bridgeto the desired remote callstring</span></span><br><span class="line"><span class="comment"> \param timelimit_sec timeout in seconds for outgoing call</span></span><br><span class="line"><span class="comment"> \param table optional state handler table to install on the channel</span></span><br><span class="line"><span class="comment"> \param cid_name_override override the caller id name</span></span><br><span class="line"><span class="comment"> \param cid_num_override override the caller id number</span></span><br><span class="line"><span class="comment"> \param caller_profile_override override the entire calling caller profile</span></span><br><span class="line"><span class="comment"> \param ovars variables to be set on the outgoing channel</span></span><br><span class="line"><span class="comment"> \param flags flags to pass</span></span><br><span class="line"><span class="comment"> \return SWITCH_STATUS_SUCCESS if bleg is a running session.</span></span><br><span class="line"><span class="comment"> \note bleg will be read locked which must be unlocked with switch_core_session_rwunlock() before losing scope</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="comment">/*!</span></span><br><span class="line"><span class="comment"> \brief 往外发起呼叫</span></span><br><span class="line"><span class="comment"> \param 正在发起会话的会话,可以简单理解为 a-leg,如果没有 a-leg 传入 NULL 即可</span></span><br><span class="line"><span class="comment"> \param 传入接收 b-leg 的 session 指针</span></span><br><span class="line"><span class="comment"> \param 传入接收呼叫结果的指针</span></span><br><span class="line"><span class="comment"> \param 想要呼叫的远端设备的链接</span></span><br><span class="line"><span class="comment"> \param 向外呼叫超时时间</span></span><br><span class="line"><span class="comment"> \param table optional state handler table to install on the channel</span></span><br><span class="line"><span class="comment"> \param 覆盖呼叫者的名字</span></span><br><span class="line"><span class="comment"> \param 覆盖呼叫者的号码</span></span><br><span class="line"><span class="comment"> \param 覆盖呼叫者的整个配置内容</span></span><br><span class="line"><span class="comment"> \param 设置在外呼通道上的变量</span></span><br><span class="line"><span class="comment"> \param flags flags to pass</span></span><br><span class="line"><span class="comment"> \retur 如果 b-leg 建立成功会返回 SWITCH_STATUS_SUCCESS</span></span><br><span class="line"><span class="comment"> \note bleg will be read locked which must be unlocked with switch_core_session_rwunlock() before losing scope</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>FreeSWTICH</category>
</categories>
<tags>
<tag>FreeSWITCH源码</tag>
</tags>
</entry>
<entry>
<title>FreeSWTICH中自定义命令的添加</title>
<url>/2022/01/08/freeswitch/FreeSWTICH%E4%B8%AD%E8%87%AA%E5%AE%9A%E4%B9%89%E5%91%BD%E4%BB%A4%E7%9A%84%E6%B7%BB%E5%8A%A0/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>本文将介绍如何在 FreeSWITCH 中开发自己的命令。<br>本文需要在<a href="./FreeSWTICH%E5%9C%A8vs%E4%B8%AD%E6%B7%BB%E5%8A%A0%E4%B8%80%E4%B8%AA%E6%B5%8B%E8%AF%95%E6%A8%A1%E5%9D%97">FreeSWTICH在vs中添加一个测试模块</a>作为基础知识。</p>
<h2 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h2><table>
<thead>
<tr>
<th>环境名</th>
<th>版本</th>
</tr>
</thead>
<tbody><tr>
<td>WIN</td>
<td>WIN10</td>
</tr>
<tr>
<td>FS</td>
<td>1.10.0</td>
</tr>
<tr>
<td>VS</td>
<td>vs2017</td>
</tr>
</tbody></table>
<h2 id="FreeSWITCH-模块基础知识"><a href="#FreeSWITCH-模块基础知识" class="headerlink" title="FreeSWITCH 模块基础知识"></a>FreeSWITCH 模块基础知识</h2><p>关于模块的定义、生命周期的开启与结束都在以下所示的定义中:</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line">SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_xx_shutdown);</span><br><span class="line">SWITCH_MODULE_LOAD_FUNCTION(mod_xx_load);</span><br><span class="line">SWITCH_MODULE_RUNTIME_FUNCTION(mod_xx_runtime);</span><br><span class="line"></span><br><span class="line">SWITCH_MODULE_DEFINITION(mod_xx, mod_xx_load, mod_xx_shutdown, mod_xx_runtime);</span><br></pre></td></tr></table></figure>
<p>此行我们着重关注模块的启动,因为我们将要在里面放置我们需要添加的命令。<br>那我们直接开始上代码把!</p>
<h2 id="添加一个命令"><a href="#添加一个命令" class="headerlink" title="添加一个命令"></a>添加一个命令</h2><p>在 <code>SWITCH_MODULE_LOAD_FUNCTION</code>中添加指向处理命令的 mod_name_function 并<br>告知控制台接收的命令字符串有 <code>help</code>这个命令</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line">SWITCH_MODULE_LOAD_FUNCTION(mod_xx_load)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">switch_api_interface_t</span> *api_interface;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* connect my internal structure to the blank pointer passed to me */</span></span><br><span class="line"> *module_interface = switch_loadable_module_create_module_interface(pool, modname);</span><br><span class="line"></span><br><span class="line"> SWITCH_ADD_API(api_interface, <span class="string">"mod_name"</span>, <span class="string">"mod description"</span>, mod_name_function, <span class="string">"syntax"</span>);</span><br><span class="line"> switch_console_set_complete(<span class="string">"add mod name help"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* indicate that the module should continue to be loaded */</span></span><br><span class="line"> <span class="keyword">return</span> SWITCH_STATUS_SUCCESS;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="处理命令"><a href="#处理命令" class="headerlink" title="处理命令"></a>处理命令</h2><p>处理命令,如果只输入了<code>mod_name</code>而没有相应的<code>help</code>那么我们直接输出 hello world,代码如下所示:</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line">SWITCH_STANDARD_API(srs_function)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">char</span> *mycmd = <span class="literal">NULL</span>;</span><br><span class="line"> <span class="keyword">switch_status_t</span> status = SWITCH_STATUS_SUCCESS;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (zstr(cmd)) </span><br><span class="line"> { </span><br><span class="line"> stream->write_function(stream, <span class="string">"%s"</span>, <span class="string">"hello world"</span>);</span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">done:</span><br><span class="line"> switch_safe_free(mycmd);</span><br><span class="line"> <span class="keyword">return</span> status;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>FreeSWTICH</category>
</categories>
<tags>
<tag>command</tag>
</tags>
</entry>
<entry>
<title>freeswitch中开发列出所有模块命令</title>
<url>/2021/05/25/freeswitch/FreeSWTICH%E4%B8%AD%E5%BC%80%E5%8F%91%E5%88%97%E5%87%BA%E6%89%80%E6%9C%89%E6%A8%A1%E5%9D%97%E5%91%BD%E4%BB%A4/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>本文章主要是对本人在fs中开发一个命令的时候的一些随想。主要记录一些遇到的问题与一些简答的想法,不具有体系性,望与共勉!</p>
<h2 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h2><table>
<thead>
<tr>
<th>环境名</th>
<th>版本</th>
</tr>
</thead>
<tbody><tr>
<td>WIN</td>
<td>WIN10</td>
</tr>
<tr>
<td>FS</td>
<td>1.10.0</td>
</tr>
<tr>
<td>VS</td>
<td>vs2017</td>
</tr>
</tbody></table>
<h2 id="vs中编译代码"><a href="#vs中编译代码" class="headerlink" title="vs中编译代码"></a>vs中编译代码</h2><p>开发一个模块命令后,需要重新<code>build</code>。</p>
<ul>
<li>自言自语:点击调试好像没法重新加载代码,重新<code>build</code>很慢,是否有其它方法?只是一个模块,应该是编译这一个模块就可以塞?</li>
</ul>
<p>干,vs2017中<code>生成</code>里面有重新生成修改的模块。-_-||</p>
<h2 id="用到的函数"><a href="#用到的函数" class="headerlink" title="用到的函数"></a>用到的函数</h2><ul>
<li><code>switch_xml_open_cfg(const char *file_path, switch_xml_t *node, switch_event_t *params)</code><ul>
<li>这个函数内部调用<code>switch_xml_locate</code>,看其中内容可以发现要求传入文件的名字即可。先就讲到这里,细节后面再说</li>
<li>file_path:需要指定文件的名字,不包括路径。例如: “modules.conf”</li>
<li>node: 声明一个switch_xml_t即可</li>
<li>params: 直接传输NULL</li>
</ul>
</li>
<li><code>switch_xml_child(switch_xml_t xml, const char *name)</code><ul>
<li>这个函数主要用于获取xml文件的节点内容,xml懂得都懂</li>
<li>xml: 这里传入刚才在上诉函数中获取node</li>
<li>name:注意xml的层级关系,第一次的话只能获取最顶部的,然后再获取下面的child,</li>
</ul>
</li>
<li><code>switch_xml_attr_soft(switch_xml_t xml, const char *attr)</code><ul>
<li>此函数用于获取在节点上的属性值。例如:<load module="mod_syslog"/>,其中的module中的值</li>
<li>xml: 获取到上面例如中的节点</li>
<li>name: 输入<code>"module"</code>然后就可以得到值</li>
</ul>
</li>
<li><code>stream->write_function(switch_stream_handle_t *handle, const char *fmt, ...)</code><ul>
<li>此函数用于在console中输出内容</li>
<li>handle: 将在command中获取到的stream扔进去即可</li>
<li>fmt: 输出内容</li>
<li>…:如果在fmt中使用占位符,可以在此处传入值</li>
</ul>
</li>
<li><code>sprintf、malloc、strlen</code><ul>
<li>系统函数,就不讲了</li>
</ul>
</li>
</ul>
]]></content>
<categories>
<category>FreeSWTICH</category>
</categories>
<tags>
<tag>command</tag>
</tags>
</entry>
<entry>
<title>FreeSWTICH在vs中添加一个测试模块</title>
<url>/2021/06/24/freeswitch/FreeSWTICH%E5%9C%A8vs%E4%B8%AD%E6%B7%BB%E5%8A%A0%E4%B8%80%E4%B8%AA%E6%B5%8B%E8%AF%95%E6%A8%A1%E5%9D%97/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>本文主要记录如何在 vs2017 中添加一个模块,并编译运行。然后,测试 event 内容</p>
<h2 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h2><table>
<thead>
<tr>
<th>环境名</th>
<th>版本</th>
</tr>
</thead>
<tbody><tr>
<td>WIN</td>
<td>WIN10</td>
</tr>
<tr>
<td>FS</td>
<td>1.10.0</td>
</tr>
<tr>
<td>VS</td>
<td>vs2017</td>
</tr>
</tbody></table>
<h2 id="添加一个模块"><a href="#添加一个模块" class="headerlink" title="添加一个模块"></a>添加一个模块</h2><h3 id="手动添加各种参数"><a href="#手动添加各种参数" class="headerlink" title="手动添加各种参数"></a>手动添加各种参数</h3><ol>
<li><p>在 vs2017 的资源管理中,选择一个文件夹,添加一个 c++ -> dll 项目,添加完成后删除多余的内容。</p>
</li>
<li><p>添加引用,直接在项目处添加引用,选择项目中的引用 <code>FreeswitchCoreLib</code></p>
</li>
<li><p>增加库文件,选择 项目-> 属性 -> c/c++ -> 所有选项 -> 附加包含目录 增加项目解决方案的 lib 即可,目录内容为<code>$(SolutionDir)\src\include</code></p>
</li>
<li><p>修改预处理器。在 fs 项目中,通过 vs 添加的项目默认为导入,我们需要在 项目->属性->c/c++->预编译头->预处理器定义 中添加<code>MOD_EXPORTS</code>,将项目标识为导出。源代码如下所示:</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 我们在使用 SWITCH_MODULE_DEFINITION 时会被扩展为带有 SWITCH_MOD_DECLARE_DATA 前缀的结构体</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> defined(SWITCH_MOD_DECLARE_STATIC)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SWITCH_MOD_DECLARE(type) type __stdcall</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SWITCH_MOD_DECLARE_NONSTD(type) type __cdecl</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SWITCH_MOD_DECLARE_DATA</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">elif</span> defined(MOD_EXPORTS)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SWITCH_MOD_DECLARE(type) __declspec(dllexport) type __stdcall</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SWITCH_MOD_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SWITCH_MOD_DECLARE_DATA __declspec(dllexport)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SWITCH_MOD_DECLARE(type) __declspec(dllimport) type __stdcall</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SWITCH_MOD_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SWITCH_MOD_DECLARE_DATA __declspec(dllimport)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br></pre></td></tr></table></figure>
</li>
<li><p>修改 项目->属性->c/c++->语言->符合模式 为<strong>否</strong></p>
</li>
<li><p>在 “项目”(顶部导航栏) 中选择 “清理项目”,然后 “生成项目”即可</p>
</li>
</ol>
<h3 id="使用属性管理器"><a href="#使用属性管理器" class="headerlink" title="使用属性管理器"></a>使用属性管理器</h3><ol>
<li><p>在 vs2017 的资源管理中,选择一个文件夹,添加一个 c++ -> dll 项目,添加完成后删除多余的内容。</p>
<blockquote>
<p>注意:添加的代码为 C 语言代码,所以代码文件要以*.c结尾</p>
</blockquote>
</li>
<li><p>添加引用,直接在项目处添加引用,选择项目中的引用 <code>FreeswitchCoreLib</code></p>
</li>
<li><p><strong>属性管理器</strong>中找到新创建的项目,在<strong>Debug | Win32</strong>中选择“添加现有属性表”,添加<code>freeswitch/w32</code>中的<code>module_debug.props</code></p>
</li>
<li><p>修改 项目->属性->c/c++->语言->符合模式 为<strong>否</strong></p>
</li>
</ol>
]]></content>
<categories>
<category>FreeSWTICH</category>
</categories>
<tags>
<tag>event</tag>
</tags>
</entry>
<entry>
<title>Sip协议中的一些概念</title>
<url>/2023/12/24/freeswitch/Sip%E5%8D%8F%E8%AE%AE%E4%B8%AD%E7%9A%84%E4%B8%80%E4%BA%9B%E6%A6%82%E5%BF%B5/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>本文主要介绍 SIP 协议中的一些缩写字符的含义,这些缩写在阅读 Sofia-sip 的代码时常有出现</p>
<h2 id="Sip-缩写字符"><a href="#Sip-缩写字符" class="headerlink" title="Sip 缩写字符"></a>Sip 缩写字符</h2><ul>
<li><p>线性空白(Linear White Space,简称LWS): 位于文本字符序列中的空白字符,包括空格、制表符和换行符等。<br>在计算机编程中,线性空白通常用来描述文本中字符之间的间距,包括但不限于字母、数字、标点符号等。<br>线性空白与非线性空白(Non-Linear White Space,简称NLWS)相对,非线性空白一般指符号或标点之间的间距,如句子结束的标点符号与下一句的起始字母之间的间隔</p>
</li>
<li><p>CRLF: 换行符</p>
</li>
</ul>
]]></content>
<categories>
<category>freeswitch</category>
</categories>
<tags>
<tag>Sip</tag>
</tags>
</entry>
<entry>
<title>Sofia中的一些概念</title>
<url>/2023/12/23/freeswitch/Sofia%E4%B8%AD%E7%9A%84%E4%B8%80%E4%BA%9B%E6%A6%82%E5%BF%B5/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>本文主要对 Sofia 中的一些概念进行分析与解释,方便进行源码阅读。</p>
<h2 id="Sofia-概念"><a href="#Sofia-概念" class="headerlink" title="Sofia 概念"></a>Sofia 概念</h2><h3 id="事件循环Event-loop-与根对象-root-object"><a href="#事件循环Event-loop-与根对象-root-object" class="headerlink" title="事件循环Event loop 与根对象 root object"></a>事件循环Event loop 与根对象 root object</h3><ul>
<li>NUA以事件反应器模式(也称为分发及通知模式)驱动事件系统(请参考[Using Design Patterns to Develop Reusable Object-oriented Communication Software, D.C. Schmidt, CACM October ‘95, 38(10): 65-74]一书)。<br>Sofia以任务作为编程模型的基本执行单元。根据编程模型,程序可以请求事件循环在特定事件触发时调用回调函数。具体事件包括I/O激活,定时器或其它任务传递的异步消息。</li>
<li>root 对象是应用软件中描述一个任务的句柄。<ul>
<li>透视事件的另一种方式是:root对象描述任务的主事件循环。通过root对象,任务代码可以访问它的上下文信息(magic)和线程同步,比如说等待对象、定时器,消息。</li>
</ul>
</li>
<li>使用NUA服务的应用必须创建一个root对象,并设置处理NUA事件的回调函数。<ul>
<li>调用 <code>su_root_create()</code>创建root对象,调用<code>nua_create()</code>函数注册回调函数。root 对象的数据类型是 su_root_t。</li>
</ul>
</li>
</ul>
<h3 id="Magic"><a href="#Magic" class="headerlink" title="Magic"></a>Magic</h3><ul>
<li>magic 是一种描述上下文指针的术语,应用程序可以把它绑定到Sofia栈的各种对象上(比如说root对象和操作句柄)。当主事件循环调用注册的回调函数时,上下文指针会回传给应用层代码。<br>Sofia栈保留回调函数调用之间的上下文信息。应用层可以利用上下文信息存储处理事件所需要的任何信息</li>
</ul>
<h3 id="内存处理"><a href="#内存处理" class="headerlink" title="内存处理"></a>内存处理</h3><ul>
<li>给定的任务需要分配许多小块内存时,使用home-based内存管理机制会很便利。内存通过home对象分配,它维护所有内存块的引用信息。当home对象释放时,所有相关内存一并释放。这个机制简化了应用逻辑,因为应用层代码不需要跟踪内存块的分配记录,也不需要独立释放每一个内存块。<br>使用NUA服务的应用程序可以使用SU库提供的内存管理服务,但这不是强制要求的。</li>
</ul>
<h2 id="引用"><a href="#引用" class="headerlink" title="引用"></a>引用</h2><ul>
<li><a href="https://blog.csdn.net/yetyongjin/article/details/105839864">Sofia “nua”模块–高层UA库</a></li>
</ul>
]]></content>
<categories>
<category>freeswitch</category>
</categories>
<tags>
<tag>Sofia</tag>
</tags>
</entry>
<entry>
<title>Sofia发送subscriber的源码解析</title>
<url>/2023/12/23/freeswitch/Sofia%E5%8F%91%E9%80%81subscriber%E7%9A%84%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>本文将对 sofia 发送 subscriber 这个信令进行源码分析其中会对一些涉及到的其它源码进行解析,用以后续学习</p>
<h2 id="Sofia-的-handle"><a href="#Sofia-的-handle" class="headerlink" title="Sofia 的 handle"></a>Sofia 的 handle</h2><p>这里对 handle 进行一定的解释。这个 handle 用于管理向谁发送什么样的数据,这个谁一般指定 uac 。 一个 handle 会生成一个新的 call-id,产生一个新的 session。</p>
<ul>
<li><code>nua_handle_destroy()</code>: 用于销毁这个 handle。<ul>
<li>小知识:FreeSWITCH 一般在创建后 <code>nua_handle_bind(fnh, &mod_sofia_globals.destroy_private)</code>,后续不用后会自动销毁, 这个销毁主要依赖于 our_sofia_event_callback<br>中的以下代码:<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="keyword">if</span> ((sofia_private && sofia_private == &mod_sofia_globals.destroy_private)) {</span><br><span class="line"> nua_handle_bind(nh, <span class="literal">NULL</span>);</span><br><span class="line"> nua_handle_destroy(nh);</span><br><span class="line"> nh = <span class="literal">NULL</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li>
</ul>
</li>
<li><code>nua_handle_bind</code>: 绑定给回调函数一个上下文。在发生 sip 的状态机变化的时候,nua_create 注册的回调函数会回调,其中的会带有这个绑定的值。解绑传值为 NULL</li>
<li><code>nua_handle_ref</code>: 增加了 handle 的 sub_ref, 未知</li>
<li><code>nua_handle_unref</code>: 减少了 handle 的 sub_ref,未知<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">nua.c:304 </span><br></pre></td></tr></table></figure>
<h2 id="Sofia-的-subscribe-流程"><a href="#Sofia-的-subscribe-流程" class="headerlink" title="Sofia 的 subscribe 流程"></a>Sofia 的 subscribe 流程</h2></li>
</ul>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">nua.c:701 nua_subscribe NUA_SIGNAL(nh, nua_r_subscribe, tag, value)</span><br><span class="line"></span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>freeswitch</category>
</categories>
<tags>
<tag>Sofia</tag>
</tags>
</entry>
<entry>
<title>阅读SIP协议观后感</title>
<url>/2024/01/01/freeswitch/%E9%98%85%E8%AF%BBSIP%E5%8D%8F%E8%AE%AE%E8%A7%82%E5%90%8E%E6%84%9F/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>本文主要记录阅读 SIP rfc3261 文档的一些所思所考,不会对其进行整理分类,并且存在跳跃性</p>
<h2 id="生成-SIP-响应"><a href="#生成-SIP-响应" class="headerlink" title="生成 SIP 响应"></a>生成 SIP 响应</h2><ul>
<li>8.2.6</li>
<li>除了 invite 外需要生成临时响应,其它响应应该立即响应</li>
<li>生成的临时响应,请求中的时间戳应该直接复制到响应中。如果响应慢就需要将延迟时间以 s 为单位,将时间生成在响应中</li>
<li>响应的 Call-ID、CSeq、VIA的顺序必须相同。除了 100,其它响应的 uri 内容必须相同,并且需要添加一个 tag,用于 dialog。</li>
</ul>
<h2 id="事务的解读"><a href="#事务的解读" class="headerlink" title="事务的解读"></a>事务的解读</h2><p>事务的分为客户端事务与服务器事务,客户端事务发送请求,服务器事务发送响应。</p>
<p>无状态代理不包含客户端事务或服务器事务。</p>
<ul>
<li>200(Ok)的ack作用:主要为了确保 200ok 能够正常发送到 UAC。如果后续不发送 ACK,那么服务端会不断发送,并且在三分钟后断开连接<ul>
<li>疑问:为啥 200 ok 的 ack 作为自己单独的事务?</li>
<li>解答:这样设计的原因是保证送达到UAC,并且如果没有回复 ACK,那么 UAS 将会重传</li>
</ul>
</li>
<li>客户端事务:客户端事务的主要负责将接收到的响应传递给 TU, 并过滤重传与不允许的传递。对于 invite 的请求,用于生成 ACK<ul>
<li>疑问:TU 与客户端事务有什么区别吗</li>
<li>解答:客户端是TU 与 传输层的中间层</li>
</ul>
</li>
<li>服务器事务:服务器事务的目的是接收来自传输层的请求并将其传递给TU,服务器事务过滤来自网络的任何请求重传。<br>服务器事务接受来自TU的响应,并将它们传递到传输层,以便通过网络进行传输。在INVITE事务的情况下,它会吸收除2xx响应之外的任何最终响应的ACK请求。</li>
<li>200ok与ack的生成: 都由 UA 核心来处理<ul>
<li>疑问:前面说客户端事务生成ack,现在又说 UA 核心来处理,不明白</li>
<li>解释:这里的由核心来处理指的是重传由核心处理。</li>
</ul>
</li>
<li>on-INVITE client transaction:这是没有 ack 的事务。如果需要 ack 的话,需要 tu 直接生成一个 ack?</li>
</ul>
<h3 id="客户端事务"><a href="#客户端事务" class="headerlink" title="客户端事务"></a>客户端事务</h3><ul>
<li>客户端事务状态机: invite 客户端事务与非 invite 客户端事务<ul>
<li>特点:invite 客户端事务发送延迟长,需要三方握手;非 invite 事务需要立即响应</li>
<li>注意:如果 TU 希望发送 ACK,它将一个 ACK 直接传递给传输层进行传输</li>
</ul>
</li>
</ul>
<h4 id="invite-客户端事务"><a href="#invite-客户端事务" class="headerlink" title="invite 客户端事务"></a>invite 客户端事务</h4><p>invite 事务由发送 invite、服务器事务响应、客户端事务响应ack组成。<br>其中 invite 发出后在 t1(默认值:500ms) 重发,除非接受到 1xx 响应,否则就增加两倍的 t1 进行重传。<br>最终,服务器事务发出最终响应,并有客户端事务发送 ack 用于终止重传</p>
<ul>
<li>形式描述<ul>
<li>invite 的客户端事务初始状态为 “Calling”<ul>
<li>不可靠传输启动定时器 A(t1),可靠传输不需要启动。事务启动定时器 B(64*t1) 控制事务超时</li>
<li>超时后重传必须在 “calling” 状态下进行,并且传输时间是 2*t1</li>
<li>如果定时器 B 触发后任然处于 “calling”, 则通知 TU 超时,并不生成 ack,然后进入 “Terminated” 状态</li>
</ul>
</li>
<li>当接收到临时响应是,状态改为 “Proceeding”。后续的临时响应需要传递给 TU<ul>
<li>当处于 “Calling” 或 “Proceeding” 状态下,接收到 300-699 响应必须转换为 “Completed”</li>
<li>接收到服务器事务的响应后,生成 ack 并传输到原始请求发送到的相同的地址、端口和 transport</li>
<li>当进入 “Completed” 时,启动定时器 D, 对于不可靠传输值至少为 32 秒,可靠传输置为 0。这个值等于服务器事务定时器 H(64*T1)</li>
<li>新接收到的重新响应不能传递给 TU</li>
</ul>
</li>
<li>定时器 D 在客户端事务处于 “Completed” 状态时触发,客户端事务必须移动到 “Terminated”<ul>
<li>当处于 “Calling” 或 “Proceeding” 状态下,接收 2xx 响应必须导致客户端事务进入 “Terminated” 状态,并且必须将响应传递到TU</li>
<li>Proxy 响应 200 为传递给下一跳,客户端事务生成 ack</li>
<li>客户端事务必须在进入 “Terminated” 状态的瞬间被销毁。</li>
<li>注意:如何没匹配到合适的客户端事务,则传递到 core</li>
</ul>
</li>
</ul>
</li>
<li>ack 的构造<ul>
<li>Call-ID、From 和 Request-URI 必须和原始请求相同</li>
<li>To 必须等于被确定的响应中的 To 字段</li>
<li>ACK 必须包含单一的 Via 报头字段,这个字段必须等于原始的顶部 Via 报头字段</li>
<li>如果 2xx 中有 Route 字段,则这些也要出现在 ACK 报头中</li>
<li>注意:invite 响应 415,则可以在 ACK 中放置 body 内容</li>
</ul>
</li>
</ul>
<h4 id="非-INVITE-客户端事务"><a href="#非-INVITE-客户端事务" class="headerlink" title="非 INVITE 客户端事务"></a>非 INVITE 客户端事务</h4><p>非 INVITE 客户端事务超时 t1 后重传,但是在接受到临时或最终响应后,以 t2 为间隔继续传输消息。</p>
<blockquote>
<p>疑问:按照标准文档,按照 t2 继续传输消息,是为了确保交付最后响应。服务器发送了一个请求后,传输在终止?</p>
</blockquote>
<p>非 INVITE 客户端事务的 200ok 不会响应 ACK。</p>
<ul>
<li>形式描述:<ul>
<li>发起事务请求,进入 “Trying” 状态<ul>
<li>启动定时器 F(64<em>T1) 。如果是不可靠传输,客户端事务必须设置定时器 E(T1),以MIN(2</em>T1,T2),T2 默认为 4s</li>
<li>如果定时器 F 触发,仍处于 “Trying”,通知 TU 超时,然后进入 “Terminated” 状态</li>
<li>如果在 “Trying” 状态下收到最终响应(200-699),则传递给 TU,事务转换为 “Completed” 状态</li>
</ul>
</li>
<li>当在 “Trying” 状态下收到临时响应,则转为 “Proceeding” 状态<ul>
<li>如果定时器 E 在 “Proceeding” 状态下被触发,请求需要被重传,定时器 E 重置为 T2 秒</li>
<li>如果定时器 F 在 “Proceeding” 状态下被触发,通知 TU 超时,然后进入 “Terminated” 状态</li>
<li>如果在 “Proceeding” 状态下收到最终响应(200-699),则传递给 TU,事务转换为 “Completed” 状态</li>
</ul>
</li>
<li>当进入 “Completed” 时,启动定时器 K, 对于不可靠传输值 T4 秒,可靠传输置为 0。<ul>
<li>T4表示网络清除客户机和服务器事务之间的消息所需的时间。缺省值为5s</li>
<li>如果定时器 K 在此状态下触发,客户端事务必须转换到 “Terminated” 状态。</li>
</ul>
</li>
</ul>
</li>
<li>匹配响应给对应客户端事务<ul>
<li>响应消息的 Via 头字段的 Branch 参数相同,则匹配</li>
<li>CSeq报头字段中的方法参数与创建事务的请求的方法匹配。用于 CANCEL,CANCEL 会新生成一个事务</li>
</ul>
</li>
<li>异常处理<ul>
<li>当传输发送错误时,立即想 TU 响应错误,并直接切换到 “Terminated” 状态</li>
</ul>
</li>
</ul>
<h3 id="服务器事务"><a href="#服务器事务" class="headerlink" title="服务器事务"></a>服务器事务</h3><p>服务器事务是在接收到请求时由核心创建。</p>
<h4 id="INVITE-服务器事务"><a href="#INVITE-服务器事务" class="headerlink" title="INVITE 服务器事务"></a>INVITE 服务器事务</h4><ul>
<li><p>形式描述:</p>
<ul>
<li><p>Proceeding 收到重传请求,那么需要获取 TU 给的最新的 trying 进行重传</p>
<ul>
<li>Proceeding 状态下 TU 向服务器事务传递 2xx 响应,服务器事务必须传出去,当然重传由 TU 负责,服务器事务状态转为 Terminated</li>
<li>Proceeding 状态下 TU 向服务器事务传递 300-699,必须传出去,服务器事务状态转为 Completed。不可靠传输定时器 G(T1) 触发,可靠传输,定时器不触发。</li>
</ul>
</li>
<li><p>Completed 进入后,定时器 H(64*T1) 必须启动,此定时器决定了重传超时时间。</p>
<ul>
<li>如果定时器 G 触发,则将继续重传,定时器 G 时间为 MIN(2*T1, T2)</li>
<li>Completed 状态下,接收到重传请求应该进行重传</li>
<li>Completed 状态下,收到了 ACK,则转为 Confirmed。并且定时器 G 被忽略,任何重传都会停止</li>
<li>Completed 状态下,定时器 H 被激活,则服务器事务转为 Terminated 状态,并通知 TU 事务失败。</li>
</ul>
</li>
<li><p>Confirmed 主要用于吸收多余的 ACK。</p>
<ul>
<li>当进入该状态时,定时器 I 在 T4 秒内触发,对于不可靠的传输,定时器 I 为 0 秒。</li>
<li>一旦定时器触发,则转为 Terminated 状态</li>
</ul>
</li>
<li><p>一旦事务处于“终止”状态,它必须立即销毁。与客户端事务一样,这需要确保对INVITE的2xx响应的可靠性。</p>
</li>
</ul>
</li>
</ul>
<h4 id="非-INVITE-服务器事务"><a href="#非-INVITE-服务器事务" class="headerlink" title="非 INVITE 服务器事务"></a>非 INVITE 服务器事务</h4><ul>
<li>形式描述:<ul>
<li>Trying 状态下,初始化走这个状态并且任何重传都将丢弃<ul>
<li>TU 向服务器事务传输响应,则转为 Proceeding 状态</li>
</ul>
</li>
<li>Proceeding 状态下,所有 TU 传输过来的内容,都需要全部通过传输层传输出去<ul>
<li>Proceeding 接收到请求的重传,则必须将最新发送临时响应重传出去</li>
<li>Proceeding 状态下,TU 向服务器事务传递最终响应(200-699), 则事务必须进入 Completed 状态</li>
</ul>
</li>
<li>Completed 状态必须启动定时器 J(64*T1),不可靠为 0 秒<ul>
<li>TU 传递给服务器事务的任何其他最终响应必须在处于 Completed 状态时丢弃</li>
<li>服务器事务保持这个状态,直到定时器 J 触发,转为 Terminated 状态</li>
</ul>
</li>
<li>服务器事务必须在进入 Terminated 状态的瞬间被销毁。</li>
</ul>
</li>
</ul>
<h3 id="事务的的匹配"><a href="#事务的的匹配" class="headerlink" title="事务的的匹配"></a>事务的的匹配</h3><p>在 VIA 中有 z9hG4bK 字符,通过魔法字符进行匹配。没有就采用 Request-URI, To tag, From tag, Call-ID, CSeq, and top Via header<br>匹配对应的 事务。</p>
]]></content>
<categories>
<category>freeswitch</category>
</categories>
<tags>
<tag>sip</tag>
</tags>
</entry>
<entry>
<title>js变量的解构赋值与基本使用场景</title>
<url>/2020/12/21/page/JS%E5%8F%98%E9%87%8F%E7%9A%84%E8%A7%A3%E6%9E%84%E8%B5%8B%E5%80%BC%E4%B8%8E%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>主要讲解JS变量的解构赋值的语法,与其在开发过程中的实际使用场景。</p>
<h2 id="js解构赋值"><a href="#js解构赋值" class="headerlink" title="js解构赋值"></a>js解构赋值</h2><h3 id="数组解构赋值"><a href="#数组解构赋值" class="headerlink" title="数组解构赋值"></a>数组解构赋值</h3><p>数组的解构遵循<strong>只要等号两边的模式相同,左边的变量就会被赋予对应的值</strong>。在使用的过程中可以使用默认值,默认值可以引用解构赋值的其他变量,但该变量必须已经声明</p>
<p>注意:数组的解构赋值,如果右边不是数组(不是可遍历的结构)会报错</p>
<ul>
<li>正常的使用情况</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">//完整的使用</span></span><br><span class="line"> <span class="comment">//结果:a=1,b=2,c=3</span></span><br><span class="line"> <span class="keyword">var</span> [a, b, c] = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line"> <span class="comment">//结果:foo=1,bar=2,baz=3</span></span><br><span class="line"> <span class="keyword">let</span> [foo, [[bar], baz]] = [<span class="number">1</span>, [[<span class="number">2</span>], <span class="number">3</span>]];</span><br><span class="line"></span><br><span class="line"><span class="comment">//左边少,右边正常</span></span><br><span class="line"> <span class="comment">//结果:c=3</span></span><br><span class="line"> <span class="keyword">var</span> [, , c] = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</span><br><span class="line"> <span class="comment">//结果:a=1</span></span><br><span class="line"> <span class="keyword">var</span> [a] = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</span><br><span class="line"> <span class="comment">//剩下的情况,聪明的你肯定已经明白</span></span><br><span class="line"><span class="comment">//右边少,左边正常</span></span><br><span class="line"> <span class="comment">//结果:a=1,b=undefined,c=undefined</span></span><br><span class="line"> <span class="keyword">var</span> [a, b, c] = [<span class="number">1</span>]</span><br><span class="line"> <span class="comment">//结果:a=undefined,b=undefined,c3</span></span><br><span class="line"> <span class="keyword">var</span> [a, b, c] = [, , <span class="number">3</span>]</span><br><span class="line"> <span class="comment">//剩下的情况,聪明的你肯定已经明白</span></span><br></pre></td></tr></table></figure>
<ul>
<li>默认值</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">//结果:foo=true</span></span><br><span class="line"><span class="keyword">let</span> [foo = truel = [];</span><br><span class="line"><span class="keyword">let</span> [foo = truel = [<span class="literal">undefined</span>];</span><br><span class="line"><span class="keyword">let</span> [foo = truel = [<span class="literal">null</span>];</span><br><span class="line"> </span><br><span class="line"><span class="comment">//必须声明,否则无法使用</span></span><br><span class="line"><span class="keyword">let</span> [x = <span class="number">1</span>, y = x] = []; <span class="comment">// x=1; y=1</span></span><br><span class="line"><span class="keyword">let</span> [x = <span class="number">1</span>, y = x] = [<span class="number">2</span>]; <span class="comment">// x=2; y=2</span></span><br><span class="line"><span class="keyword">let</span> [x = <span class="number">1</span>, y = x] = [<span class="number">1</span>, <span class="number">2</span>]; <span class="comment">// x=1; y=2</span></span><br><span class="line"><span class="keyword">let</span> [x = y, y = <span class="number">1</span>] = []; <span class="comment">// ReferenceError</span></span><br></pre></td></tr></table></figure>
<ul>
<li>特殊的使用</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">f</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'aaa'</span>);</span><br><span class="line">}</span><br><span class="line"><span class="comment">//结果:x=1</span></span><br><span class="line"><span class="keyword">let</span> [x = f()] = [<span class="number">1</span>];</span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>ES6</category>
</categories>
<tags>
<tag>解构赋值</tag>
</tags>
</entry>
<entry>
<title>Mybatis基本使用</title>
<url>/2020/12/09/page/Mybatis%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>本文主要讲解<code>mybatis</code>的<code>$</code>与<code>#</code>的使用,关联查询中各个关键字的使用</p>
<h2 id="动态语法的使用"><a href="#动态语法的使用" class="headerlink" title="动态语法的使用"></a>动态语法的使用</h2><h3 id="的使用"><a href="#的使用" class="headerlink" title="#{}的使用"></a>#{}的使用</h3><p>解析为一个JDBC预编译语句的参数标识符,把参数部分用占位符?代替</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select * from t_user from username = ?;</span><br><span class="line">#处理后,会对传入数据加''</span><br><span class="line">select * from t_user from username = 'Alice';</span><br></pre></td></tr></table></figure>
<h3 id="的使用-1"><a href="#的使用-1" class="headerlink" title="${}的使用"></a>${}的使用</h3><p>只做简单的字符串替换,在动态SQL解析阶段将会进行变量替换</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select * from t_user where username = 'Alice';</span><br></pre></td></tr></table></figure>
<h3 id="与-对比"><a href="#与-对比" class="headerlink" title="#{}与${}对比"></a>#{}与${}对比</h3><p>#{}用占位符站位后,JDBC的PreparedStatement会对传入的参数进行校验,防止SQL注入。</p>
<p>${}替换为具体的字符串后不会再做任何检测</p>
<h3 id="使用场景"><a href="#使用场景" class="headerlink" title="使用场景"></a>使用场景</h3><p>${}可以用于order by后的排序字段,表名,列名等。其中表名只能采用此</p>
<blockquote>
<p>注:能使用#{}尽量用,如表名,order by的排序字段作为变量时使用${}</p>
</blockquote>
<h2 id="关联查询之一对多"><a href="#关联查询之一对多" class="headerlink" title="关联查询之一对多"></a>关联查询之一对多</h2><p><code>association</code>与<code>connection</code>在关联上的使用基本一致</p>
<h3 id="单步查询"><a href="#单步查询" class="headerlink" title="单步查询"></a>单步查询</h3><ul>
<li>实体类</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CountryPlus</span> </span>{</span><br><span class="line"> Long id;</span><br><span class="line"> String name;</span><br><span class="line"> List<City> cityList;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">City</span> </span>{</span><br><span class="line"> Long id;</span><br><span class="line"> String name;</span><br><span class="line"> Long countryId;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<ul>
<li>xml配置</li>
</ul>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">select</span> <span class="attr">id</span>=<span class="string">"selectCountryPlusById"</span> <span class="attr">resultMap</span>=<span class="string">"countryPlusResultMap"</span>></span></span><br><span class="line"> select country.country_id as country_id,</span><br><span class="line"> country,</span><br><span class="line"> city_id,</span><br><span class="line"> city,</span><br><span class="line"> city.country_id as city_country_id,</span><br><span class="line"> from country left join city on country.country_id = city.country_id</span><br><span class="line"> where country.country_id=#{id}</span><br><span class="line"><span class="tag"></<span class="name">select</span>></span></span><br><span class="line"></span><br><span class="line"><span class="comment"><!--resultMap--></span></span><br><span class="line"><span class="tag"><<span class="name">resultMap</span> <span class="attr">id</span>=<span class="string">"countryPlusResultMap"</span> <span class="attr">type</span>=<span class="string">"canger.study.chapter04.bean.CountryPlus"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">id</span> <span class="attr">column</span>=<span class="string">"country_id"</span> <span class="attr">property</span>=<span class="string">"id"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">result</span> <span class="attr">column</span>=<span class="string">"country"</span> <span class="attr">property</span>=<span class="string">"name"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">collection</span> <span class="attr">property</span>=<span class="string">"cityList"</span> <span class="attr">ofType</span>=<span class="string">"*.City"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">id</span> <span class="attr">column</span>=<span class="string">"city_id"</span> <span class="attr">property</span>=<span class="string">"id"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">result</span> <span class="attr">column</span>=<span class="string">"city"</span> <span class="attr">property</span>=<span class="string">"name"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">result</span> <span class="attr">column</span>=<span class="string">"city_country_id"</span> <span class="attr">property</span>=<span class="string">"countryId"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">collection</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">resultMap</span>></span></span><br></pre></td></tr></table></figure>
<h3 id="分步查询"><a href="#分步查询" class="headerlink" title="分步查询"></a>分步查询</h3><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"> <span class="tag"><<span class="name">select</span> <span class="attr">id</span>=<span class="string">"selectCountryPlusByIdStep"</span> <span class="attr">resultMap</span>=<span class="string">"countryPlusResultMapStep"</span>></span></span><br><span class="line"> select *</span><br><span class="line"> from country</span><br><span class="line"> where country_id=#{id}</span><br><span class="line"><span class="tag"></<span class="name">select</span>></span></span><br><span class="line"></span><br><span class="line"><span class="comment"><!--resultMap--></span></span><br><span class="line"> <span class="tag"><<span class="name">resultMap</span> <span class="attr">id</span>=<span class="string">"countryPlusResultMapStep"</span> <span class="attr">type</span>=<span class="string">"*.CountryPlus"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">id</span> <span class="attr">column</span>=<span class="string">"country_id"</span> <span class="attr">property</span>=<span class="string">"id"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">result</span> <span class="attr">column</span>=<span class="string">"country"</span> <span class="attr">property</span>=<span class="string">"name"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">collection</span> <span class="attr">property</span>=<span class="string">"cityList"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">select</span>=<span class="string">"*selectCityByCountryId"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">column</span>=<span class="string">"country_id"</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">collection</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">resultMap</span>></span></span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>mybatis</category>
</categories>
<tags>
<tag>mybatis</tag>
</tags>
</entry>
<entry>
<title>springboot源代码解析(1)</title>
<url>/2020/10/31/page/springboot%E6%BA%90%E4%BB%A3%E7%A0%81%E8%A7%A3%E6%9E%90%EF%BC%881%EF%BC%89/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>主要对spring boot的源代码进行解析,解析的内容包括启动顺序、代码的作用和设计代码的设计模式。第一次内容目标需要解决的问题关于springboot的配置的加载!</p>
<h2 id="Spring-Boot的入口类"><a href="#Spring-Boot的入口类" class="headerlink" title="Spring Boot的入口类"></a>Spring Boot的入口类</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SpringBootBestPracticeApplication</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(SpringBootBestPracticeApplication.class, args);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>以上入口类主要使用<code>SpringApplication</code>中的方法,跟踪代码进入<code>run</code></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> ConfigurableApplicationContext <span class="title">run</span><span class="params">(Class<?> primarySource,</span></span></span><br><span class="line"><span class="function"><span class="params"> String... args)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> run(<span class="keyword">new</span> Class<?>[] { primarySource }, args);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> 静态助手,可用于使用默认设置和用户提供的参数从指定的源运行SpringApplication。</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> ConfigurableApplicationContext <span class="title">run</span><span class="params">(Class<?>[] primarySources,</span></span></span><br><span class="line"><span class="function"><span class="params"> String[] args)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> SpringApplication(primarySources).run(args);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>函数上的注释为函数的英文注释的中文翻译。</p>
<p>其中第一个参数<code>primarySource</code>:加载主要资源类(未知用途)</p>
<p>第二个参数<code>args</code>:用于传递参数(未知用途)</p>
<p><strong>设计模式:</strong>采用了静态工厂方法,其中主要让创建对象的时候返回其它类型的对象且具有可读性。—<<Effective-Java>></p>
<h2 id="SpringApplication实例化"><a href="#SpringApplication实例化" class="headerlink" title="SpringApplication实例化"></a><code>SpringApplication</code>实例化</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">SpringApplication</span><span class="params">(Class<?>... primarySources)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>(<span class="keyword">null</span>, primarySources);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">SpringApplication</span><span class="params">(ResourceLoader resourceLoader, Class<?>... primarySources)</span> </span>{</span><br><span class="line"> <span class="comment">//初始化资源加载器为null</span></span><br><span class="line"> <span class="keyword">this</span>.resourceLoader = resourceLoader;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//断言primarySources是否为null,不能为null</span></span><br><span class="line"> Assert.notNull(primarySources, <span class="string">"PrimarySources must not be null"</span>);</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//初始化加载资源类集合并去重</span></span><br><span class="line"> <span class="keyword">this</span>.primarySources = <span class="keyword">new</span> LinkedHashSet<>(Arrays.asList(primarySources));</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//推断web类型,SERVLET,REACTIVE,None</span></span><br><span class="line"> <span class="keyword">this</span>.webApplicationType = deduceWebApplicationType();</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//设置应用上下文初始化器</span></span><br><span class="line"> setInitializers((Collection) getSpringFactoriesInstances(</span><br><span class="line"> ApplicationContextInitializer.class));</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//设置应用监听器</span></span><br><span class="line"> setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//推断主入口应用类</span></span><br><span class="line"> <span class="keyword">this</span>.mainApplicationClass = deduceMainApplicationClass();</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p><code>SpringApplication</code>实例化过程中经过了<code>7</code>个步骤,前<code>3</code>个步骤集中于对<code>resourceLoader</code>、<code>primarySources</code>的初始与判定,较为简单。后四个步骤为实例化的重点</p>
<h3 id="推断web类型"><a href="#推断web类型" class="headerlink" title="推断web类型"></a>推断<code>web</code>类型</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> WebApplicationType <span class="title">deduceWebApplicationType</span><span class="params">()</span> </span>{</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//判断如果存在*reactive.DispatcherHandler</span></span><br><span class="line"> <span class="comment">//并且不存在*web.servlet.DispatcherServlet</span></span><br><span class="line"> <span class="comment">//并且不存在org.glassfish.jersey.server.ResourceConfig</span></span><br><span class="line"> <span class="keyword">if</span> (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, <span class="keyword">null</span>)</span><br><span class="line"> && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, <span class="keyword">null</span>)</span><br><span class="line"> && !ClassUtils.isPresent(JERSEY_WEB_ENVIRONMENT_CLASS, <span class="keyword">null</span>)) {</span><br><span class="line"> <span class="keyword">return</span> WebApplicationType.REACTIVE;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//判断是否存在javax.servlet.Servlet和</span></span><br><span class="line"> <span class="comment">//*.ConfigurableWebApplicationContext</span></span><br><span class="line"> <span class="keyword">for</span> (String className : WEB_ENVIRONMENT_CLASSES) {</span><br><span class="line"> <span class="keyword">if</span> (!ClassUtils.isPresent(className, <span class="keyword">null</span>)) {</span><br><span class="line"> <span class="keyword">return</span> WebApplicationType.NONE;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> WebApplicationType.SERVLET;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">enum</span> WebApplicationType {</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The application should not run as a web application and should not start an</span></span><br><span class="line"><span class="comment"> * embedded web server.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> NONE,</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The application should run as a servlet-based web application and should start an</span></span><br><span class="line"><span class="comment"> * embedded servlet web server.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> SERVLET,</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The application should run as a reactive web application and should start an</span></span><br><span class="line"><span class="comment"> * embedded reactive web server.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> REACTIVE</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p><code>ClassUtils.isPresent</code>函数主要用于确定类是否存在</p>
<p><code>WebApplicationType</code>有三种类型,<code>None</code>表示不是以一个web应用启动,<code>servlet</code>表示以<code>servlet</code>为基础的web应用,<code>REACTIVE</code>表示是一个reactive的web。<code>REACTIVE</code>本人研究不多,按照<code>Spring</code>官方说法是一个非阻塞的web框架,其使用到的maven为<code>spring-boot-starter-webflux</code></p>
<h3 id="设置应用上下文初始化器"><a href="#设置应用上下文初始化器" class="headerlink" title="设置应用上下文初始化器"></a>设置应用上下文初始化器</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">setInitializers((Collection) getSpringFactoriesInstances(</span><br><span class="line"> ApplicationContextInitializer.class));</span><br></pre></td></tr></table></figure>
<h4 id="应用上下文初始化器的作用"><a href="#应用上下文初始化器的作用" class="headerlink" title="应用上下文初始化器的作用"></a>应用上下文初始化器的作用</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">ApplicationContextInitializer</span><<span class="title">C</span> <span class="keyword">extends</span> <span class="title">ConfigurableApplicationContext</span>> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Initialize the given application context.</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> applicationContext the application to configure</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">initialize</span><span class="params">(C applicationContext)</span></span>;</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>用来初始化指定的 Spring 应用上下文,如注册属性资源、激活配置文件等</p>
<h4 id="设置应用上下文初始化"><a href="#设置应用上下文初始化" class="headerlink" title="设置应用上下文初始化"></a>设置应用上下文初始化</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setInitializers</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params"> Collection<? extends ApplicationContextInitializer<?>> initializers)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.initializers = <span class="keyword">new</span> ArrayList<>();</span><br><span class="line"> <span class="keyword">this</span>.initializers.addAll(initializers);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>只是将其初始化一个名为<code>initializers</code>的集合</p>
<h4 id="getSpringFactoriesInstances的作用"><a href="#getSpringFactoriesInstances的作用" class="headerlink" title="getSpringFactoriesInstances的作用"></a><code>getSpringFactoriesInstances</code>的作用</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">private</span> <T> <span class="function">Collection<T> <span class="title">getSpringFactoriesInstances</span><span class="params">(Class<T> type)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> getSpringFactoriesInstances(type, <span class="keyword">new</span> Class<?>[] {});</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <T> <span class="function">Collection<T> <span class="title">getSpringFactoriesInstances</span><span class="params">(Class<T> type,</span></span></span><br><span class="line"><span class="function"><span class="params"> Class<?>[] parameterTypes, Object... args)</span> </span>{</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//获取当前线程的类加载器</span></span><br><span class="line"> ClassLoader classLoader = Thread.currentThread().getContextClassLoader();</span><br><span class="line"> <span class="comment">// Use names and ensure unique to protect against duplicates</span></span><br><span class="line"> <span class="comment">//获取ApplicationContextInitializer实例类并去重</span></span><br><span class="line"> Set<String> names = <span class="keyword">new</span> LinkedHashSet<>(</span><br><span class="line"> SpringFactoriesLoader.loadFactoryNames(type, classLoader));</span><br><span class="line"> <span class="comment">//根据实例类实例化对应并进行排序</span></span><br><span class="line"> List<T> instances = createSpringFactoriesInstances(type, parameterTypes,</span><br><span class="line"> classLoader, args, names);</span><br><span class="line"> AnnotationAwareOrderComparator.sort(instances);</span><br><span class="line"> <span class="keyword">return</span> instances;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>springboot</category>
</categories>
<tags>
<tag>spring boot源码</tag>
</tags>
</entry>
<entry>
<title>springboot第一次学习-搭建一个简单的项目</title>
<url>/2020/09/01/page/springboot%E7%AC%AC%E4%B8%80%E6%AC%A1%E5%AD%A6%E4%B9%A0-%E6%90%AD%E5%BB%BA%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84%E9%A1%B9%E7%9B%AE/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>阅读官方文档,官方文档中对于springboot的简单项目搭建的基本解释。</p>
<h2 id="SpringBoot中spring-parent的作用"><a href="#SpringBoot中spring-parent的作用" class="headerlink" title="SpringBoot中spring-parent的作用"></a><code>SpringBoot</code>中<code>spring-parent</code>的作用</h2><blockquote>
<p>Spring Boot provides a number of “Starters” that let you add jars to your classpath. Our applications for smoke tests use the <code>spring-boot-starter-parent</code> in the <code>parent</code> section of the POM. The <code>spring-boot-starter-parent</code> is a special starter that provides useful Maven defaults. It also provides a <a href="https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-dependency-management"><code>dependency-management</code></a> section so that you can omit <code>version</code> tags for “blessed” dependencies.</p>
</blockquote>
<ul>
<li>根据文档的翻译可以简单概括为spring-boot-starter-parent不提供依赖关系。它主要提供maven的一些默认值,一个依赖管理器用于你添加依赖的时候不需要在maven中加version。<a href="https://docs.spring.io/spring-boot/docs/current/reference/html/getting-started.html#getting-started-first-application-dependencies">原文链接</a></li>
<li><span style="color:red;">注意:其中不提供依赖的意思是,它不提供如start-web这一类的web启动依赖。即spring-boot-starter-parent不是启动程序,它只是提供了管理工具与预设置值</span></li>
</ul>
<h2 id="SpringBoot的Plugin"><a href="#SpringBoot的Plugin" class="headerlink" title="SpringBoot的Plugin"></a><code>SpringBoot</code>的<code>Plugin</code></h2><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-maven-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugin</span>></span></span><br></pre></td></tr></table></figure>
<p><code>Plugin</code>有7个features:</p>
<ul>
<li><p>Java 1.8 as the default compiler level.</p>
</li>
<li><p>UTF-8 source encoding.</p>
</li>
<li><p>A dependency management section, inherited from the <code>spring-boot-dependencies</code> POM, that manages the versions of common dependencies. This dependency management lets you omit `` tags for those dependencies when used in your own POM.</p>
</li>
<li><p>An execution of the <a href="https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/html/#goals-repackage"><code>repackage</code> goal</a> with a <code>repackage</code> execution id.</p>
</li>
<li><p>Sensible <a href="https://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html">resource filtering</a>.</p>
</li>
<li><p>Sensible plugin configuration (<a href="https://github.com/ktoso/maven-git-commit-id-plugin">Git commit ID</a>, and <a href="https://maven.apache.org/plugins/maven-shade-plugin/">shade</a>).</p>
</li>
<li><p>Sensible resource filtering for <code>application.properties</code> and <code>application.yml</code> including profile-specific files (for example, <code>application-dev.properties</code> and <code>application-dev.yml</code>)</p>
<blockquote>
<p>Since the <code>application.properties</code> and <code>application.yml</code> files accept Spring style placeholders (<code>${…}</code>), the Maven filtering is changed to use <code>@..@</code> placeholders. (You can override that by setting a Maven property called <code>resource.delimiter</code>.)</p>
</blockquote>
</li>
</ul>
<p><code>SpringBoot</code>的<code>Plugin</code>有以下7个作用,其中原文如上,下方是个人理解</p>
<ul>
<li><p><code>java8</code>作为默认的编译器</p>
</li>
<li><p><code>UTF-8</code>作为打包时候的编码方式</p>
</li>
<li><p>从spring启动依赖项POM继承的依赖项管理部分,用于管理公共依赖项的版本。这种依赖项管理允许您在自己的POM中使用这些依赖项时省略<version>标记。</p>
</li>
<li><p>不懂啥意思,直译好像是重新打包的时候会伴随一个重新打包的id</p>
</li>
<li><p><code>SpringBoot</code>中打包时候传递参数给<code>application.yml</code>配置文件,对其进行资源过滤</p>
</li>
<li><p><code>SpringBoot</code>中打包时候修改配置<code>git commit id</code>和<code>shade</code></p>
</li>
<li><p><code>SpringBoot</code>中打包时根据需求过滤不同形式的文件类型,如 <code>application.properties</code> and <code>application.yml</code></p>
<blockquote>
<p>简单来说就是从maven中的pom.xml传递参数到application.properties时,需要使用@..@引用变量。如果想修改的话,在pom.xml中的properties中通过<resource.delimiter>@<resource.delimiter>进行修改</p>
</blockquote>
</li>
</ul>
<h2 id="SpringBoot在POM中配置示例"><a href="#SpringBoot在POM中配置示例" class="headerlink" title="SpringBoot在POM中配置示例"></a><code>SpringBoot</code>在<code>POM</code>中配置示例</h2><h3 id="SpringBoot作为父项目"><a href="#SpringBoot作为父项目" class="headerlink" title="SpringBoot作为父项目"></a><code>SpringBoot</code>作为父项目</h3><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">xml</span> <span class="attr">version</span>=<span class="string">"1.0"</span> <span class="attr">encoding</span>=<span class="string">"UTF-8"</span>?></span></span><br><span class="line"><span class="tag"><<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">"http://maven.apache.org/POM/4.0.0"</span> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">modelVersion</span>></span>4.0.0<span class="tag"></<span class="name">modelVersion</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>com.example<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>myproject<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.0.0-SNAPSHOT<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"><!--设置项目的默认参数与定义环境变量--></span></span><br><span class="line"> <span class="tag"><<span class="name">properties</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">maven.compiler.source</span>></span>1.8<span class="tag"></<span class="name">maven.compiler.source</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">maven.compiler.target</span>></span>1.8<span class="tag"></<span class="name">maven.compiler.target</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">project.build.sourceEncoding</span>></span>UTF-8<span class="tag"></<span class="name">project.build.sourceEncoding</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">project.reporting.outputEncoding</span>></span>UTF-8<span class="tag"></<span class="name">project.reporting.outputEncoding</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">properties</span>></span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"><!--继承springboot作为当前项目的父项目--></span></span><br><span class="line"> <span class="tag"><<span class="name">parent</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-parent<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.3.5.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">parent</span>></span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"><!--具体的依赖关系--></span></span><br><span class="line"> <span class="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependencies</span>></span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"><!--引入springboot的管理插件--></span></span><br><span class="line"> <span class="tag"><<span class="name">build</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugins</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-maven-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugins</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">build</span>></span></span><br><span class="line"><span class="tag"></<span class="name">project</span>></span></span><br></pre></td></tr></table></figure>
<h3 id="SpringBoot不作为父项目"><a href="#SpringBoot不作为父项目" class="headerlink" title="SpringBoot不作为父项目"></a><code>SpringBoot</code>不作为父项目</h3><p>由于在公司开发的时候可能需要继承公司的父项目,因而无法继承<code>SpringBoot</code>作为父项目。可采用以下形式</p>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">xml</span> <span class="attr">version</span>=<span class="string">"1.0"</span> <span class="attr">encoding</span>=<span class="string">"UTF-8"</span>?></span></span><br><span class="line"><span class="tag"><<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">"http://maven.apache.org/POM/4.0.0"</span> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">modelVersion</span>></span>4.0.0<span class="tag"></<span class="name">modelVersion</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>com.example<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>myproject<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.0.0-SNAPSHOT<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"><!--设置项目的默认参数与定义环境变量--></span></span><br><span class="line"> <span class="tag"><<span class="name">properties</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">maven.compiler.source</span>></span>1.8<span class="tag"></<span class="name">maven.compiler.source</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">maven.compiler.target</span>></span>1.8<span class="tag"></<span class="name">maven.compiler.target</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">project.build.sourceEncoding</span>></span>UTF-8<span class="tag"></<span class="name">project.build.sourceEncoding</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">project.reporting.outputEncoding</span>></span>UTF-8<span class="tag"></<span class="name">project.reporting.outputEncoding</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">properties</span>></span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"><!--引入springboot,dependencyManagement只是声明依赖,不引入--></span></span><br><span class="line"> <span class="tag"><<span class="name">dependencyManagement</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="comment"><!-- Import dependency management from Spring Boot --></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-dependencies<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.3.5.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">type</span>></span>pom<span class="tag"></<span class="name">type</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>import<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependencyManagement</span>></span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"><!--具体的依赖关系--></span></span><br><span class="line"> <span class="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependencies</span>></span></span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> <span class="comment"><!--引入springboot的管理插件--></span></span><br><span class="line"> <span class="tag"><<span class="name">build</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugins</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-maven-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugins</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">build</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">project</span>></span></span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>springboot</category>
</categories>
<tags>
<tag>maven</tag>
</tags>
</entry>
<entry>
<title>springcloud工程搭建pom依赖</title>
<url>/2020/11/07/page/springcloud%E5%B7%A5%E7%A8%8B%E6%90%AD%E5%BB%BApom%E4%BE%9D%E8%B5%96/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>本文主要讲解<code>SpringCloud</code>项目搭建的时候涉及的<code>pom</code>文件依赖内容,以及对maven的字段的解释。在<code>SpringCloud</code>项目搭建过程中使用多模块的形式,因而主要解释多模块情况下<code>pom</code>的依赖问题</p>
<h3 id="SpringCloud父项目的pom依赖"><a href="#SpringCloud父项目的pom依赖" class="headerlink" title="SpringCloud父项目的pom依赖"></a><code>SpringCloud</code>父项目的<code>pom</code>依赖</h3><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="comment"><!-- 统一管理jar包版本 --></span></span><br><span class="line"> <span class="tag"><<span class="name">properties</span>></span></span><br><span class="line"> <span class="comment"><!--https://maven.apache.org/pom.html#Properties--></span></span><br><span class="line"> <span class="tag"><<span class="name">project.build.sourceEncoding</span>></span>UTF-8<span class="tag"></<span class="name">project.build.sourceEncoding</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">project.reporting.outputEncoding</span>></span>UTF-8<span class="tag"></<span class="name">project.reporting.outputEncoding</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">maven.compiler.source</span>></span>1.8<span class="tag"></<span class="name">maven.compiler.source</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">maven.compiler.target</span>></span>1.8<span class="tag"></<span class="name">maven.compiler.target</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">junit.version</span>></span>4.12<span class="tag"></<span class="name">junit.version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">log4j.version</span>></span>1.2.17<span class="tag"></<span class="name">log4j.version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">lombok.version</span>></span>1.16.18<span class="tag"></<span class="name">lombok.version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">mysql.version</span>></span>5.1.47<span class="tag"></<span class="name">mysql.version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">druid.version</span>></span>1.1.21<span class="tag"></<span class="name">druid.version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">mybatis.spring.boot.version</span>></span>1.3.0<span class="tag"></<span class="name">mybatis.spring.boot.version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">properties</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="comment"><!-- 子模块继承之后,提供作用:锁定版本+子modlue不用写groupId和version --></span></span><br><span class="line"> <span class="tag"><<span class="name">dependencyManagement</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="comment"><!--spring boot 2.2.2--></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-dependencies<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.2.2.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">type</span>></span>pom<span class="tag"></<span class="name">type</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>import<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="comment"><!--spring cloud Hoxton.SR1--></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-dependencies<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>Hoxton.SR1<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">type</span>></span>pom<span class="tag"></<span class="name">type</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>import<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="comment"><!--spring cloud alibaba 2.1.0.RELEASE--></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>com.alibaba.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-alibaba-dependencies<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.1.0.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">type</span>></span>pom<span class="tag"></<span class="name">type</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>import<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>mysql<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>mysql-connector-java<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>${mysql.version}<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>com.alibaba<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>druid<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>${druid.version}<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.mybatis.spring.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>mybatis-spring-boot-starter<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>${mybatis.spring.boot.version}<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>junit<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>junit<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>${junit.version}<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>log4j<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>log4j<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>${log4j.version}<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.projectlombok<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>lombok<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>${lombok.version}<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependencyManagement</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">build</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugins</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-maven-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">fork</span>></span>true<span class="tag"></<span class="name">fork</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">addResources</span>></span>true<span class="tag"></<span class="name">addResources</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugins</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">build</span>></span></span><br></pre></td></tr></table></figure>
<ul>
<li><p><code>dependencyManagement</code></p>
<p>使用方式:通常在一个组织或项目的最顶层的父<code>POM</code>中看到</p>
<p>作用:能让所有子相聚中引用一个依赖而不用显式的列出版本号。<code>Maven</code>会沿着父子层次向上找,直到找到拥有<code>dependencyManagement</code>元素的项目,然后使用其中指定的版本</p>
<p><span style="color:red">注意:</span><code>dependencyManagement</code>只是声明依赖,并不实现引入,需要子项目显示的声明需要的依赖</p>
</li>
<li><p><code>properties</code></p>
<p>作用:可以声明“变量”,可以在后续的<code>pom</code>文件中通过<code>${变量名}</code>进行使用</p>
<p><span style="color:red">注意:</span><code>maven</code>环境中有很多默认需要设置的变量,其中包括编译器版本、编码格式等</p>
</li>
</ul>
]]></content>
<categories>
<category>springcloud</category>
</categories>
<tags>
<tag>pom</tag>
</tags>
</entry>
<entry>
<title>springcloud服务注册-eureka的使用</title>
<url>/2020/12/02/page/springcloud%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C-eureka%E7%9A%84%E4%BD%BF%E7%94%A8/</url>
<content><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="\assets\css\APlayer.min.css"><script src="\assets\js\APlayer.min.js" class="aplayer-secondary-script-marker"></script><script class="meting-secondary-script-marker" src="\assets\js\Meting.min.js"></script><p>本文主要讲解<code>eureka</code>的简单使用,由于<code>eureka</code>的停更所以目前的学习只作为基础的了解。其中<code>eureka</code>的配置主要涉及pom(依赖导入)、application.yaml(配置)、代码注解这三个方面,本文主要着重在这三个方面!</p>
<h2 id="Eureka服务端"><a href="#Eureka服务端" class="headerlink" title="Eureka服务端"></a>Eureka服务端</h2><h3 id="服务端pom的引入内容"><a href="#服务端pom的引入内容" class="headerlink" title="服务端pom的引入内容"></a>服务端pom的引入内容</h3><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="comment"><!--引入最新的eureka的server端--></span></span><br><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-eureka-server<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"><span class="comment"><!--引入springboot的web启动程序--></span></span><br><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-web<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"><span class="comment"><!--引入springboot的监控,一般与web一起使用,且其提供监控api用于第三方监控开发--></span></span><br><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-actuator<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure>
<h3 id="服务端的application-yaml配置"><a href="#服务端的application-yaml配置" class="headerlink" title="服务端的application.yaml配置"></a>服务端的application.yaml配置</h3><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">7002</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="comment">#eureka服务端的实例名称</span></span><br><span class="line"> <span class="attr">hostname:</span> <span class="string">eureka7002.com</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="comment">#false表示不向注册中心注册自己</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">false</span></span><br><span class="line"> <span class="comment">#false表示自己端就是注册中心,职责是维护实例,并不需要检索服务</span></span><br><span class="line"> <span class="attr">fetch-registry:</span> <span class="literal">false</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="comment">#不是集群就按照下面的内容方式配置</span></span><br><span class="line"> <span class="comment">#设置与Eureka Server 交互的地址查询服务和注册服务都需要依赖这个地址</span></span><br><span class="line"> <span class="comment">#defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka/</span> <span class="comment">#集群指向其他eureka</span></span><br><span class="line"> <span class="attr">server:</span></span><br><span class="line"> <span class="comment"># 关闭自我保护机制,保证不可用服务被及时剔除.默认开启保护机制 true</span></span><br><span class="line"> <span class="attr">enable-self-preservation:</span> <span class="literal">false</span></span><br><span class="line"> <span class="attr">eviction-interval-timer-in-ms:</span> <span class="number">2000</span></span><br></pre></td></tr></table></figure>
<h3 id="服务端的启动代码"><a href="#服务端的启动代码" class="headerlink" title="服务端的启动代码"></a>服务端的启动代码</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//必须开启eureka的服务端注册,如果成功就会看到eureka启动成功</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableEurekaServer</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">EurekaMain7002</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span></span>{</span><br><span class="line"> SpringApplication.run(EurekaMain7002.class,args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="Eureka客户端-服务注册"><a href="#Eureka客户端-服务注册" class="headerlink" title="Eureka客户端-服务注册"></a>Eureka客户端-服务注册</h2><h3 id="客户端pom的引入内容"><a href="#客户端pom的引入内容" class="headerlink" title="客户端pom的引入内容"></a>客户端pom的引入内容</h3><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"> <span class="comment"><!-- 引入eureka客户端 --></span></span><br><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-eureka-client<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="comment"><!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --></span></span><br><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-web<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="comment"><!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --></span></span><br><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-actuator<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure>
<h3 id="客户端的application-yaml配置"><a href="#客户端的application-yaml配置" class="headerlink" title="客户端的application.yaml配置"></a>客户端的application.yaml配置</h3><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8001</span></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="comment">#此处的name会作为注册到eureka服务的名字,调用的采用此处的名字</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">cloud-payment-service</span></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="comment">#是否将自己注册到注册中心, 默认true</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">true</span></span><br><span class="line"> <span class="comment">#是否从EurekaServer抓取已有的注册信息,单机无所谓,集群必须设置为true配合ribbon使用负载均衡</span></span><br><span class="line"> <span class="attr">fetch-registry:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="comment"># defaultZone: http://localhost:7001/eureka #单机版</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka</span> <span class="comment">#集群版</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="comment">#此处如果指定了名字,那么eureka中的status处会显示此处的名字</span></span><br><span class="line"> <span class="comment">#否则会显示上面的cloud-payment-service,如果多个同样服务就分不清</span></span><br><span class="line"> <span class="attr">instance-id:</span> <span class="string">payment8001</span></span><br><span class="line"> <span class="comment">#访问路径可以显示IP地址</span></span><br><span class="line"> <span class="attr">prefer-ip-address:</span> <span class="literal">true</span></span><br><span class="line"> <span class="comment">#Eureka客户端向服务端发送心跳的时间间隔.单位为秒(默认30 秒)</span></span><br><span class="line"> <span class="attr">lease-renewal-interval-in-seconds:</span> <span class="number">1</span></span><br><span class="line"> <span class="comment">#Eureka服务端在收到最后一次心跳等待时间上限.单位为秒(默认90 秒),超时将剔除服务</span></span><br><span class="line"> <span class="attr">lease-expiration-duration-in-seconds:</span> <span class="number">2</span></span><br></pre></td></tr></table></figure>
<h3 id="客户端的启动代码与注册代码"><a href="#客户端的启动代码与注册代码" class="headerlink" title="客户端的启动代码与注册代码"></a>客户端的启动代码与注册代码</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//主启动增加EnableEurekaClient</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableEurekaClient</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PaymentMain8001</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span></span>{</span><br><span class="line"> SpringApplication.run(PaymentMain8001.class,args);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>后续所有的Controller中的调用接口都会被注册到服务中</p>
<blockquote>