-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
869 lines (638 loc) · 63.5 KB
/
index.html
File metadata and controls
869 lines (638 loc) · 63.5 KB
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
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.2.1">
<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
<link rel="mask-icon" href="/images/logo.svg" color="#222">
<link rel="stylesheet" href="/css/main.css">
<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">
<script id="hexo-configurations">
var NexT = window.NexT || {};
var CONFIG = {"hostname":"yoursite.com","root":"/","scheme":"Muse","version":"8.0.0-rc.2","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}}};
</script>
<meta name="description" content="去节点思维">
<meta property="og:type" content="website">
<meta property="og:title" content="iddunk">
<meta property="og:url" content="http://yoursite.com/index.html">
<meta property="og:site_name" content="iddunk">
<meta property="og:description" content="去节点思维">
<meta property="og:locale" content="zh_CN">
<meta property="article:author" content="iddunk">
<meta name="twitter:card" content="summary">
<link rel="canonical" href="http://yoursite.com/">
<script id="page-configurations">
// https://hexo.io/docs/variables.html
CONFIG.page = {
sidebar: "",
isHome : true,
isPost : false,
lang : 'zh-CN'
};
</script>
<title>iddunk</title>
<noscript>
<style>
.use-motion .brand,
.use-motion .menu-item,
.sidebar-inner,
.use-motion .post-block,
.use-motion .pagination,
.use-motion .comments,
.use-motion .post-header,
.use-motion .post-body,
.use-motion .collection-header { opacity: initial; }
.use-motion .site-title,
.use-motion .site-subtitle {
opacity: initial;
top: initial;
}
.use-motion .logo-line-before i { left: initial; }
.use-motion .logo-line-after i { right: initial; }
</style>
</noscript>
</head>
<body itemscope itemtype="http://schema.org/WebPage">
<div class="container use-motion">
<div class="headband"></div>
<header class="header" itemscope itemtype="http://schema.org/WPHeader">
<div class="header-inner"><div class="site-brand-container">
<div class="site-nav-toggle">
<div class="toggle" aria-label="切换导航栏">
</div>
</div>
<div class="site-meta">
<a href="/" class="brand" rel="start">
<span class="logo-line-before"><i></i></span>
<h1 class="site-title">iddunk</h1>
<span class="logo-line-after"><i></i></span>
</a>
</div>
<div class="site-nav-right">
<div class="toggle popup-trigger">
</div>
</div>
</div>
</div>
</header>
<div class="back-to-top">
<i class="fa fa-arrow-up"></i>
<span>0%</span>
</div>
<main class="main">
<div class="main-inner">
<div class="content-wrap">
<div class="content index posts-expand">
<article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2020/05/19/spring/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="iddunk">
<meta itemprop="description" content="去节点思维">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="iddunk">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2020/05/19/spring/" class="post-title-link" itemprop="url">spring源码学习(一)</a>
</h2>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2020-05-19 14:12:58 / 修改时间:14:20:51" itemprop="dateCreated datePublished" datetime="2020-05-19T14:12:58+08:00">2020-05-19</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h2 id="Spring源码学习之IoC-走马观花"><a href="#Spring源码学习之IoC-走马观花" class="headerlink" title="Spring源码学习之IoC(走马观花)"></a>Spring源码学习之IoC(走马观花)</h2><h3 id="什么是IoC"><a href="#什么是IoC" class="headerlink" title="什么是IoC"></a>什么是IoC</h3><ul>
<li>调用方不去new被调用方,而是由第三方去new</li>
</ul>
<h3 id="IoC和DI的区别"><a href="#IoC和DI的区别" class="headerlink" title="IoC和DI的区别"></a>IoC和DI的区别</h3><p> 首先,给出结论:<font color=yellow><strong>IOC是目的,DI是手段</strong></font></p>
<p> 如何理解这个结论呢?</p>
<ul>
<li>引用Martin Fowler原话</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">As a result I think we need a more specific name for this pattern. Inversion of Control is too generic a term, and thus people find it confusing. As a result with a lot of discussionwith various IoC advocates we settled on the name Dependency Injection.</span><br></pre></td></tr></table></figure>
<p>大意是</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">已经存在某种模式,该模式被称为IoC,但IoC太普遍,会让人产生疑惑,为了让表意更明确,决定用DI来精确指称那个模式。</span><br></pre></td></tr></table></figure>
<p>IoC要做的事情就是让控制反转,对象实例不再由程序员来new,这是它的目的,而IoC主要的实现方式有两种:依赖查找,依赖注入。</p>
<p>DI即Dependency Injection就是依赖注入,它只是IoC这个目的的一种实现手段,只是因为依赖注入相对于依赖查找是一种更可取的手段,使得它成了更流行的那一种,所以才导致人们总是把IoC和DI混为一谈。</p>
<h3 id="Bean是如何被初始化的"><a href="#Bean是如何被初始化的" class="headerlink" title="Bean是如何被初始化的"></a>Bean是如何被初始化的</h3><ul>
<li>首先编写一个简易demo,方便我们快速的找到IoC所做的事情</li>
</ul>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/spring/spring-ioc-1.jpg" alt="spring-ioc-1"></p>
<ul>
<li><p>从图中我们可以知道,ClassPathXmlApplicationContext是实例化Bean的关键,它把Bean加载到context,并通过getBean方法拿到Bean实例。那我们接着看看ClassPathXmlApplicationContext到底做了什么</p>
<p> <img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/spring/spring-ioc-2.jpg" alt="spring-ioc-2"></p>
</li>
<li><p>首先来看一下它的类图,大概了解一下其大致框架</p>
</li>
<li><p>从<code>ClassPathXmlApplicationContext</code>的构造函数看,最核心的就是<code>refresh()</code>函数,其他只是设一些值。<br> 而这个<code>refresh()</code>是调用父类<code>AbstractApplicationContext</code>中的<code>refresh()</code>。<br> 根据它的注解可知它是加载刷新了整个context,并且加载所有Bean定义和创建对应的单例。</p>
</li>
</ul>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/spring/spring-ioc-refresh-1.jpg" alt="spring-ioc-refresh-1"></p>
<p>那我们来看一下这个refresh函数做了什么</p>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/spring/spring-ioc-refresh-2.jpg" alt="spring-ioc-refresh-2"></p>
<p>里面有许多对于beanFactory的操作方法,重点看下<code>obtainFreshBeanFactory()</code>(重新获取一个BeanFactory)。</p>
<p>它里面有个核心的方法<code>refreshBeanFactory()</code></p>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/spring/spring-ioc-refreshBeanFactory.jpg" alt="spring-ioc-refreshBeanFactory"></p>
<p>如果已有BeanFactory,先删除所有Bean,然后关闭BeanFactory。<br>然后创建一个新的<code>ListableBeanFactory</code>,这个工厂里会预先加载所有的Bean。<br>最后核心的就是<code>loadBeanDefinitions(beanFactory)</code>。</p>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/spring/spring-ioc-loadBeanDefinitions.jpg" alt="spring-ioc-load-1"></p>
<p>它是加载Bean的定义,实现交给了下面这个方法</p>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/spring/spring-ioc-loadBeanDefinitions-1.jpg" alt="spring-ioc-load-1"></p>
<p>用的是XmlBeanDefinitionReader直接读配置文件加载Bean Definition(Bean定义)到BeanFactory。它里面一步步把xml的配置文件拆解读取,把一个个Bean Definition加载到BeanFactory里。</p>
<p>至此,已经有用一个加载好Bean Definition的BeanFactory了。<br>其他方法也是围绕BeanFactory后置处理和Context的配置准备。</p>
<h3 id="Bean又是如何被获取的"><a href="#Bean又是如何被获取的" class="headerlink" title="Bean又是如何被获取的"></a>Bean又是如何被获取的</h3><p>找到一开始的context.getBean(),查看源码找到对应的DefaultListableBeanFactory中的实现</p>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/spring/spring-ioc-getBean.jpg" alt="spring-ioc-getBean-1"></p>
<p>可以看出 拿到Bean的关键在于resolveBean方法,再次深入查看其源码</p>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/spring/spring-ioc-resolveBean.jpg" alt="spring-ioc-resolveBean"></p>
<p>如果namedBean不为空,直接从其中获取到实例返回,如果为空则获取父类的,那么我们再进到resolveNamedBean中看看</p>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/spring/spring-ioc-getBeanNameForType.jpg" alt="spring-ioc-resolveNamedBean"></p>
<p>这里通过getBeanNamesForType获取到当前Type下所有BeanName,看看spring是如何做的</p>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/spring/spring-ioc-getBeanNameForType-1.jpg" alt="spring-ioc-getBeanNamesForType"></p>
<p>两个return最终都是调用了doGetBeanNamesForType,继续往里看</p>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/spring/spring-ioc-getBeanNameForType-2.jpg" alt="spring-ioc-doGetBeanNamesForType"></p>
<p>可以看到,它是遍历BeanFactory里面维护的beanDefinitionNames和manualSingletonNames成员变量,找出命中的beanName返回。(方法很长,截图未能展示manualSingletonNames部分)</p>
<p>然后拿着这个beanName去找具体的bean实例。这里的代码比较长,在<code>AbstractBeanFactory</code>里面的<code>doGetBean()</code>中实现。</p>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/spring/spring-ioc-doGetBean.jpg" alt="spring-ioc-doGetBean"></p>
<p>大意是先尝试去找手动添加bean的单例工厂里找有没有对应的实例,没有的话就往父类beanFactory里面找,最后没有的话就生成一个。</p>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><ul>
<li>本文只是走马观花的了解IoC的大致过程,知道其中调用了哪些类等等</li>
<li>重点需要了解BeanFactory中的<strong>DefaultListableBeanFactory</strong>实现,<strong>在Spring中,实际上是把DefaultListableBeanFactory作为一个默认的功能完整的IoC容器来使用的。包含了基本IoC容器所具有的重要功能。</strong></li>
<li>知道了大致过程后接下来应该仔细阅读,了解其中所运用的设计模式,以及各个类在整个架构中担任了什么功能</li>
</ul>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2020/05/16/solidity/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="iddunk">
<meta itemprop="description" content="去节点思维">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="iddunk">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2020/05/16/solidity/" class="post-title-link" itemprop="url">Solidity之基础特性</a>
</h2>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2020-05-16 11:33:20 / 修改时间:11:44:06" itemprop="dateCreated datePublished" datetime="2020-05-16T11:33:20+08:00">2020-05-16</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h2 id="Solidity语言学习"><a href="#Solidity语言学习" class="headerlink" title="Solidity语言学习"></a>Solidity语言学习</h2><h3 id="Solidity基础特性"><a href="#Solidity基础特性" class="headerlink" title="Solidity基础特性"></a>Solidity基础特性</h3><p> 任何编程语言都有其规范的代码结构,用于表达在一个代码文件中如何组织和编写代码,Solidity也一样。</p>
<p>本节,我们将通过一个简单的合约示例,来了解智能合约的代码结构。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">pragma solidity ^0.4.25;</span><br><span class="line">contract Sample {</span><br><span class="line"></span><br><span class="line"> //State variables</span><br><span class="line"> address private _admin;</span><br><span class="line"> uint private _state;</span><br><span class="line"></span><br><span class="line"> //Modifier</span><br><span class="line"> modifier onlyAdmin() {</span><br><span class="line"> require(msg.sender == _admin, "You are not admin"); </span><br><span class="line"> _;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> //Events</span><br><span class="line"> event SetState(uint value);</span><br><span class="line"></span><br><span class="line"> //Constructor</span><br><span class="line"> constructor() public {</span><br><span class="line"> _admin = msg.sender;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> //Functions</span><br><span class="line"> function setState(uint value) public onlyAdmin {</span><br><span class="line"> _state = value;</span><br><span class="line"> emit SetState(value);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> function getValue() public view returns (uint) {</span><br><span class="line"> return _state;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>上面这段程序包括了以下功能:</p>
<ul>
<li>通过构造函数来部署合约</li>
<li>通过setValue函数设置合约状态</li>
<li>通过getValue函数查询合约状态</li>
</ul>
<p>整个合约主要分为以下几个构成部分:</p>
<ul>
<li><strong>状态变量</strong> - _admin, _state,这些变量会被永久保存,也可以被函数修改</li>
<li><strong>构造函数</strong> - 用于部署并初始化合约</li>
<li><strong>事件</strong> - SetState, 功能类似日志,记录了一个事件的发生</li>
<li><strong>修饰符</strong> - onlyAdmin, 用于给函数加一层”外衣”</li>
<li><strong>函数</strong> - setState, getState,用于读写状态变量</li>
</ul>
<p>下面将逐一介绍上述构成部分。</p>
<h4 id="状态变量"><a href="#状态变量" class="headerlink" title="状态变量"></a>状态变量</h4><p>状态变量是合约的骨髓,它记录了合约的业务信息。用户可以通过函数来修改这些状态变量,这些修改也会被包含到交易中;交易经过区块链网络确认后,修改即为生效。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uint private _state;</span><br></pre></td></tr></table></figure>
<p>状态变量的声明方式为:[类型] [访问修饰符-可选] [字段名]</p>
<h4 id="构造函数"><a href="#构造函数" class="headerlink" title="构造函数"></a>构造函数</h4><p>构造函数用于初始化合约,它允许用户传入一些基本的数据,写入到状态变量中。</p>
<p>在上述例子中,设置了_admin字段,作为后面演示其他功能的前提。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">constructor() public {</span><br><span class="line"> _admin = msg.sender;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>和java不同的是,构造函数不支持重载,只能指定一个构造函数。</p>
<h4 id="函数"><a href="#函数" class="headerlink" title="函数"></a>函数</h4><p>函数被用来读写状态变量。对变量的修改将会被包含在交易中,经区块链网络确认后才生效。生效后,修改会被永久的保存在区块链账本中。</p>
<p>函数签名定义了函数名、输入输出参数、访问修饰符、自定义修饰符。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">function setState(uint value) public onlyAdmin;</span><br></pre></td></tr></table></figure>
<p>函数还可以返回多个返回值:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">function functionSample() public view returns(uint, uint) {</span><br><span class="line"> return (1,2);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>在本合约中,还有一个配备了view修饰符的函数。这个view表示了该函数不会修改任何状态变量。</p>
<p>与view类似的还有修饰符pure,其表明该函数是纯函数,连状态变量都不用读,函数的运行仅仅依赖于参数。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">function add(uint a, uint b) public pure returns(uint) {</span><br><span class="line"> return a+b;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>如果在view函数中尝试修改状态变量,或者在pure函数中访问状态变量,编译器均会报错。</p>
<h4 id="事件"><a href="#事件" class="headerlink" title="事件"></a>事件</h4><p>事件类似于日志,会被记录到区块链中,客户端可以通过web3订阅这些事件。</p>
<p><strong>定义事件</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">event SetState(uint value);</span><br></pre></td></tr></table></figure>
<p><strong>构造事件</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">emit SetState(value);</span><br></pre></td></tr></table></figure>
<p>这里有几点需要注意:</p>
<ul>
<li><p>事件的名称可以任意指定,不一定要和函数名挂钩,但推荐两者挂钩,以便清晰地表达发生的事情.</p>
</li>
<li><p>构造事件时,也可不写emit,但因为事件和函数无论是名称还是参数都高度相关,这样操作很容易笔误将事件写成函数调用,因此不推荐。</p>
</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">function setState(uint value) public onlyAdmin {</span><br><span class="line"> _state = value;</span><br><span class="line"> //emit SetState(value);</span><br><span class="line"> //这样写也可以,但不推荐,因为很容易笔误写成setState </span><br><span class="line"> SetState(value); </span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<ul>
<li>Solidity编程风格应采用一定的规范。关于编程风格,建议参考<a href="https://learnblockchain.cn/docs/solidity/style-guide.html#id16" target="_blank" rel="noopener">这里</a></li>
</ul>
<h4 id="修饰符"><a href="#修饰符" class="headerlink" title="修饰符"></a>修饰符</h4><p>修饰符是合约中非常重要的一环。它挂在函数声明上,为函数提供一些额外的功能,例如检查、清理等工作。</p>
<p>在本例中,修饰符onlyAdmin要求函数调用前,需要先检测函数的调用者是否为函数部署时设定的那个管理员(即合约的部署人)。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">//Modifer</span><br><span class="line">modifier onlyAdmin() {</span><br><span class="line"> require(msg.sender == _admin, "You are not admin"); </span><br><span class="line"> _;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line">//Functions</span><br><span class="line">function setState(uint value) public onlyAdmin {</span><br><span class="line"> ...</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>值得注意的是,定义在修饰符中的下划线“_”,表示函数的调用,指代的是开发者用修饰符修饰的函数。在本例中,表达的是setState函数调用的意思。</p>
<h3 id="Solidity语言运行"><a href="#Solidity语言运行" class="headerlink" title="Solidity语言运行"></a>Solidity语言运行</h3><h4 id="运行方法"><a href="#运行方法" class="headerlink" title="运行方法"></a>运行方法</h4><p>通过在线ide remix来进行合约的部署与运行, remix的地址<a href="http://remix.ethereum.org/" target="_blank" rel="noopener">在这</a></p>
<h4 id="编译"><a href="#编译" class="headerlink" title="编译"></a>编译</h4><p>首先,在remix的文件ide中键入代码后,通过编译按钮来编译。成功后会在按钮上出现一个绿色对勾:</p>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/solidityStudy-1.png" alt="solidityStudy-1"></p>
<h4 id="部署"><a href="#部署" class="headerlink" title="部署"></a>部署</h4><p>编译成功后就可进行部署环节,部署成功后会出现合约实例。</p>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/solidityStudy-2.png" alt="solidityStudy-2"></p>
<h4 id="setState"><a href="#setState" class="headerlink" title="setState"></a>setState</h4><p>合约部署后,我们来调用setState(4)。在执行成功后,会产生一条交易收据,里面包含了交易的执行信息。</p>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/solidityStudy-3.png" alt="solidityStudy-3"></p>
<p>在这里,用户可以看到交易执行状态(status)、交易执行人(from)、交易输入输出(decoded input, decoded output)、交易开销(execution cost)以及交易日志(logs)。</p>
<p>在logs中,我们看到SetState事件被抛出,里面的参数也记录了事件传入的值4。</p>
<p>如果我们换一个账户来执行,那么调用会失败,因为onlyAdmin修饰符会阻止用户调用。</p>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/solidityStudy-4.png" alt="solidityStudy-4"></p>
<h4 id="getState"><a href="#getState" class="headerlink" title="getState"></a>getState</h4><p>调用getState后,可以直接看到所得到的值为4,正好是我们先前setState所传入的值:</p>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/solidityStudy-5.png" alt="solidityStudy-5"></p>
<h3 id="Solidity数据类型"><a href="#Solidity数据类型" class="headerlink" title="Solidity数据类型"></a>Solidity数据类型</h3><h4 id="整数系列"><a href="#整数系列" class="headerlink" title="整数系列"></a>整数系列</h4><p>Solidity提供了一组数据类型来表示整数, 包含无符号整数与有符号整数。每类整数还可根据长度细分,具体细分类型如下。</p>
<table>
<thead>
<tr>
<th>类型</th>
<th>长度(位)</th>
<th>有符号</th>
</tr>
</thead>
<tbody><tr>
<td>uint</td>
<td>256</td>
<td>否</td>
</tr>
<tr>
<td>uint8</td>
<td>8</td>
<td>否</td>
</tr>
<tr>
<td>uint16</td>
<td>16</td>
<td>否</td>
</tr>
<tr>
<td>…</td>
<td>…</td>
<td>否</td>
</tr>
<tr>
<td>uint256</td>
<td>256</td>
<td>否</td>
</tr>
<tr>
<td>int</td>
<td>256</td>
<td>是</td>
</tr>
<tr>
<td>int8</td>
<td>8</td>
<td>是</td>
</tr>
<tr>
<td>int16</td>
<td>16</td>
<td>是</td>
</tr>
<tr>
<td>…</td>
<td>…</td>
<td>是</td>
</tr>
<tr>
<td>int256</td>
<td>256</td>
<td>是</td>
</tr>
</tbody></table>
<h4 id="定长bytes系列"><a href="#定长bytes系列" class="headerlink" title="定长bytes系列"></a>定长bytes系列</h4><p>Solidity提供了bytes1到bytes32的类型,它们是固定长度的字节数组。</p>
<p>用户可以读取定长bytes的内容。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">function bytesSample() public {</span><br><span class="line"></span><br><span class="line"> bytes32 barray;</span><br><span class="line"> //Initialize baarray</span><br><span class="line"> //read brray[0]</span><br><span class="line"> byte b = barray[0];</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>并且,可以将整数类型转换为bytes。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">uint256 s = 1;</span><br><span class="line">bytes32 b = bytes32(s);</span><br></pre></td></tr></table></figure>
<p>这里有一个关键细节,Solidity采取大端序编码,高地址存的是整数的小端。例如,b[0]是低地址端,它存整数的高端,所以值为0;取b[31]才是1。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">function bytesSample() public pure returns(byte, byte) {</span><br><span class="line"></span><br><span class="line"> uint256 value = 1;</span><br><span class="line"> bytes32 b = bytes32(value);</span><br><span class="line"> //Should be (0, 1)</span><br><span class="line"> return (b[0], b[31]);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<h4 id="变长bytes"><a href="#变长bytes" class="headerlink" title="变长bytes"></a>变长bytes</h4><p>从上文中,读者可了解定长byte数组。此外,Solidity还提供了一个变长byte数组:bytes。使用方式类似数组,后文会有介绍。</p>
<h4 id="string"><a href="#string" class="headerlink" title="string"></a>string</h4><p>Solidity提供的string,本质是一串经UTF-8编码的字节数组,它兼容于变长bytes类型。</p>
<p>目前Solidity对string的支持不佳,也没有字符的概念。用户可以将string转成bytes。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">function stringSample() public view returns(bytes) {</span><br><span class="line"> string memory str = "abc";</span><br><span class="line"> bytes memory b = bytes(str);</span><br><span class="line"> //0x616263</span><br><span class="line"> return b;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>要注意的是,当将string转换成bytes时,数据内容本身不会被拷贝,如上文中,str和b变量指向的都是同一个字符串abc。</p>
<h4 id="address"><a href="#address" class="headerlink" title="address"></a>address</h4><p>address表示账户地址,它由私钥间接生成,是一个20字节的数据。同样,它也可以被转换为bytes20。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">function addressSample() public view returns(bytes20) {</span><br><span class="line"></span><br><span class="line"> address me = msg.sender;</span><br><span class="line"> bytes20 b = bytes20(me);</span><br><span class="line"> return b;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h4 id="mapping"><a href="#mapping" class="headerlink" title="mapping"></a>mapping</h4><p>mapping表示映射, 是极其重要的数据结构。它与java中的映射存在如下几点差别:</p>
<ul>
<li>它无法迭代keys,因为它只保存键的哈希,而不保存键值,如果想迭代,可以用开源的可迭代哈希类库</li>
<li>如果一个key未被保存在mapping中,一样可以正常读取到对应value,只是value是空值(字节全为0)。所以它也不需要put、get等操作,用户直接去操作它即可。</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">contract Sample {</span><br><span class="line"></span><br><span class="line"> mapping(uint=>string) private values;</span><br><span class="line"></span><br><span class="line"> function mappingSample() public view returns(bytes20) {</span><br><span class="line"> //put a key value pair</span><br><span class="line"> values[10] = "hello";</span><br><span class="line"></span><br><span class="line"> //read value</span><br><span class="line"> string value = values[10];</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h4 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h4><p>如果数组是状态变量,那么支持push等操作:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">contract Sample {</span><br><span class="line"></span><br><span class="line"> string[] private arr;</span><br><span class="line"></span><br><span class="line"> function arraySample() public view {</span><br><span class="line"> arr.push("Hello");</span><br><span class="line"> uint len = arr.length;//should be 1</span><br><span class="line"> string value = arr[0];//should be Hello</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>数组也可以以局部变量的方式使用,但稍有不同:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">function arraySample() public view returns(uint) {</span><br><span class="line"> //create an empty array of length 2</span><br><span class="line"> uint[] memory p = new uint[](2);</span><br><span class="line"> p[3] = 1;//THIS WILL THROW EXCEPTION </span><br><span class="line"> return p.length;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h4 id="struct"><a href="#struct" class="headerlink" title="struct"></a>struct</h4><p>Solidity允许开发者自定义结构对象。结构体既可以作为状态变量存储,也可以在函数中作为局部变量存在。 </p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">struct Person {</span><br><span class="line"> uint age;</span><br><span class="line"> string name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> Person private _person;</span><br><span class="line"></span><br><span class="line"> function structExample() {</span><br><span class="line"> Person memory p = Person(1, "alice");</span><br><span class="line"> _person = p;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>本节中只介绍了比较常见的数据类型,更完整的列表可参考Solidity<a href="https://solidity.readthedocs.io/en/latest/types.html" target="_blank" rel="noopener">官方网站</a></p>
<h3 id="全局变量"><a href="#全局变量" class="headerlink" title="全局变量"></a>全局变量</h3><p>示例合约代码的构造函数中,包含msg.sender。它属于全局变量。在智能合约中,全局变量或全局方法可用于获取和当前区块、交易相关的一些基本信息,如块高、块时间、合约调用者等。</p>
<p>比较常用的全局变量是msg变量,表示调用上下文,常见的全局变量有以下几种:</p>
<ul>
<li><p><strong>msg.sender</strong>:合约的直接调用者。</p>
<p> 由于是直接调用者,所以当处于 用户A->合约1->合约2 调用链下,若在合约2内使用msg.sender,得到的会是合约1的地址。如果想获取用户A,可以用tx.origin.</p>
</li>
<li><p><strong>tx.origin</strong>:交易的”始作俑者”,整个调用链的起点。</p>
</li>
<li><p><strong>msg.calldata</strong>:包含完整的调用信息,包括函数标识、参数等。calldata的前4字节就是函数标识,与msg.sig相同。</p>
</li>
<li><p><strong>msg.sig</strong>:msg.calldata的前4字节,用于标识函数。</p>
</li>
<li><p><strong>block.number</strong>:表示当前所在的区块高度。</p>
</li>
<li><p><strong>now</strong>:表示当前的时间戳。也可以用block.timestamp表示。</p>
</li>
</ul>
<p>这里只列出了部分常见全局变量,完整版本请参考<a href="https://solidity.readthedocs.io/en/latest/units-and-global-variables.html" target="_blank" rel="noopener">这里</a></p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2020/05/16/docker/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="iddunk">
<meta itemprop="description" content="去节点思维">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="iddunk">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2020/05/16/docker/" class="post-title-link" itemprop="url">docker基础</a>
</h2>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2020-05-16 11:18:25 / 修改时间:11:22:36" itemprop="dateCreated datePublished" datetime="2020-05-16T11:18:25+08:00">2020-05-16</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="docker"><a href="#docker" class="headerlink" title="docker"></a>docker</h1><h2 id="docker安装"><a href="#docker安装" class="headerlink" title="docker安装"></a>docker安装</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 1、yum 包更新到最新</span></span><br><span class="line">yum update</span><br><span class="line"><span class="meta">#</span><span class="bash"> 2、 安装需要的软件包,yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的</span></span><br><span class="line">yum install -y yum-utils device-mapper-persistent-data lvm2</span><br><span class="line"><span class="meta">#</span><span class="bash"> 3、 设置yum源</span></span><br><span class="line">yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo</span><br><span class="line"><span class="meta">#</span><span class="bash"> 4、 安装docker,出现输入的界面都按y</span></span><br><span class="line">yum install -y docker-ce</span><br><span class="line"><span class="meta">#</span><span class="bash"> 5、 查看docker版本,验证是否安装成功</span></span><br><span class="line">docker -v</span><br></pre></td></tr></table></figure>
<h2 id="docker架构"><a href="#docker架构" class="headerlink" title="docker架构"></a>docker架构</h2><p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/docker-frame.jpg" alt="image-20200416205059220"></p>
<ul>
<li>daemon: docker在机器上以守护进程(后台运行的进程)的形式存在,客户端发送docker命令操作该进程</li>
<li>image(镜像): 镜像就是一堆只读层(read-only layer)的统一视角,不可变</li>
<li>container:(容器): 容器 = 镜像 + 读写层,关系就像类与对象的关系;一个运行态容器(running container)被定义为一个可读写的统一文件系统加上隔离的进程空间和包含其中的进程,注意,一个容器只能有一个进程隔离空间</li>
<li>repository: 仓库,类似maven仓库,也有公共仓库和私有仓库</li>
</ul>
<h2 id="docker镜像加速"><a href="#docker镜像加速" class="headerlink" title="docker镜像加速"></a>docker镜像加速</h2><ul>
<li>打开阿里云</li>
<li>搜索容器镜像服务</li>
<li>找到镜像加速器,复制粘贴配置即可</li>
</ul>
<h2 id="docker命令"><a href="#docker命令" class="headerlink" title="docker命令"></a>docker命令</h2><h3 id="服务相关命令"><a href="#服务相关命令" class="headerlink" title="服务相关命令"></a>服务相关命令</h3><ul>
<li><p>启动docker服务</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl start docker</span><br></pre></td></tr></table></figure>
</li>
<li><p>停止docker服务</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl stop docker</span><br></pre></td></tr></table></figure>
</li>
<li><p>重启docker服务</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl restart docker</span><br></pre></td></tr></table></figure>
</li>
<li><p>查看docker服务状态</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl status docker</span><br></pre></td></tr></table></figure>
</li>
<li><p>设置开机启动docker服务</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl enable docker</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="镜像相关命令"><a href="#镜像相关命令" class="headerlink" title="镜像相关命令"></a>镜像相关命令</h3><ul>
<li><p>查看镜像</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 1、 查看所有镜像详细信息</span></span><br><span class="line">docker images </span><br><span class="line"><span class="meta">#</span><span class="bash"> 2、 查看所有镜像id</span></span><br><span class="line">docker images -q</span><br></pre></td></tr></table></figure>
</li>
<li><p>搜索镜像(查看有哪些可以下载)</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker search</span><br></pre></td></tr></table></figure>
</li>
<li><p>拉取,下载镜像</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker pull</span><br></pre></td></tr></table></figure>
</li>
<li><p>删除镜像</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 1、删除单个镜像</span></span><br><span class="line">docker rmi <imageid>|<repository:tag></span><br><span class="line"><span class="meta">#</span><span class="bash"> 2、 删除所有镜像</span></span><br><span class="line">docker rmi `docker images -q`</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="容器相关命令"><a href="#容器相关命令" class="headerlink" title="容器相关命令"></a>容器相关命令</h3><ul>
<li><p>创建并运行容器</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">docker run </span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment">####### 可配置参数</span></span></span><br><span class="line">-i 保持容器运行</span><br><span class="line">-t 分配一个终端,exit容器就会关闭</span><br><span class="line">--name 起名</span><br><span class="line">--expose 公开一个或多个端口</span><br><span class="line">-d 以(守护)后台模式运行容器,并打印容器id,进入终端需要输入 docker exec -it <name> /bin/bash,exit容器不会关闭</span><br><span class="line">-l 添加元数据</span><br><span class="line">-p <主机port>:<容器port> 将容器端口映射到主机端口</span><br><span class="line">-P 随机映射端口</span><br><span class="line">--rm 当容器退出时自动移除这个容器</span><br><span class="line">centos:7 <镜像名>:<tag>/<imageid></span><br><span class="line">/bin/bash 初始化运行命令</span><br></pre></td></tr></table></figure>
</li>
<li><p>查看正在运行的容器</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker ps</span><br></pre></td></tr></table></figure>
</li>
<li><p>查看全部容器</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker ps -a</span><br></pre></td></tr></table></figure>
</li>
<li><p>启动容器</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker start</span><br></pre></td></tr></table></figure>
</li>
<li><p>停止容器</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker stop</span><br></pre></td></tr></table></figure>
</li>
<li><p>删除容器</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker rm</span><br></pre></td></tr></table></figure>
</li>
<li><p>删除所有不在运行的容器</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker rm `docker ps -aq`</span><br></pre></td></tr></table></figure>
</li>
<li><p>查看容器信息</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker inspect</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p><a href="http://dockone.io/article/783" target="_blank" rel="noopener">深入理解docker命令</a></p>
<h2 id="docker容器的数据卷"><a href="#docker容器的数据卷" class="headerlink" title="docker容器的数据卷"></a>docker容器的数据卷</h2><h3 id="数据卷概念"><a href="#数据卷概念" class="headerlink" title="数据卷概念"></a>数据卷概念</h3><p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/docker-data-%20volume.jpg" alt="image-docker-data-volume"></p>
<p>思考:</p>
<ul>
<li>Docker容器删除后,容器中产生的数据是否会随之销毁?</li>
<li>Docker容器与外部机器是否可以直接交换文件?</li>
<li>容器之间是否可以进行数据交互?</li>
</ul>
<p>数据卷:</p>
<ul>
<li>数据卷是宿主机中的一个目录或文件</li>
<li>当容器目录和数据卷目录绑定后,对方的修改会立即同步</li>
<li>一个数据卷可以被多个容器同时挂载</li>
<li>一个容器也可以被挂载多个数据卷</li>
</ul>
<p>注意事项:</p>
<ul>
<li>目录必须是绝对路径</li>
<li>如果目录不存在,会自动创建</li>
</ul>
<p>作用:</p>
<ul>
<li>容器数据持久化</li>
<li>外部机器和容器间接通信</li>
<li>容器之间数据交换</li>
</ul>
<h3 id="配置数据卷"><a href="#配置数据卷" class="headerlink" title="配置数据卷"></a>配置数据卷</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -it --name=test -v /root/data:/root/data centos:7</span><br></pre></td></tr></table></figure>
<h3 id="数据卷容器"><a href="#数据卷容器" class="headerlink" title="数据卷容器"></a>数据卷容器</h3><p>多容器进行数据交换</p>
<ul>
<li>多个容器挂载同一个数据卷</li>
<li>数据卷容器</li>
</ul>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/docker-volume-container.jpg" alt="image-docker-volume-container"></p>
<p>配置数据卷容器</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 1、 创建启动c3数据卷容器,使用-v参数设置数据卷</span></span><br><span class="line">docker run -it --name=c3 -v /volume centos:7</span><br><span class="line"><span class="meta">#</span><span class="bash"> 2、 创建启动c1、c2容器,使用--volumes-from参数设置数据卷</span></span><br><span class="line">docker run -it --name=c1 --volumes-from c3 centos:7</span><br><span class="line">docker run -it --name=c2 --volumes-from c3 centos:7</span><br></pre></td></tr></table></figure>
<h2 id="docker应用部署"><a href="#docker应用部署" class="headerlink" title="docker应用部署"></a>docker应用部署</h2><h3 id="mysql部署"><a href="#mysql部署" class="headerlink" title="mysql部署"></a>mysql部署</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 1、搜索mysql镜像</span></span><br><span class="line">docker search mysql</span><br><span class="line"><span class="meta">#</span><span class="bash"> 2、拉取mysql镜像</span></span><br><span class="line">docker pull mysql:5.6</span><br><span class="line"><span class="meta">#</span><span class="bash"> 3、创建容器,设置端口映射、目录映射</span></span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 在/root目录下创建mysql目录用于存出mysql数据信息</span></span></span><br><span class="line">mkdir ~/mysql</span><br><span class="line">cd ~/mysql</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># -p:端口映射 -v:目录映射 -e:环境 </span></span></span><br><span class="line">docker run -id \</span><br><span class="line">-p 3306:3306 \</span><br><span class="line">--name=c_mysql \</span><br><span class="line">-v $PWD/conf:/etc/mysql/conf.d \</span><br><span class="line">-v $PWD/logs:/logs \</span><br><span class="line">-v $PWD/data:/var/lib/mysql \</span><br><span class="line">-e MYSQL_ROOT_PASSWORD=123456 \</span><br><span class="line">mysql:5.6</span><br></pre></td></tr></table></figure>
<h2 id="dockerfile"><a href="#dockerfile" class="headerlink" title="dockerfile"></a>dockerfile</h2><h3 id="镜像原理"><a href="#镜像原理" class="headerlink" title="镜像原理"></a>镜像原理</h3><p>思考:</p>
<ul>
<li>docker镜像的本质是什么?</li>
<li>docker中一个centos镜像为什么只有200M,而一个centos操作系统的iso文件要几个G?</li>
<li>docker中一个tomcat镜像为什么有500M,而tomcat的安装包才70多M?</li>
</ul>
<ul>
<li><p>docker镜像是由特殊的文件系统叠加而成</p>
<p> 最底端是bootfs,并使用宿主机的bootfs</p>
<p> 第二层是root文件系统rootfs,称为base image</p>
<p> 然后再往上可以叠加其他的镜像文件</p>
</li>
<li><p>统一文件系统(Union File System)技术能够将不同层整合成一个文件系统,为这些层提供了一个统一的视角,这样就隐藏了多层的存在,在用户的角度看来,只存在一个文件系统</p>
</li>
<li><p>一个镜像可以放在另一个镜像的上面,位于下面的镜像称为父镜像,最底部的镜像称为基础镜像</p>
</li>
<li><p>当从一个镜像启动容器时,docker会在最顶层加载一个读写文件系统作为容器</p>
</li>
</ul>
<p><img src="https://iddunk.oss-cn-shenzhen.aliyuncs.com/docker-image.png" alt="image-docker-image"></p>
<h3 id="镜像制作"><a href="#镜像制作" class="headerlink" title="镜像制作"></a>镜像制作</h3><h4 id="容器转为镜像"><a href="#容器转为镜像" class="headerlink" title="容器转为镜像"></a>容器转为镜像</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">docker commit 容器id 镜像名称:版本号</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 镜像不能直接传输,需要先压缩</span></span></span><br><span class="line">docker save -o 压缩文件名称 镜像名称:版本号</span><br><span class="line">docker load -i 压缩文件名称</span><br></pre></td></tr></table></figure>
<h4 id="dockerfile概念"><a href="#dockerfile概念" class="headerlink" title="dockerfile概念"></a>dockerfile概念</h4><ul>
<li>dockerfile是一个文本文件</li>
<li>每一条指令构建一层,基于基础镜像,最终构建成一个新的镜像</li>
</ul>
<h4 id="dockerfile制作"><a href="#dockerfile制作" class="headerlink" title="dockerfile制作"></a>dockerfile制作</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1、定义父镜像: FROM centos:7</span><br><span class="line">2、定义作者信息: MAINTAINER iddunk<iddunk@example.com></span><br><span class="line">3、执行安装vim命令: RUN yum install -y vim</span><br><span class="line">4、定义默认的工作目录: WORKDIR /usr</span><br><span class="line">5、定义容器启动执行的命令: CMD /bin/bash</span><br></pre></td></tr></table></figure>
<h4 id="springboot项目部署"><a href="#springboot项目部署" class="headerlink" title="springboot项目部署"></a>springboot项目部署</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1、制作父镜像: FROM java:8</span><br><span class="line">2、定义作者信息: MAINTAINER: iddunk<iddunk@example.com></span><br><span class="line">3、将jar包添加到容器: ADD springboot.jar app.jar </span><br><span class="line">4、定义容器启动执行的命令: CMD java -jar app.jar</span><br><span class="line">5、通过dockerfile构建: docker build -f dockerfile文件路径 -t 镜像名称:版本</span><br></pre></td></tr></table></figure>
<h2 id="docker-compose"><a href="#docker-compose" class="headerlink" title="docker compose"></a>docker compose</h2><h3 id="docker-compose概念"><a href="#docker-compose概念" class="headerlink" title="docker compose概念"></a>docker compose概念</h3><p>docker compose是一个编排多容器分布式部署的工具,提供命令集管理容器化应用的完整开发周期,包括服务构建,启动和停止。使用步骤:</p>
<ul>
<li>利用dockerfile定义运行环境镜像</li>
<li>使用docker-compose.yml定义组成应用的各服务</li>
<li>运行docker-compose up启动应用</li>
</ul>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<script>
window.addEventListener('tabs:register', () => {
let { activeClass } = CONFIG.comments;
if (CONFIG.comments.storage) {
activeClass = localStorage.getItem('comments_active') || activeClass;
}
if (activeClass) {
let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
if (activeTab) {
activeTab.click();
}
}
});
if (CONFIG.comments.storage) {
window.addEventListener('tabs:click', event => {
if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
let commentClass = event.target.classList[1];
localStorage.setItem('comments_active', commentClass);
});
}
</script>
</div>
<div class="toggle sidebar-toggle">
<span class="toggle-line toggle-line-first"></span>
<span class="toggle-line toggle-line-middle"></span>
<span class="toggle-line toggle-line-last"></span>
</div>
<aside class="sidebar">
<div class="sidebar-inner">
<ul class="sidebar-nav motion-element">
<li class="sidebar-nav-toc">
文章目录
</li>
<li class="sidebar-nav-overview">
站点概览
</li>
</ul>
<!--noindex-->
<div class="post-toc-wrap sidebar-panel">
</div>
<!--/noindex-->
<div class="site-overview-wrap sidebar-panel">
<div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
<p class="site-author-name" itemprop="name">iddunk</p>
<div class="site-description" itemprop="description">去节点思维</div>
</div>
<div class="site-state-wrap motion-element">
<nav class="site-state">
<div class="site-state-item site-state-posts">
<a href="/archives">
<span class="site-state-item-count">3</span>
<span class="site-state-item-name">日志</span>
</a>
</div>
<div class="site-state-item site-state-tags">
<span class="site-state-item-count">5</span>
<span class="site-state-item-name">标签</span>
</div>
</nav>
</div>
</div>
</div>
</aside>
<div id="sidebar-dimmer"></div>
</div>
</main>
<footer class="footer">
<div class="footer-inner">
<div class="copyright">
©
<span itemprop="copyrightYear">2020</span>
<span class="with-love">
<i class="fa fa-heart"></i>
</span>
<span class="author" itemprop="copyrightHolder">iddunk</span>
</div>
<div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/muse/" class="theme-link" rel="noopener" target="_blank">NexT.Muse</a> 强力驱动
</div>
</div>
</footer>
</div>
<script src="/lib/anime.min.js"></script>
<script src="/lib/velocity/velocity.min.js"></script>
<script src="/lib/velocity/velocity.ui.min.js"></script>
<script src="/js/utils.js"></script>
<script src="/js/motion.js"></script>
<script src="/js/schemes/muse.js"></script>
<script src="/js/next-boot.js"></script>
</body>
</html>