-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
189 lines (133 loc) · 136 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
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[Git 常用命令]]></title>
<url>%2F2019%2F05%2F22%2FGit%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E9%80%9F%E6%9F%A5%E8%A1%A8%2F</url>
<content type="text"><![CDATA[Git 常用命令大览 master 默认开发分支 Origin 默认远程版本库 Head 默认开发分支 Head^ Head的父提交 创建版本库 git clone 从远程仓库拷贝代码到本地 git init 创建 Git 库 分支与标签 git branch xxx_dev 创建名字为 xxx_dev 的分支 git branch -d xxx_dev 删除xxx_dev 的分支 git branch 查看当前的分支名称 git branch -r :查看远程分支 git merge 将 branch 分支合并到当前分支 git checkout xxx_dev 切换到名字为 xxx_dev 的分支 git checkout 可以将 HEAD 移到一个新的分支,并更新工作目录。因为可能会覆盖本地的修改,所以执行这个指令之前,你需要 stash 或者 commit 暂存区和工作区的更改。 git push origin xxx_dev 执行推送的操作,完成本地分支向远程分支的同步 git tag 查看标签 git tag xxx_dev 基于最新提交创建名字为 xxx_dev 标签 git tag -d xxx_dev 删除xxx_dev 的标签 打标签 git tag -a v1.01 -m “Release version 1.01” 提交标签到远程仓库 :git push origin --tags 查看某两次 tag 之间的 commit :git log --pretty=oneline tagA..tagB 查看某次 tag 之后的 commit :git log --pretty=oneline tagA.. git checkout 切换到指定分支或标签;可以将 HEAD 移到一个新的分支,并更新工作目录。因为可能会覆盖本地的修改,所以执行这个指令之前,你需要 stash 或者 commit 暂存区和工作区的更改。 这两个命令都是把修改从一个分支集成到另一个分支上,它们只是以非常不同的方式进行 何时使用: 如果你对修改不够果断,请使用合并操作 根据你希望的历史记录的样子,而选择使用变基或合并操作 git merge 把本地代码和已经取得的远程仓库代码合并 git rebase ,是复位基底的意思。使用变基时,意味着使用另一个分支作为集成修改的新基础 Git 提交代码时候写错 commit 信息后,如何重新设置 commit 信息? 可以通过 git commit --amend 来对本次 commit 进行修改。 修改和提交 git status 查看当前仓库的状态 git diff 查看本次修改与上次修改的内容的区别 git show 显示某次提交的内容 git show $id git add 把现在所要添加的文件放到暂存区中 git rm 从版本库中删除文件 git reset 从暂存区恢复到工作文件 git reset HEAD^ 恢复最近一次提交过的状态,即放弃上次提交后的所有本次修改 git commit 把 git add 到暂存区的内容提交到代码区中 git stash 暂存 git stash pop 恢复最近一次的暂存 git reset HEAD^ —hard 刚才的Commit后悔了,想要拆掉重做) 远程操作 git pull 抓取远程仓库所有分支更新并合并到本地 git push origin master :将本地主分支推到远程主分支 使用 git fetch 是取回远端更新,不会对本地执行 merge 操作,不会去动你的本地的内容。而 git pull 会更新你本地代码到服务器上对应分支的最新版本 git remote -v 查看远程版本库信息 git remote show 查看指定远程版本库信息 git remote add 添加远程版本库 来自于 芋道源码 Git 面试题 🦅 reset 与 rebase 有什么区别? reset 操作,不修改 commit 相关的东西,只会去修改 .git 目录下的东西。 rebase 操作,会试图修改你已经 commit 的东西,比如覆盖 commit 的历史等,但是不能使用 rebase 来修改已经 push 过的内容,容易出现兼容性问题。rebase 还可以来解决内容的冲突,解决两个人修改了同一份内容,然后失败的问题。 推荐看看 《“git reset”和“git rebase”有什么区别?》 。 🦅 reset 与 revert 与 checkout 有什么区别? 首先是它们的共同点:用来撤销代码仓库中的某些更改。 然后是不同点: 1)从 commit 层面来说: git reset ,可以将一个分支的末端指向之前的一个 commit 。然后再下次 Git 执行垃圾回收的时候,会把这个 commit 之后的 commit 都扔掉。git reset 还支持三种标记,用来标记 reset 指令影响的范围: --mixed :会影响到暂存区和历史记录区。也是默认选项; --soft :只影响历史记录区; --hard:影响工作区、暂存区和历史记录区。 注意:因为 git reset 是直接删除 commit 记录,从而会影响到其他开发人员的分支,所以不要在公共分支(比如 develop)做这个操作。 git checkout ,可以将 HEAD 移到一个新的分支,并更新工作目录。因为可能会覆盖本地的修改,所以执行这个指令之前,你需要 stash 或者 commit 暂存区和工作区的更改。 git revert ,和 git reset 的目的是一样的,但是做法不同,它会以创建新的 commit 的方式来撤销 commit ,这样能保留之前的 commit 历史,比较安全。另外,同样因为可能会覆盖本地的修改,所以执行这个指令之前,你需要 stash 或者 commit 暂存区和工作区的更改。 2)从文件层面来说 git reset ,只是把文件从历史记录区拿到暂存区,不影响工作区的内容。而且支持 --mixed、--soft 和 --hard 。 git checkout ,则是把文件从历史记录拿到工作区,不影响暂存区的内容。 git revert ,不支持文件层面的操作。 总的来说,回答关键点: 对于 commit 层面和文件层面,这三个指令本身功能差别很大。 git revert 不支持文件层面的操作。 不要在公共分支做 git reset 操作。 🦅 不小心用 git reset –hard 指令把提交理掉了,有机会救回來吗? 放心,基本上东西进了 Git 就不容易消失,它們只是以一种我们肉眼看不懂的格式存放在 Git 空间裡。我们可以透過 git reflog 指令去翻一下被 reset 的那個 Commit 的编号值,然後再做一次 git reset --hard 就可以把它救回來了。 参考资料 【状况题】听说git push -f这个指令很可怕]]></content>
</entry>
<entry>
<title><![CDATA[IntelliJ IDEA 从SVN检出Maven项目到Tomcat部署]]></title>
<url>%2F2019%2F02%2F28%2FIDEA%E8%B5%B7%E6%AD%A5%2F</url>
<content type="text"><![CDATA[起步 下载IDEA(不要下载社区版),并激活 Maven环境配置 检出项目 同一窗口查看多个项目(模块),就像eclipse一样 Tomcat 配置 启动项目 截图分步骤展示激活IDEAIntelliJ IDEA 注册码 Maven环境配置idea 自带maven,只需把settings.xml放在合适的路径下即可。 SVN检出项目 如果SVN版本控制不是svn协议,而是https协议的话,可以选中截图画框选项: 同一窗口查看多个项目(模块)idea打开 File -> Project Structure Tomcat 配置1、安装插件: 2、配置 Tomcat 端口号与项目中bootstrap.yml里面的port配置一致即可 启动。快捷键 Use ⇧⌘⏎ to complete a current statement such as if, do-while, try-catch, return (or a method call) into a syntactically correct construct (e.g. add curly braces). ⌘ + F 在当前文件进行文本查找 ⌘ + R 在当前文件进行文本替换 ⌘ + Z 撤销 ⌘ + Y 复制光标所在行 或 复制选择内容,并把复制内容插入光标位置下面;(自定义) ⌘ + X 剪切光标所在行 或 剪切选择内容 ⌘ + C 复制光标所在行 或 复制选择内容 ⌘ + D 删除光标所在行或删除选中的行(自定义) ⌘ + E 显示最近打开的文件记录列表 ⌘ + O 类大纲(自定义) ⌘ + L 在当前文件跳转到指定行处 ⌘ + G 查找下一个/移至下一个出现 ⌘ + J 插入自定义动态代码模板 ⌘ + P 根据输入的 类名 查找类文件 (自定义) ⌘ + shift + O 根据输入的 文件名 查找文件 ⇧ + F6 It is possible to rename CSS selectors directly from HTML. Position the caret at the selector to be renamed and press ⇧F6 (Refactor | Rename). ⌘ + shift + U 大小写转换 ⌘ + shift + ↩ 自动结束代码,行末自动添加分号 alt + P 显示方法的参数信息(自定义) ⌘ + N 生成代码(getter、setter、构造函数、hashCode/equals,toString) ⌘ + shift+V 从最近的缓冲区粘贴 Use ⌘↑ keyboard shortcut to show the navigation bar, and arrow keys to locate the necessary files or folders. ⌘ + shift+上/下箭头 向上或向下移动 ⌘ + alt + L 可以再src 下直接Optimize imports ⌃ + alt + O 自动导包 四、Compile and Run(编译和运行) ⌘F9 编译Project ⌘⇧F9 编译选择的文件、包或模块 ⌃⌥R 弹出 Run 的可选择菜单 ⌃⌥D 弹出 Debug 的可选择菜单 ⌃R 运行 ⌃D 调试 ⌃⇧R, ⌃⇧D 从编辑器运行上下文环境配置 五、Debugging(调试) F8 进入下一步,如果当前行断点是一个方法,则不进入当前方法体内 F7 进入下一步,如果当前行断点是一个方法,则进入当前方法体内,如果该方法体还有方法,则不会进入该内嵌的方法中 ⇧F7 智能步入,断点所在行上有多个方法调用,会弹出进入哪个方法 ⇧F8 跳出 ⌥F9 运行到光标处,如果光标前有其他断点会进入到该断点 ⌥F8 计算表达式(可以更改变量值使其生效) ⌘⌥R 恢复程序运行,如果该断点下面代码还有断点则停在下一个断点上 ⌘F8 切换断点(若光标当前行有断点则取消断点,没有则加上断点) ⌘⇧F8 查看断点信息]]></content>
</entry>
<entry>
<title><![CDATA[CentOS 7 安装配置分布式文件系统FastDFS]]></title>
<url>%2F2019%2F01%2F04%2FCentOS%207%20%E5%AE%89%E8%A3%85%E9%85%8D%E7%BD%AE%E5%88%86%E5%B8%83%E5%BC%8F%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9FFastDFS%2F</url>
<content type="text"><![CDATA[简介感谢淘宝资深架构师余庆大神开源了如此优秀的轻量级分布式文件系统,记录一下FastDFS V5.05在CentOS7中的安装与配置。 首先简单了解一下基础概念,FastDFS是一个开源的轻量级分布式文件系统,由跟踪服务器(tracker server)、存储服务器(storage server)和客户端(client)三个部分组成,主要解决了海量数据存储问题,特别适合以中小文件(建议范围:4KB < file_size <500MB)为载体的在线服务。 下载包 libfastcommon-1.0.7.tar.gzFastDFS_v5.05.tar.gznginx-1.8.0.tar.gz FastDFS的两个核心概念分别是: Tracker(跟踪器) Tracker主要做调度工作,相当于mvc中的controller的角色,在访问上起负载均衡的作用。跟踪器和存储节点都可以由一台或多台服务器构成,跟踪器和存储节点中的服务器均可以随时增加或下线而不会影响线上服务,其中跟踪器中的所有服务器都是对等的,可以根据服务器的压力情况随时增加或减少。 Tracker负责管理所有的Storage和group,每个storage在启动后会连接Tracker,告知自己所属的group等信息。并保持周期性的心跳,tracker根据storage的心跳信息,建立group==>[storage server list]的映射表,Tracker需要管理的元信息很少,会全部存储在内存中。 另外tracker上的元信息都是由storage汇报的信息生成的,本身不需要持久化任何数据,这样使得tracker非常容易扩展,直接增加tracker机器即可扩展为tracker cluster来服务,cluster里每个tracker之间是完全对等的,所有的tracker都接受stroage的心跳信息,生成元数据信息来提供读写服务。 Storage(存储节点) Storage采用了分卷[Volume](或分组[group])的组织方式,存储系统由一个或多个组组成,组与组之间的文件是相互独立的,所有组的文件容量累加就是整个存储系统中的文件容量。 一个卷[Volume](组[group])可以由一台或多台存储服务器组成,一个组中的存储服务器中的文件都是相同的,组中的多台存储服务器起到了冗余备份和负载均衡的作用,数据互为备份,存储空间以group内容量最小的storage为准,所以建议group内的多个storage尽量配置相同,以免造成存储空间的浪费。 参考资料: CentOS 7 安装配置分布式文件系统FastDFS]]></content>
</entry>
<entry>
<title><![CDATA[Quartz 分布式任务]]></title>
<url>%2F2018%2F11%2F28%2FQuartz%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1%E7%9B%B8%E5%85%B3%E8%A1%A8%E4%BB%8B%E7%BB%8D%2F</url>
<content type="text"><![CDATA[1. qrtz_job_details:存储每一个已配置的 jobDetail 的详细信息 表字段 含义 sched_name 调度名称 job_name 集群中job的名字,该名字用户自己可以随意定制,无强行要求 job_group 集群中job的所属组的名字,该名字用户自己随意定制,无强行要求 description 相关介绍 job_class_name 集群中个notejob实现类的完全包名,quartz就是根据这个路径到classpath找到该job类 is_durable 是否持久化,把该属性设置为1,quartz会把job持久化到数据库中 is_nonconcurrent 是否并发 is_update_data 是否更新数据 requests_recovery 是否接受恢复执行,默认为false,设置了RequestsRecovery为true,则该job会被重新执行 job_data 一个blob字段,存放持久化job对象 2. qrtz_triggers: 保存触发器的基本信息 表字段 含义 sched_name 调度名称 trigger_name 触发器的名字,该名字用户自己可以随意定制,无强行要求 trigger_group 触发器所属组的名字,该名字用户自己随意定制,无强行要求 job_name qrtz_job_details表job_name的外键 job_group qrtz_job_details表job_group的外键 description 相关介绍 next_fire_time 上一次触发时间(毫秒) prev_fire_time 下一次触发时间,默认为-1,意味不会自动触发 priority 优先级 trigger_state 当前触发器状态,设置为ACQUIRED,如果设置为WAITING,则job不会触发 trigger_type 触发器的类型,使用cron表达式 start_time 开始时间 end_time 结束时间 calendar_name 日程表名称,表qrtz_calendars的calendar_name字段外键 misfire_instr 措施或者是补偿执行的策略 job_data 一个blob字段,存放持久化job对象 3. qrtz_cron_triggers:存储触发器的cron表达式表。 表字段 含义 sched_name 调度名称 trigger_name qrtz_triggers表trigger_name的外键 trigger_group qrtz_triggers表trigger_group的外键 cron_expression cron表达式 time_zone_id 时区 4. qrtz_scheduler_state:存储集群中note实例信息,quartz会定时读取该表的信息判断集群中每个实例的当前状态。 表字段 含义 sched_name 调度名称 instance_name 之前配置文件中org.quartz.scheduler.instanceId配置的名字,就会写入该字段 ,如果设置为AUTO,quartz会根据物理机名和当前时间产生一个名字 last_checkin_time 上次检查时间 checkin_interval 检查间隔时间 5. qrtz_blob_triggers:Trigger 作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时候) 表字段 含义 sched_name 调度名称 trigger_name qrtz_triggers表trigger_name的外键 trigger_group qrtz_triggers表trigger_group的外键 blob_data 一个blob字段,存放持久化Trigger对象 6. qrtz_calendars:以 Blob 类型存储存放日历信息, quartz可配置一个日历来指定一个时间范围。 表字段 含义 sched_name 调度名称 calendar_name 日历名称 calendar 一个blob字段,存放持久化calendar对象 7. qrtz_fired_triggers:存储与已触发的 Trigger 相关的状态信息,以及相联 Job 的执行信息。 表字段 含义 sched_name 调度名称 entry_id 调度器实例id trigger_name qrtz_triggers表trigger_name的外键 trigger_group qrtz_triggers表trigger_group的外键 instance_name 调度器实例名 fired_time 触发的时间 sched_time 定时器制定的时间 priority 优先级 state 状态 job_name 集群中job的名字,该名字用户自己可以随意定制,无强行要求 job_group 集群中job的所属组的名字,该名字用户自己随意定制,无强行要求 is_nonconcurrent 是否并发 requests_recovery 是否接受恢复执行,默认为false,设置了RequestsRecovery为true,则会被重新执行 8. qrtz_locks:存储程序的悲观锁的信息(假如使用了悲观锁)。 表字段 含义 sched_name 调度名称 lock_name 悲观锁名称 9. qrtz_paused_trigger_grps:存储已暂停的 Trigger 组的信息。 表字段 含义 sched_name 调度名称 trigger_group qrtz_triggers表trigger_group的外键 10. qrtz_paused_trigger_grps:存储已暂停的 Trigger 组的信息。 表字段 含义 sched_name 调度名称 trigger_group qrtz_triggers表trigger_group的外键 11. qrtz_simple_triggers:存储简单的 Trigger,包括重复次数,间隔,以及已触发的次数。 sched_name 调度名称 trigger_name qrtztriggers表trigger name的外键 trigger_group qrtz_triggers表trigger_group的外键 repeat_count 重复的次数统计 repeat_interval 重复的间隔时间 times_triggered 已经触发的次数 12. qrtz_simprop_triggers:存储CalendarIntervalTrigger和DailyTimeIntervalTrigger 表字段 含义 SCHED_NAME 调度名称 TRIGGER_NAME qrtztriggers表trigger name的外键 TRIGGER_GROUP qrtz_triggers表trigger_group的外键 STR_PROP_1 String类型的trigger的第一个参数 STR_PROP_2 String类型的trigger的第二个参数 STR_PROP_3 String类型的trigger的第三个参数 INT_PROP_1 int类型的trigger的第一个参数 INT_PROP_2 int类型的trigger的第二个参数 LONG_PROP_1 long类型的trigger的第一个参数 LONG_PROP_2 long类型的trigger的第二个参数 DEC_PROP_1 decimal类型的trigger的第一个参数 DEC_PROP_2 decimal类型的trigger的第二个参数 BOOL_PROP_1 Boolean类型的trigger的第一个参数 BOOL_PROP_2 Boolean类型的trigger的第二个参数]]></content>
</entry>
<entry>
<title><![CDATA[Quartz Best Practices]]></title>
<url>%2F2018%2F06%2F20%2FQuartz%20Best%20Practices%2F</url>
<content type="text"><![CDATA[最佳实践 Production System Tips JobDataMap Tips Trigger Tips JDBC JobStore Daylight Savings Time Jobs Listeners (TriggerListener, JobListener, SchedulerListener Exposing Scheduler Functionality Through Applications 生产环境中的建议跳过检查更新通过配置 “org.quartz.scheduler.skipUpdateCheck: true” 属性,你能够取消检查更新。 JobDataMap 建议Only Store Primitive Data Types (including Strings) In the JobDataMap,避免序列化问题 Use the Merged JobDataMap在任务执行的时候,JobExecutionContext中的JobDataMap作为一个convenience。它是通过在JobDetail中的JobDataMap和Trigger中的JobDataMap合并而来,后者中的值会覆盖前面一个中同名变量的值。 当你有一个任务在scheduler中,而且这个任务又会被多个Triggers重复使用,那么你最好把值存在Trigger的JobDataMap中,这样对于每次独立的任务触发时,你就可以为Job提供不同的数据输入啦。 根据以上所述,我们提出了如下的最佳实践:在调用Job.execute(…)方法时,一般来说应该从JobExecutionContext中的JobDataMap中解析变量的值,而不是直接从JobDetail的JobDataMap中解析。 Trigger 建议Use TriggerUtils 提供了一个简单的方法来创建triggers(schedules) 有很多不同的方法通过schedules来创建triggers以满足特定的描述,这个要比直接实例化特定类型的triggers(SimpleTrigger,CronTrigger等)然后调用不同的setter方法来配置它们方便许多 提供了一个简单的方法来创建日期(比如start/end日期) 提供了分析triggers的助手(e.g. calculating future fire times) JDBC JobStore永远都不要直接往Quartz的表中写数据Writing scheduling data directly to the database (via SQL) rather than using scheduling API:永远不要在同一个Database将一个Non-Clustered Scheduler 指向另一个相同名字的Scheduler NameIf you point more than one scheduler instance at the same set of database tables, and one or more of those instances is not configured for clustering, any of the following may occur: 会造成数据腐化(被删除的数据,混乱的数据) 会造成任务在到达执行点的时候像没有执行就消失了 会造成当触发时间到来时,而任务还未执行 可能会造成死锁 Ensure Adequate Datasource Connection Size建议将你的数据源连接数配置为配置为线程池中工作线程数加3。如果你的应用还要经常调用scheduler的API,那么你还需要增加额外的connections。If you are using JobStoreCMT, the “non managed” datasource should have a max connection size of at least four. Daylight Savings TimeAvoid Scheduling Jobs Near the Transition Hours of Daylight Savings Time注意:本地的时钟向前或者向后转移时和总的时间的细节可以在如下链接中找到:https://en.wikipedia.org/wiki/Daylight_saving_time_by_country. SimpleTriggers不受夏令时的影响,这是因为它们总是在毫秒时刻被精确地触发,并且在进过了精确的毫秒数之后会再次被触发。 由于CronTriggers会在给定的时/分/秒被触发,当夏令时转移时到来的时候,它们会受到这些怪事的影响。 举一个可能发生的例子,在夏令时的美国时区/位置进行调度的时候,如果使用CronTrigger并且调度的触发时间是在1:00 AM和2:00 AM之间时会发生下列的问题: 1:05 AM may occur twice! - duplicate firings on CronTrigger possible 2:05 AM may never occur! - missed firings on CronTrigger possible Again, specifics of time and amount of adjustment varies by locale. 其他的触发器类型是根据日历的移动而不是根据确切的时间量来进行的,例如CalenderIntervalTrigger,将会同样地受影响,但不是错过触发或者触发两次,而是将它的触发时间偏移一个小时。 Jobs等待条件来到长时间运行的任务会阻止其他任务的运行(如果在线程池中所有的线程都繁忙)。 如果你认为需要调用 Thread.sleep() 这个方法来停止工作线程执行任务,这是一个典型的信号,任务不会完成其余的任务,因它必须等待某些条件的到来(比如某些数据可读)。 一个更好的方法是释放线程 (exit the job) 并且允许其他任务在这个线程执行。任务可以重新调度自己,或者在它退出之前其他任务。 抛出异常一个任务的执行方法应该包含在try-catch块中,以此处理可能发生的异常。 如果一个任务抛出一个异常,Quartz一般会马上再执行它(可能会抛出相同的异常)。最好是任务捕获所有它可能遇到的异常并处理它们,然后重新调度自己或其他的任务。 可恢复性和幂等性In-progress Jobs marked “recoverable” are automatically re-executed after a scheduler fails. This means some of the job’s “work” will be executed twice. This means the job should be coded in such a way that its work is idempotent. 监听器(TriggerListener, JobListener, SchedulerListener)Keep Code In Listeners Concise And EfficientKeep Code In Listeners Concise And EfficientPerforming large amounts of work is discouraged, as the thread that would be executing the job (or completing the trigger and moving on to firing another job, etc.) will be tied up within the listener. 处理异常每个监听器的方法都应该在try-catch块中处理所有可能的异常。 如果一个监听器抛出了一个异常,可能会造成其他的监听器无法被通知到或阻止其他任务的执行等。 通过应用来暴露调度器的功能Be Careful of Security!有的用户通过应用程序接口来暴露Quartz的调度功能。这会非常有用,虽它可能会造成极度的危险。 确保你没有错误地允许用户定义他们想要的任何参数和任何类型的任务。例如,Quartz会带有一个预定的任务org.quartz.jobs.NativeJob,这个任务将会在它们定义的任意的本地系统上执行命令。恶意的用户可能会使用这个来控制或者摧毁你的系统。 同样的像 SendEmailJob 之类的任务,并且事实上任何其他的任务都可以被当作恶意用途。 如果允许用户定义任意他们想要的任务将会是你的系统遭受各种可能的危害,等同于 OWASP 和 MITRE 定义的命令注入攻击等。 参考在此:Quartz Best Practices(http://www.quartz-scheduler.org/documentation/best-practices.html)]]></content>
</entry>
<entry>
<title><![CDATA[网线接口转换器 苹果Mac集线器HUB接硬盘]]></title>
<url>%2F2018%2F06%2F05%2FMac%20%E7%BD%91%E7%BA%BF%E6%8E%A5%E5%8F%A3%E8%BD%AC%E6%8D%A2%E5%99%A8%E7%9A%84%E6%AD%A3%E7%A1%AE%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95%2F</url>
<content type="text"><![CDATA[Mac 连接网线以我在京东上购买的 毕亚兹(biaze) USB分线器3.0 千兆有线网卡 USB转RJ45网线接口转换器 苹果Mac集线器HUB接硬盘 ZH17-金属银 为例: ~ csrutil status System Integrity Protection status: enabled (Custom Configuration). Configuration: Apple Internal: disabled Kext Signing: enabled Filesystem Protections: enabled Debugging Restrictions: disabled DTrace Restrictions: enabled NVRAM Protections: enabled BaseSystem Verification: enabled This is an unsupported configuration, likely to break in the future and leave your machine in an unknown state. ~ 首先,SIP status 必须是 disabled 状态才行,可以通过以下步骤设置:1、重启电脑2、按住command+r进入恢复模式3、点击顶部菜单栏实用工具中的终端,(可以输入csrutil status检查状态)4、然后输入csrutil disable 其次,下载驱动,选择 MAC OS 10.6 to 10.13 版本,下载安装。 最后,重启电脑。此时,关闭Wi-Fi 网络,试试网络吧。公司网络应该是用网线连接上了。]]></content>
</entry>
<entry>
<title><![CDATA[亿级流量网站架构核心技术]]></title>
<url>%2F2018%2F05%2F14%2F%E9%AB%98%E5%8F%AF%E7%94%A8%E4%B8%8E%E9%AB%98%E5%B9%B6%E5%8F%91%2F</url>
<content type="text"><![CDATA[跟开涛学搭建高可用高并发系统本书将介绍缓存、异步并发、连接池、线程池、如何扩容、消息队列、分布式任务等高并发原则来提升系统吞吐量。 通过负载均衡和反向代理实现分流,通过限流 保护服务免受雪崩之灾,通过降级实现部分可用、有损服务,通过隔离实现故障隔离,通过设置合理的超时与重试机制避免请求堆积造成雪崩,通过回滚机制快速修复错误版本;使得系统高可用。]]></content>
</entry>
<entry>
<title><![CDATA[那些年我看过的书]]></title>
<url>%2F2018%2F03%2F14%2Frecommend-books%2F</url>
<content type="text"><![CDATA[开头2012年底正式参加工作,先后经历了三家单位(软通、必联(北京)电子商务、北京四合天地科技),有短有长(补充:2018-06入职互金行业了)。有的得到了经验,有的在那里得到了成长。不付青春吧。期间也认识了不少志同道合的好同事,有些也成为了好朋友。技术道路上还需披荆斩棘,更进一步。回首往事,才能更好的展望未来。 技术书籍推荐(90%都是购买的书籍,偏爱)有些是在京东上购买的书籍,有些是在异步社区上购买的,还有些就是嘟嘟独立博客电子书互助计划得到的。1、 《Java 核心技术》卷一 、卷二 两本书,算是入门比较好的书籍了2、 Thinking in Java (Java 编程思想)GitBook 可下载阅读。第13章没有编辑,Java的GUI现在应用少,正合我意。3、 《Java 并发编程实战》4、 《实战Java高并发程序设计》5、 Effective Java 中文版 第2版GitBook 可下载阅读。算是 Java 的进阶书籍了,面试好多问题也是从这出来的6、 《图解数据结构-使用Java》7、 《Spring揭秘》8、 《设计模式之禅(第2版)》9、 《Redis实战》异步社区,购买的正版电子图书。超级清晰。在此推广一波10、《MyBatis从入门到精通__刘增辉(著)》11、《Android群英传:神兵利器》12、《图解HTTP》对互联网基盘-HTTP协议进行了全面系统的介绍13、《图解TCP/IP(第5版)》14、《Spring Boot实战 ,丁雪丰 (译者) 》15、《阿里巴巴Java开发手册(终极版)》 算法1、《数据结构与算法分析-Java语言描述 第3版》木有坚持读下来2、《算法 第4版》木有坚持读下来3、《程序员的数学1》4、《程序员的数学2:概率统计》5、《程序员的数学3:线性代数》 架构1、《大型网站技术架构:核心原理与案例分析》2、《淘宝技术这十年》3、《亿级流量网站架构核心技术(跟开涛学搭建高可用高并发系统)》4、《深入分布式缓存:从原理到实践》5、《Spring Cloud微服务实战》6、《架构探险:轻量级微服务架构(上)》黄勇。由此加入了勇哥建立的微信群,大佬云集7、《分布式服务框架原理与实践》8、《Netty权威指南第二版》 优秀博客推荐1、万维钢 用理工科思维理解世界2、刘未鹏3、酷壳-陈皓4、开涛的博客5、chenssy Java并发编程实战 人文书籍推荐1、《暗时间》 刘未鹏 | Mind Hacks思维改变生活2、《数学之美 (第二版)》吴军博士的,“数学之美”系列文章原刊载于谷歌黑板报3、《浪潮之巅》同样也是吴军博士的4、《三国机密》、《三国配角演义》马伯庸老爷子,有“文字鬼才”之誉5、《北京折叠》6、《人类简史》7、《万万没想到:用理工科思维理解世界》万维钢8、《黑客与画家》9、《如何变得有意思:阮一峰博客文集》10、《MacTalk 跨越边界》11、《禅与摩托车维修艺术》 商业、经济、财经1、《联盟:互联网时代的人才变革》参加了樊登读书会,因而知道的这本书2、《重新定义公司:谷歌是如何运营的》3、《罗辑思维 有种·有料·有趣》4、《魔鬼经济学》也是罗辑思维视频节目了解到的,共四册;只读了前两册。5、《从0到1开启商业与未来的秘密》6、《怪诞行为学:可预测的非理性》7、《怪诞行为学2:非理性的积极力量》8、《三体:黑暗森林》9、《我在碧桂园的1000天》电子版内部使用。以财务之眼看杨国强和他的地产王国。在碧桂园人称“三斌”之一吴建斌 著; 工具Git : 廖雪峰的 Git 教程IDEA:IntelliJ IDEA 简体中文专题教程Maven:《Maven实战》 程序员的自我修养1、《程序员修炼之道-从小工到专家》2、《代码整洁之道》3、《重构:改善既有代码的设计》4、《软技能:代码之外的生存指南》 程序员除了写代码,还得懂点其他的软技能 生活、其他1、《悟空传》今何在。有这样一群人,他们宁肯死,也不肯输。2、《煮酒探西游》吴闲云3、《我不是潘金莲》刘震云的几乎都买来读过;12年、13年那两年很喜欢读他的书,一句顶一万句,温故一九四二、一地鸡毛、温故一九四二。4、《人民的名义》影视剧开播前就已经读完了,电视剧还是追了。5、《你我皆凡人》:从金庸武侠里读出来的现实江湖(六神磊磊处女作)。有微信大号“六神磊磊读金庸”,置顶公众号,粉丝支持所以买了这本书。6、《为什么你总是害怕来不及》7、《从你的全世界路过》张嘉佳8、《儒林外史》、三言两拍;9、《万历十五年》 计划要看的电子书1、《编程之法:面试和算法心得_迷你书》2、《架构即未来 现代企业可扩展的Web架构流程和组织原书第2版》3、《一线架构师实践指南》4、《O2O实战+他们是如何利用互联网的》5、《实战Elasticsearch、Logstash、Kibana++分布式大数据搜索与日志挖掘及可视化解决方案》6、《数据库查询优化器的艺术:原理解析与SQL性能优化》 最后个人认为,作为程序员不要吝啬对自己的投资,只有自己强大了才能更好的赚钱。每年都要买几本书投资一下,未来的回报会超出你的想象的,博主先准备把2017年买的书先看完先。]]></content>
</entry>
<entry>
<title><![CDATA[Spring Cloud构建微服务架构]]></title>
<url>%2F2018%2F03%2F07%2FSpring%20Boot%E6%9E%84%E5%BB%BA%E5%BE%AE%E6%9C%8D%E5%8A%A1%2F</url>
<content type="text"><![CDATA[接触Spring Boot2016年 Spring Boot 还没有被广泛使用,到了现在经过2年的发展,很多互联网公司已经将 Spring Boot 搬上了生产,而使用 Spring Boot 的开源项目在 Github/码云 上面已有不少,很有必要开启一波学习潮了。 听到了一句挺中肯的话,“离开场景和业务的修炼都是伪命题”。所以呢,有必要总结一下Spring Boot 相关的开源项目,选取一个感兴趣的,然后深入学习提交pr,真正的提高自己的技术能力。 搜集 springcloud-app/dubbo-app 海信商业云平台的微服务落地实践马映辉 群分享 如何把复杂单体应用快速迁移到微服务 Spring Boot干货系列总纲 Spring Boot 那些事 Spring Boot基础教程 [江南一点雨(Spring Cloud教程合集)]作者参考了程序猿DD(翟永超)一书《Spring Cloud微服务实战》,可用来作为辩证学习的素材。 [江南一点雨] https://github.com/lenve 沉思录 Spring Cloud中国社区创始人,业余主要研究Spring Cloud。我们微信群猪的博客,强力推荐。 有思想的博客站点 黄勇 群主,强力推荐。 纯洁的微笑 微笑大佬,我们【原创技术博客作者交流群】群主。 程序猿DD 嘟嘟独立博客 泥瓦匠BYSocket 小柒2012 周立 Aresn iView 主力开发者 花裤衩(手摸手,带你用vue撸后台) 老齐 Goileo Lee 许彬 stormzhang 简单之美 独孤求胜 马勇发 任玉刚 见识(web前端) 猴子007 Litten IMWeb前端博客 Blankj 有个非常知名的 awesome-java-leetcode https://blankj.com/ 郭霖 张鸿洋 http://www.wanandroid.com/ 张鸿洋运营 eclipse_xu 《Android群英传:神兵利器》,买了读过。有意思的人儿 Lawlite zhisheng JumpByte 结构之法 算法之道 酷壳-陈皓 江南白衣 老司机 芋道源码的博客 文斌兄的地盘,另外也有知识星球,可以加入我们。 你假笨@JVM I WANNA RUN MOxFIVE Yelee主题开发者,很美观。 YouMeek 终极搜寻 Spring Cloud中国社区 http://www.spring4all.com/ Spring Boot 中文索引 Spring Boot 开源软件都有哪些? http://www.gitnavi.com/ 结语朋友圈里看到了一句话,觉得特别好:不善于总结的人,就是在吃老本,吃惯性,吃你的智商和知识。所以呢建立博客,有的没的写一些技术、生活相关的东西,但愿不辜负青春,便想努力留下印记。]]></content>
</entry>
<entry>
<title><![CDATA[Mac之神兵利器]]></title>
<url>%2F2018%2F03%2F05%2FMac%E4%B9%8B%E7%A5%9E%E5%85%B5%E5%88%A9%E5%99%A8%2F</url>
<content type="text"><![CDATA[接触Mac我是2016年底买的Mac,原因是在那时候通读了《MacTalk 跨越边界》、《MacTalk 人生元编程》这两本书,顿觉打开了一扇大门。随即宣告了我的联想Y570正式退役。现如今Mac上的开发利器、效率工具也装了不少,也该是从资料库整理一下的时机了。 搜集Mac Mac使用 Alfred 提高你的工作效率 神兵利器——Alfred 推荐几款我最喜爱的 Mac 软件(非技术) 从 Mac OS 到 macOS,一个新的轮回 Mac 与 Windows 的虚妄之争 程序员最常用的十个 Mac 工具(上) 程序员最常用的十个 Mac 工具(中) 程序员最常用的十个 Mac 工具(下) 我在大学里学到的几件事 OmniFocus 2 Pro for Mac 2.10 序号版 - 最优秀的GTD效率工具 Parallels Desktop 13 for Mac 13.2.0.43213 破解版 - Mac上最优秀的虚拟机 Paragon NTFS for Mac付费购买 CleanMyMac 3付费购买 Contexts 3花钱购买的 有思想的读物 普通程序员能实现财务自由吗? 罗永浩-酷玩实验室 终极搜寻 爱情守望者 爱范儿]]></content>
</entry>
<entry>
<title><![CDATA[区块链与比特币破冰]]></title>
<url>%2F2018%2F01%2F23%2F%E5%8C%BA%E5%9D%97%E9%93%BE%E4%B8%8E%E6%AF%94%E7%89%B9%E5%B8%81%E7%A0%B4%E5%86%B0%2F</url>
<content type="text"><![CDATA[大咖说池大大在2018 年技术趋势预测中写道: 区块链是可以改变世界的发明。区块链源起比特币,但并不局限在币圈。区块链技术是储存、验证和数据保护等问题的实际解决办法。区块链可被视为分散的、极度安全的数据库。更专业一点来说,区块链是分布式的点对点的基于密码学的共享账本,可以在金融服务、保险、医疗、政府等领域内被广泛应用。2018年应该是区块链技术起飞并日趋成熟的一年。 2018 年技术趋势预测 由于是在池建强 MacTalk 公众号上发布的文章,网址链接较长,这里用了https://goo.gl 做了short URL。如果不能翻墙的话,还请前往微信阅读。 疑惑不解面对比特币的疯涨诱惑,很多人按捺不住躁动:“虽然我买不起比特币,那还可以入手其它币吗?” 自从有人,就有投机的存在。但是人类历史上第一次有记载的大规模的投机事件是17世纪荷兰的郁金香泡沫。区块链存在泡沫吗? 还有 keso 描述的 区块链焦虑与错失恐惧症。 好多问题都需要我们自己来判断、决定,前提是我们需要学习、多了解一些,不管从大势上面还是技术层面上!尽力避免成为吃瓜群众,“山寨币”的韭菜。 了个究竟一个浪头打过来,最好的办法是迎上去了解个究竟,而不是漠视,或者干脆当事情没有发生。 区块链有多火? 区块链焦虑与错失恐惧症 再不懂区块链,你就OUT了! 比特币是如何被一群“囚犯”创造出来的 九分钟了解区块链 迅雷出局:想靠“山寨币”致富的人,是时候醒来搬砖了 不要试图挑战人性 一个足以颠覆微信、超越阿里的超级风口!40万亿大产业即将爆发! 中国比特币矿机垄断全球:最被忽视的制造业样本 比特币和区块链(0):骗局还是改变命运的科技 比特币和区块链(1):真钱,电子货币以及区块链 比特币和区块链(2):比特币中区块链的实现 比特币和区块链(3):比特币的共识机制 比特币和区块链(4):比特币成功的不可复制性 2018-01-25 我做比特币矿工这一年。 2018-02-02 互联网大佬谈区块链,看法爱憎分明 “币圈”暴富指南:致不愿醒来的韭菜们 2018-02-24 春节假期“三点钟”社群大佬激辩区块链2万字干货全记录,看这一篇足够了! 2018-03-02 区块链性能提升:链上设计之道 韭菜席地而坐 2018年区块链落地的现状、阻碍与机遇 |捕手志 专访陈伟星:解密加密数字经济为何是未来 |捕手志 周鸿祎:写区块链最好的一篇文章 黄渊普:关于区块链,那些骗子都知道自己是骗子 2018-03-06 ICO裹挟区块链强势重来 深入研究的套路之黑客与区块链 5天钓到40枚以太币 杂谈区块链生态里的前端黑 区块链的十个吐槽 结语2016年在接受《财经》杂志专访时,张一鸣说过的那段特别具有张一鸣色彩的话: 历史上精英们一直在试图让大众拥有很高的精神追求,但社会整体从来没有达到过这个目标。以前的媒体精英意识不到这一点,他们认为自己特别希望导向的才是特别重要的。但多数人的强烈主张,从历史上看,多数都没有产生多大价值。]]></content>
</entry>
<entry>
<title><![CDATA[如何搭建个人网站]]></title>
<url>%2F2018%2F01%2F05%2F%E5%A6%82%E4%BD%95%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BA%E7%BD%91%E7%AB%99%2F</url>
<content type="text"><![CDATA[写在开头有了个人网站,可能就又多了一些学(zhuang)习(bi)的动力吧!所以,拥有自己的网站,算是迈出了第一步! 好可惜最近才看到玉刚大神的文章,意识觉醒的晚了树立个人品牌:让名企hr们主动来找你 如何拥有自己的专属域名goileolee http://goileo.top/如何免费且快速的搭建个人网站 为 Github Pages 绑定的自定义域名启用 HTTPS 协议https://zhouhao.me/2017/07/21/using-https-with-custom-domain-name-on-github-pages/ hexo yilia主题添加文章访问量统计https://www.lookk.cn/2017/12/09/hexo-yilia主题添加文章访问量统计/ 原因在结尾在浏览器和访问的网站之间提供更安全的通讯HTTPS 比 HTTP 的速度更快能提高搜索引擎的优化排名]]></content>
</entry>
<entry>
<title><![CDATA[初探Visual Studio Code编写Vue]]></title>
<url>%2F2017%2F12%2F28%2FVisual%20Studio%20Code%2F</url>
<content type="text"><![CDATA[应用介绍https://code.visualstudio.com/界面简洁大方,^_^ Vue插件安装在 VSCode Marketplace https://marketplace.visualstudio.com/vscode 搜素Vue 出现关于语法高亮的插件有 Vue 2 Snippets,vue-beautify,vue-color,Vetur等等。花花绿绿的,往下翻看,目前使用率最高的就是Vetur了。安装插件:⌘P 然后输入 ext install vetur 然后回车点安装即可。但是如果你使用惯了Vim/Sublime/Atom等,VSCode允许安装自己的键盘快捷方式。我个人选择了Sublime,设置后并激活,这时按下command+shift+p输入 Vetur VS Code ESLint extension安装插件和Vetur类似。ESLint 不是安装后就可以用的,还需要一些环境和配置:eg:首先在自己的工作空间建立一个文件夹xmall-front,zsh中运行 npm init然后依次执行命令,快速体验下: ~/VSCodeProjects/xmall-front npm install --save-dev eslint eslint-plugin-html npm notice created a lockfile as package-lock.json. You should commit this file. npm WARN [email protected] No repository field. + [email protected] + [email protected] added 146 packages in 14.54s ~/VSCodeProjects/xmall-front ./node_modules/.bin/eslint --init ? How would you like to configure ESLint? Answer questions about your style ? Are you using ECMAScript 6 features? Yes ? Are you using ES6 modules? Yes ? Where will your code run? Browser ? Do you use CommonJS? Yes ? Do you use JSX? Yes ? Do you use React? No ? What style of indentation do you use? Tabs ? What quotes do you use for strings? Single ? What line endings do you use? Unix ? Do you require semicolons? No ? What format do you want your config file to be in? JavaScript Successfully created .eslintrc.js file in /Users/jinkui/VSCodeProjects/xmall-front ~/VSCodeProjects/xmall-front la . .. .eslintrc.js node_modules package-lock.json package.json 在 vscode 中配置下 ESLint:eslint.validate - an array of language identifiers specify the files to be validated. Something like “eslint.validate”: [ “javascript”, “javascriptreact”, “html” ]. If the setting is missing, it defaults to [“javascript”, “javascriptreact”].查看扩展:ESLint 的Settings Options,发现确实默认不支持vue文件啊。所以说虽然安装了eslint-plugin-html还是需要配置一下的:On a Mac, click Code > Preferences > Settings // An array of language ids which should be validated by ESLint "eslint.validate": [ "javascript", "javascriptreact", { "language": "html", "autoFix": true }, "vue" ] 安装插件-提高效率所有插件都类似于Sublime使用Package Control安装,按下快捷键⌘⇧P,在命令提示框搜索插件即可。 Project Manager 在多个项目之前快速切换的工具 HTML Snippets Full HTML tags including HTML5 Snippets HTML CSS Support 让 html 标签上写class 智能提示当前项目所支持的样式 jQuery Code Snippets Over 130 jQuery Code Snippets Beautify Beautify code in place for VS Code vscode-fileheader insert header comment,and automatically update the time. Bracket Pair Colorizer 让括号拥有独立的颜色,易于区分。可以配合任意主题使用 Auto Close Tag Automatically add HTML/XML close tag, same as Visual Studio IDE or Sublime Text does Auto Rename Tag Auto rename paired HTML/XML tag Bookmarks 添加行书签 Indenticator 缩进高亮 Quokka.js 不需要手动运行,行内显示变量结果 JavaScript (ES6) code snippets ES6语法代码段 language-stylus Stylus语法高亮和提示 String Manipulation 字符串转换处理(驼峰、大写开头、下划线等等) VueHelper Vue2代码段(包括Vue2 api、vue-router2、vuex2) File Peek The extension supports all the normal capabilities of symbol definition tracking, but does it for file names Path Intellisense Visual Studio Code plugin that autocompletes filenames TODO Parser Parse TODOs in your working files Git History (git log) View git log, file or line History Git Lens 显示文件最近的commit和作者,显示当前行commit信息 Git History Diff View git history. View commit details. View diff of committed files. Multi-root workspaces supported. gitignore .gitignore文件语法 npm npm commands for VSCode npm Intellisense 导入模块时,提示已安装模块名称 Output Colorizer 彩色输出信息 markdownlint Markdown linting and style checking for Visual Studio Code vscode-icons Icons for Visual Studio Code(大大的好啊) 快捷键见官网。https://code.visualstudio.com/shortcuts/keyboard-shortcuts-macos.pdf 修改默认快捷键打开默认键盘快捷方式设置: 修改 keybindings.json: // 将键绑定放入此文件中以覆盖默认值 [ // '删除一行' { "key": "cmd+d", "command": "editor.action.deleteLines", "when": "editorTextFocus && !editorReadonly" }, // 与'删除一行'的快捷键互换 { "key": "shift+cmd+k", "command": "editor.action.addSelectionToNextFindMatch", "when": "editorFocus" }, // 大小写转换快捷键,需安装 TextTransform 插件 { "key": "cmd+shift+y", "command": "editor.action.transformToUppercase", "when": "editorTextFocus" }, { "key": "cmd+shift+x", "command": "editor.action.transformtolowercase", "when": "editorTextFocus" } ] 结语开启一波Vue学习潮,干后端的也不能落伍啊 参考在此:使用Visual Studio Code编写Vue的札记vs code & Atom 对比使用心得]]></content>
</entry>
<entry>
<title><![CDATA[Mac下之Sublime Text的好用之处]]></title>
<url>%2F2017%2F12%2F27%2FSublime%20Text%2F</url>
<content type="text"><![CDATA[应用介绍Sublime Text 拥有漂亮的用户界面和非凡的功能,而根据其官网介绍,Sublime Text的特点如下:拥有高效、没有干扰的界面,在编辑方面的多选、宏、代码片段等功能,以及很有特色的Minimap。用户广受喜爱的众多功能之一GOTO ANYTHING仅仅敲击几次键盘就能即刻jump to symbols, lines or words.Shortcuts: ⌘ + P 要支持一把的官网购买啊http://www.sublimetext.com/啊不花钱看这里:Sublime Text 3 Build 3156 主题插件安装soda-theme该插件主要能够使sublime 兼容mac的retina屏幕我采用Git安装最新版本,可以通过菜单 Preferences -> Browse Packages….,定位到你的Sublime Text Packages文件夹,然后在这个文件夹下面 git clone就OK了。 git clone https://github.com/buymeasoda/soda-theme/ "Theme - Soda" Configure Sublime Text 3 打开配置文件: Sublime Text -> Preferences -> Settings - User 添加主题:”theme”: “Soda Light 3.sublime-theme” 我自己的主题和字体配置: 插件与配置安装插件所有插件都可以使用Package Control安装,按下快捷键⌘⇧P,在命令提示框搜索插件即可。前端开发 sublime text 常用插件和配置 快捷键 符号 说明 ⌘ command ⌃ control ⌥ option ⇧ shift ↩ enter ⌫ delete Shortcuts: ⌘ + P 即刻jump to symbols, lines or words. 快捷键 功能 @ jump to symbols # 查找文件内的单词 : 跳到行号处 Preferences -> Key Bindings,在-User文件里自定义快捷键(会覆盖相应的-Default配置) 打开/关闭/前往 快捷键 功能 ⌘⇧N 打开一个新的sublime窗口 ⌘N 新建文件 ⌘⇧W 关闭sublime,关闭所有文件 ⌘W 关闭当前文件 ⌘P GOTO ANYTHING ⌘⇧T 重新打开最近关闭的文件 ⌘T 前往文件 ⌘R 前往method ⌘⇧P 命令提示 ⌃` 打开控制台 编辑 快捷键 功能 ⌘KK 从光标处删除至行尾 ⌘⌫ 从光标处删除至行首 ⌘KV paste_from_history ⌘L Select line - Repeat to select next lines ⌘D 删除行(⌃⇧K) ⌘E 选择词(重复按下时多重选择相同的词进行多重编辑)(⌘D) ⌘J 选择行(重复按下将下一行加入选择) ⌘JL Join line below to the end of the current line(⌘J) ⌃ + ⇧ + M Select all contents of the current parentheses ⌃ + M Jump to closing parentheses Repeat to jump to opening parentheses ⌘⇧↩ 在当前行前插入新行 ⌘↩ 在当前行后插入新行 ⌘+shift+y 改为大写(⌘KU) ⌘+shift+x 改为小写(⌘KL) ⌘C 复制 ⌘X 剪切 ⌘V 粘贴 ⌘Z 撤销 ⌘+shift+z 恢复撤销 ⌘y 重做 ⌘u soft_undo ⌘⇧u soft_redo ⌘/ 注释 ⌘] 向右缩进 ⌘[ 向左缩进 ⌃ + ⇧ + ↑ 一个或多行向上移动 ⌃ + ⇧ + ↓ 一个或多行向下移动 打开/关闭/前往 快捷键 功能 ⌘f 查找 ⌘⌥f 查找并替换 ⌘⌥g 查找下一个符合当前所选的内容 ⌘⌃g 查找所有符合当前选择的内容进行多重编辑 ⌘⇧F 在所有打开的文件中进行查找 ⌘ + I Incremental Find 结语Preferences -> Key Bindings,在-User文件里自定义快捷键: [ { "keys": ["super+shift+y"], "command": "upper_case" }, { "keys": ["super+shift+x"], "command": "lower_case" }, { "keys": ["super+j"], "command": "expand_selection", "args": {"to": "line"} }, { "keys": ["super+j+l"], "command": "join_lines" }, { "keys": ["super+e+s+f+s"], "command": "slurp_find_string" }, { "keys": ["super+e"], "command": "find_under_expand" }, { "keys": ["super+d"], "command": "run_macro_file", "args": {"file": "res://Packages/Default/Delete Line.sublime-macro"} } ] 参考在此:Keyboard Shortcuts - OSX]]></content>
</entry>
<entry>
<title><![CDATA[一张通往计算机世界的地图]]></title>
<url>%2F2017%2F12%2F19%2F%E4%B8%80%E5%BC%A0%E9%80%9A%E5%BE%80%E8%AE%A1%E7%AE%97%E6%9C%BA%E4%B8%96%E7%95%8C%E7%9A%84%E5%9C%B0%E5%9B%BE%2F</url>
<content type="text"><![CDATA[一张通往计算机世界的地图引述我们通过计算机来拓展我们自己的大脑。最开始计算机被用来解决和算数有关的问题,但其自身的价值很快地延伸到了各个领域。 像是运行互联网络,处理实时图像,制造人工智能,以及模拟整个宇宙等等。 而其神奇的地方就在于这一切强大功能的背后,竟然仅是 0 和 1 的来回变化。 原文作者:Surmon https://surmon.me/article/75]]></content>
</entry>
<entry>
<title><![CDATA[Redis技术交流]]></title>
<url>%2F2017%2F12%2F12%2Fredis%E6%8A%80%E6%9C%AF%E4%BA%A4%E6%B5%81%2F</url>
<content type="text"><![CDATA[Redis原理与实战,不定期更新Redis是业界普遍应用的缓存组件,研究一个组件框架,就要探究它的设计哲学。https://redis.io/ 系列文章有些是从Redis源码,有些是从数据结构、内存优化、持久化、Redis集群实现原理探讨开来。总之,很是流行,有必要多方位了解一下啦。 张铁蕾 Redis压缩列表原理与应用分析 深入浅出Redis Cluster原理 Redis 集群的合纵与连横 360开源的类Redis存储系统:Pika 动态追踪技术(中) - Dtrace、SystemTap、火焰图 QCon上海2016的幻灯片合集 QCon北京2016幻灯片下载合集 QCon 上海 2017 PPT 合集 Redis源码学习(云栖社区) 基于Redis的BloomFilter算法去重 redis过期清除机制及应用方法 由浅入深介绍 Redis LRU 策略的具体实现 Nginx+Lua+Redis搭建高并发服务 Redis的hmget操作复杂度问题 Redis中BitMap的妙用 Redis的内存优化 理解Redis的RESP协议 深入学习 Redis:Redis API 的原子性分析 Redis 实现接口访问频率限制 Redis 源码学习之事件驱动 Redis 通信协议 —— 了解 Redis 客户端实现原理 有赞延迟队列设计 Redis内存分析方法 redis分布式内存锁:余量扣除示例(上) redis分布式内存锁:余量扣除示例(下) redisson GitHub将持久数据从Redis迁出 Redis架构之防雪崩设计:网站不宕机背后的兵法 千亿级高性能 KV 存储生态圈 Redis内核基于时间点的备份恢复和基于AOF日志的增量同步机制设计 TiDB技术内幕 Redis源码学习之事件驱动 揭秘 Reddit 愚人节项目的技术实现过程 Redis 通信协议 —— 了解 Redis 客户端实现原理 redis哨兵模式使用lua脚本实现分布式锁 CRUG | Redisson性能压测权威发布 听滴滴大神给你讲Redis Cluster迁移遇到的坑 Redis开启AOF导致的删库事件 唯品会海量实时OLAP分析技术升级之路 Jedis常见异常汇总 redis cluster 集群畅谈 Redis Performance Monitoring with the ELK Stack Redis 和 I/O 多路复用 使用 Redis 解决“树”形数据的复杂查询 JMeter’s Redis Data Set - An Introduction Redis 如何分布式,来看京东金融的设计与实践 Redis 新数据结构 - Streams Redis集群实现原理探讨 当主重启时sentinel没有切换导致数据丢失 大规模codis集群的治理与实践 springboot中redis的使用和分布式session共享问题 A Guide to Redis with Redisson 直击Redis持久化磁盘IO痛点,让存储不再有负担! Redis Cluster 迁移案例 【译】Reddit如何统计每个帖子的浏览量 在Redis中进行分页排序查询 一个小改进,解决Redis数据在线加载大痛点 社区好友动态Feed流的Redis实现 Redis 应用案例 - 在问题中不断成长 国内外三个领域巨头告诉你Redis怎么用 Redis作为LRU Cache的实现 如何使用redis存储海量小数据 Redis性能问题排查解决手册 如何在Redis中实现事务 ansible-playbook配置redis的sentinel高可用集群 redis过期清除机制及应用方法 记一次 Redis 实战,实现答题系统 大规模排行榜系统实践及挑战 京东抢购服务高并发实践 教你看懂redis配置系列 Netty+Redis开发高并发应用的一些思考(二)/) 如何用 redis 造一把分布式锁 Redis 设计思路学习与总结 如何改变Redis用不好的误区 基于 Redis 的序列号服务的设计 Redis practice(一)基础篇 Redis practise(二)使用Docker部署Redis高可用,分布式集群 2017-12-29更新 Redis中的used_memory与maxmemory解惑 golang基于redis lua封装的优先级去重队列 搭建Redis&Minerd安全应急演练环境 GeoBike: Building Location Aware Application with Redis 利用Redis实现Bloom-Filter 神奇的Redis延迟 Spring Boot + Redis 缓存方案深度解读 同程凤凰缓存系统基于Redis的设计与实践 2018-01-24更新 不管你的Redis集群规模有多大,都是时候思考下如何提升资源利用率了 Setting Up a Redis Test Environment using Docker Compose 2018-02-24 Redis 队列 Jmeter Redis插件开发 – 读写数据 线上redis迁移思路 基于Redis实现分布式应用限流 2018-03-05 Cache设计和使用上的套路 Shiro安全框架基于Redis的分布式集群方案 运用 Redis 构建分布式爬虫,抓妹子图 Redisson PRO Redis探索之路 Build a bikesharing app with Redis and Python 不停机分库分表迁移 豌豆夹Redis解决方案Codis源码剖析:Dashboard Redis消息通知系统的实现 Docker Swarm Part II: Rescheduling Redis Redis 集群搭建详细指南 参考在此:Redis技术交流群Redis技术交流群2:微信群]]></content>
</entry>
<entry>
<title></title>
<url>%2F2017%2F11%2F22%2Fconfig%2F</url>
<content type="text"><![CDATA[{"name":"Java 程序员眼中的 Linux","introduction":"笔者从 Java 开发角度,全方位讲解各种环境搭建及常用工具详解,是一部适合程序员的百科全书。"}]]></content>
</entry>
<entry>
<title><![CDATA[深入理解Java虚拟机-学习]]></title>
<url>%2F2017%2F11%2F17%2Fjvm-tool%2F</url>
<content type="text"><![CDATA[jvm调优工具jdk的命令行工具 jps:虚拟机进程状况工具(jps -l) jstat:虚拟机统计信息监视工具(jstat -gcutil VMID,stat -gccapacity VMID) (Local Virtual Machine Identifier,LVMID) jinfo:Java配置信息工具 jinfo -flag +PrintGCDetails VMID jinfo -flag +PrintGC VMID jinfo -flag +PrintGCTimeStamps VMID以上就可以在一个正在运行的JVM中动态开启GC日志功能。 jmap:Java内存映像工具 jmap -heap VMID 显示Java堆详细信息,例如使用哪种回收器、参数配置、分代状况等。 jhat:虚拟机堆转储快照分析工具 jstack:Java堆栈跟踪工具 jstack -l VMID jdk的可视化工具jconsoleJDK中自带的java监控和管理控制台,用于对JVM中内存,线程和类等的监控,是一个基于JMX(java management extensions)的GUI性能监测工具。 VisualVMVisualVM(All-in-One Java Troubleshooting Tool)强大的运行监视和故障处理程序,也能够进行性能分析,CPU、内存,在Profiler页签中能看到。1.插件安装 2.主界面 因为VisualVM的插件太多,重点展示下Visual GC: 第三方调优工具 MAT(Memory Analyzer Tool) GC Easy MAT以eclipse插件形式安装,利用visualvm或者是 jmap命令生产堆文件,导入eclipse mat中生成分析报告: 参考在此:深入理解Java虚拟机 第2版jvm调优-工具篇 作者:纯洁的微笑]]></content>
</entry>
<entry>
<title><![CDATA[Java内存模型之happens-before]]></title>
<url>%2F2017%2F11%2F03%2Fhappens-before%2F</url>
<content type="text"><![CDATA[Java内存模型之happens-before从JDK 5 开始,JMM就使用happens-before(先行发生原则)的概念来阐述多线程之间的内存可见性。 在JMM中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系。 happens-before原则定义如下: 1. 如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前。2. 两个操作之间存在happens-before关系,并不意味着一定要按照happens-before原则制定的顺序来执行。如果重排序之后的执行结果与按照happens-before关系来执行的结果一致,那么这种重排序并不非法。 下面是Java内存模型下一些“天然的“先行发生关系,可以再编码中直接使用。如果两个操作之间的关系不在此列,并且无法从下列规则推导出来的话,虚拟机可以对它们随意地进行重排序。 (摘自《深入理解Java虚拟机第12章》): 程序次序规则(Program Order Rule):在一个线程内,按照程序代码顺序,书写在前面的操作先行发生于书写在后面的操作。准确地说,应该是控制流顺序而不是程序代码顺序,因为要考虑分支、循环等结构。 锁定规则(Monitor Lock Rule):一个unlock操作先行发生与后面同一个锁的lock操作。这里必须强调的是同一个锁,而”后面“是指时间上的先后顺序。 volatile变量规则(Volatile Variable Rule):这是一条比较重要的规则,它标志着volatile保证了线程可见性。通俗点讲就是如果一个线程先去写一个volatile变量,然后一个线程去读这个变量,那么这个写操作一定是happens-before读操作的。 线程启动规则(Thread Start Rule):Thread 对象的start()方法先行发生与此线程的每一个动作。 线程终止规则(Thread Termination Rule):线程中的所有操作都先行发生与对此线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。 线程中断原则(Thread Interruption Rule):对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测到是否有中段发生。 对象终结规则(Finalizer Rule):一个对象的初始化完成(构造函数执行结束)先行发生与它的finalize()方法的开始。 传递性(Transitivity):如果操作A先行发生与操作B,操作B先行发生于操作C,那就可以得出操作A先行发生于操作C的结论。 上面八条是原生Java满足Happens-before关系的规则,但是我们可以对他们进行推导出其他满足happens-before的规则: 将一个元素放入一个线程安全的队列的操作Happens-Before从队列中取出这个元素的操作 将一个元素放入一个线程安全容器的操作Happens-Before从容器中取出这个元素的操作 在CountDownLatch上的倒数操作Happens-Before CountDownLatch#await()操作 释放Semaphore许可的操作Happens-Before获得许可操作 Future表示的任务的所有操作Happens-Before Future#get()操作 向Executor提交一个Runnable或Callable的操作Happens-Before任务开始执行操作 参考在此: 深入理解Java虚拟机:JVM高级特性与最佳实践(最新第二版)周志明 著]]></content>
</entry>
<entry>
<title><![CDATA[Java内存模型看并发(一)]]></title>
<url>%2F2017%2F11%2F01%2FJVM-1%2F</url>
<content type="text"><![CDATA[Java内存模型所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢? 对象和类的数据存储在3个不同的内存区域:堆(heap space)、方法区(method area)、本地区(native area)。 堆内存存放对象以及数组的数据,方法区存放类的信息(包括类名、方法、字段)、静态变量、编译器编译后的代码,本地区包含线程栈、本地方法栈等存放线程 方法区有时被称为持久代(PermGen)。 所有的对象在实例化后的整个运行周期内,都被存放在堆内存中。堆内存又被划分成不同的部分:伊甸区(Eden),幸存者区域(Survivor Sapce),老年代(Old Generation Space)。 方法的执行都是伴随着线程的。原始类型的本地变量以及引用都存放在线程栈中。而引用关联的对象比如String,都存在在堆中。 你真的会写单例吗/** * 漫画:什么是单例模式?见:https://mp.weixin.qq.com/s/pAYYcvh4IRvLs5WYgiPe3A * https://blankj.com/2016/04/21/really-use-singleton/ * @ClassName: Singleton.java * @Description: 单例模式实现方式<br> * 1、双重锁检测<br> * 2、静态内部类<br> * 3、饿汉式 * * @author: zhangjk * @date: 2018年3月7日 下午2:05:53 */ public class Singleton { //一、双检查锁(DCL,即 double-checked locking) //描述:这种方式称为双重检查锁(Double-Check Locking),需要注意的是,如果使用双重检查锁定来实现懒汉式单例类 // private Singleton() {} // private volatile static Singleton instance = null; //单例对象;volatile 修饰符阻止了变量访问前后的指令重排序,保证了指令执行顺序。 // public static Singleton getInstance() { // if (instance == null) { // synchronized (Singleton.class) { // if(instance == null) { // instance = new Singleton(); // } // } // } // return instance; // } // 二、用静态内部类实现单例模式: // 1.从外部无法访问静态内部类LazyHolder,只有当调用Singleton.getInstance方法的时候,才能得到单例对象INSTANCE。 // 2.INSTANCE对象初始化的时机并不是在单例类Singleton被加载的时候,而是在调用getInstance方法,使得静态内部类LazyHolder被加载的时候。 //描述:饿汉式单例类不能实现延迟加载,不管将来用不用始终占据内存;懒汉式单例类线程安全控制繁琐,而且性能受影响。 // private static class LazyHolder { // private static final Singleton INSTANCE = new Singleton(); // } // // private Singleton() {} // public static Singleton getInstance() { // return LazyHolder.INSTANCE; // } //三、饿汉式 //优点:没有加锁,执行效率会提高。 //缺点:类加载时就初始化,浪费内存。 private static Singleton instance = new Singleton(); private Singleton() {} public static Singleton getIntance() { return instance; } } 并发工具类CountDownLatch和CyclicBarrier是jdk concurrent包下非常有用的两个并发工具类,它们提供了一种控制并发流程的手段。 CountDownLatch 允许一个或多个线程等待其他线程完成操作。CyclicBarrier 让一组线程到达一个同步点后再一起继续运行,在其中任意一个线程未达到同步点,其他到达的线程均会被阻塞。 Semaphore(信号量)信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。 一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。拿到信号量的线程可以进入代码,否则就等待。通过acquire()和release()获取和释放访问许可。 /** * 控制并发线程数 */ public class SemaphoreDemo { /** *执行任务类,获取信号量 */ class SemaphoreRunnable implements Runnable{ private Semaphore semaphore; private int user; public SemaphoreRunnable(Semaphore semaphore, int user) { this.semaphore = semaphore; this.user = user; } @Override public void run() { try { //获取信号量许可 semaphore.acquire(); System.out.println("用户【" + user + "】进入窗口,准备买票..."); Thread.sleep((long)(Math.random()*10000)); System.out.println("用户【" + user + "】买票完成,即将离开..."); Thread.sleep((long)(Math.random()*10000)); System.out.println("用户【" + user + "】离开售票窗口..."); //释放信号量许可 semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); } } } private void execute(){ //定义窗口个数 final Semaphore semaphore = new Semaphore(3); //线程池 ExecutorService threadPool = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { threadPool.execute(new SemaphoreRunnable(semaphore,i + 1)); } threadPool.shutdown(); } public static void main(String[] args) { SemaphoreDemo semaphoreDemo = new SemaphoreDemo(); semaphoreDemo.execute(); } } CountDownLatch源码注释:A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.(一个或者多个线程,等待其他多个线程完成某件事情之后才能执行) CountDownLatch声明: CountDownLatch的构造函数接受int型参数作为它的计数器,如果想等待N个点完成,就传入N; 调用CountDownLatch的countDown方法时,N会减1,CountDownLatch的await方法会阻塞主线程直到N减少到0。 网上有个经典例子,在此抄录一下帮助理解记忆。 /** * F1赛车每次进站后,车队技师都需要在尽可能短的时间内对赛车做三个工作:加注燃油、更换轮胎、更换刹车片。 * 当然,这三项工作都是同时进行的。只有当这三项工作完成,赛车才能驶出维修站。 */ public class CountdownlatchDemo { static class Mechanician implements Runnable{ String work; CountDownLatch cDownLatch ; public Mechanician(String work,CountDownLatch cDownLatch) { this.work = work; this.cDownLatch = cDownLatch; } @Override public void run() { try { int random=new Random().nextInt(7); TimeUnit.SECONDS.sleep(random); System.out.println(Thread.currentThread().getName()+"--- "+work+" 完成,此组耗时:"+random+"秒"); } catch (InterruptedException e) { e.printStackTrace(); }finally{ /*当前技师的任务完成,cDownLatch计算器减1 *通常countDown放在finally里中使用*/ cDownLatch.countDown(); } } } public static void main(String[] args) { CountDownLatch cDownLatch=new CountDownLatch(3);//初始计数器值为3,对应3个维修组 /*1、赛车进站*/ System.out.println("F1赛车进站,时间:"+Calendar.getInstance().get(Calendar.SECOND)); List<Mechanician> mechanician_team=new ArrayList<Mechanician>(); mechanician_team.add(new Mechanician("加注燃油", cDownLatch)); mechanician_team.add(new Mechanician("更换轮胎", cDownLatch)); mechanician_team.add(new Mechanician("更换刹车片", cDownLatch)); for(Mechanician mechanician : mechanician_team){ new Thread(mechanician).start(); } /*3、等待技师完成三项工作。实际就是等待cDownLatch计数器变成0*/ try { cDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } /*4、完成维护,出发*/ System.out.println("F1赛车维修完毕,出发!时间:"+Calendar.getInstance().get(Calendar.SECOND)); } } Countdownlatch 是一个倒计数器锁。调用CountDownLatch对象的await()方法使线程处于等待状态,调用countDown()方法的线程会将计数器减1,当计数到达0时,所有等待线程(可多个,但通常的应用场景中只有一个等待者)开始继续执行。 CyclicBarrier源码注释:A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.(多个线程互相等待,直到到达同一个同步点,再继续一起执行) CyclicBarrier(int parties) 默认构造方法,参数表示拦截的线程数量。 CyclicBarrier(int parties, Runnable barrierAction)由于线程之前的调度是由CPU决定的,所以默认的构造方法无法设置线程执行优先级,CyclicBarrier提供一个更高级的构造函数(int parties, Runnable barrierAction),用于在线程到达同步点时,优先执行线程barrierAction,这样可以更加方便的处理一些复杂的业务场景。 创建CyclicBarrier后,每个线程调用await方法告诉CyclicBarrier自己已经到达同步点,然后当前线程被阻塞。 结语在Java语言内部,java.lang.Runtime对象就是一个使用单例模式的例子。在每一个Java应用程序里面,都有唯一的一个Runtime对象,应用程序可以与其运行环境发生相互作用。 参考在此:深入理解Java虚拟机 第2版(第2章 Java 内存区域与内存溢出异常)JAVA的内存模型及结构你真的会写单例吗J.U.C之并发工具类:CountDownLatch]]></content>
</entry>
<entry>
<title><![CDATA[poi实现Excel文件导入、导出]]></title>
<url>%2F2017%2F10%2F23%2FExcel-poi-how%2F</url>
<content type="text"><![CDATA[poi 是什么呢Apache POI 简介是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office(Excel、WORD、PowerPoint、Visio等)格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写,意为“可怜的模糊实现”。 与我而言使用于某项技术,来完成特定业务是最重要的。看下图最终要实现的功能:考查、考试,在对应的中期(期中)考核形式、期末考试形式 相应位置处画 √必修课补考形式 唯一必填。难点在于 期中考试形式、期末考试形式、必修课补考形式(考试形式字典)是动态可增减的。 归纳总结Excel工具类 public static Map<String,String> getExcelHeaderString(String filePath) { // You'd use HSSF if you needed to read or write an Excel file using Java (XLS). // You'd use XSSF if you need to read or write an OOXML Excel file using Java (XLSX). boolean isE2007 = false; //判断是否是excel2007格式 if(filePath.endsWith("xlsx")) isE2007 = true; //得到表头字段 Map<String, String> excelHeaderMap = new LinkedHashMap<String, String>(); InputStream input = null; Workbook wb = null; try { //建立输入流 input = new FileInputStream(filePath); //根据文件格式(2003或者2007)来初始化 if(isE2007) wb = new XSSFWorkbook(input); else wb = new HSSFWorkbook(input); Sheet sheet = wb.getSheetAt(0); //获得第一个表单 Row row = sheet.getRow(0); int columnNum = row.getLastCellNum(); for (short i = 0; i < columnNum; i++) { Cell cell = row.getCell(i); String HeaderString = cell.getRichStringCellValue().getString().trim(); excelHeaderMap.put(HeaderString,HeaderString); } } catch (IOException e) { e.printStackTrace(); }finally{ try { if(null != wb){ input.close(); wb.close(); } } catch (IOException e) { } } return excelHeaderMap; } public static List<Map<String,Object>> getBeanList(String filePath) throws IOException{ return getBeanList(filePath, null); } /** * 解析excel 数据,每一行存为一个map, key为每列首行对应的文字 */ public static List<Map<String,Object>> getBeanList(String filePath, Map<String, String> matchingResultMap) throws IOException{ List<Map<String,Object>> beanList = new ArrayList<Map<String,Object>>(); boolean isE2007 = false; //判断是否是excel2007格式 if(filePath.endsWith("xlsx")) isE2007 = true; InputStream input = null; Workbook wb = null; try { //建立输入流 input = new FileInputStream(filePath); //根据文件格式(2003或者2007)来初始化 if(isE2007) wb = new XSSFWorkbook(input); else wb = new HSSFWorkbook(input); Sheet sheet = wb.getSheetAt(0); Map<Short, String> excelHeaderMap = new HashMap<Short, String>(); int firstRowNum = sheet.getFirstRowNum(); Row row = sheet.getRow(firstRowNum); int columnNum = row.getLastCellNum(); for (short i = 0; i < columnNum; i++) { Cell cell = row.getCell(i); String HeaderString = cell.getRichStringCellValue().getString().trim(); excelHeaderMap.put(i,HeaderString); } int rowNum = sheet.getPhysicalNumberOfRows();// 获取第0个sheet的行的数量(1...n) for (int i = firstRowNum+1; i < rowNum; i++) { Row xRow = sheet.getRow(i); Map<String,Object> beanMap = new LinkedHashMap<String, Object>(); for(short j=0; j < columnNum; j++ ){ String headerKey = null; if ( matchingResultMap == null || matchingResultMap.get(excelHeaderMap.get(j)) == null){ headerKey = excelHeaderMap.get(j); } else { matchingResultMap.get(excelHeaderMap.get(j)); } String headerValue = null; if(null != xRow.getCell(j)){ headerValue = getCellContent(xRow.getCell(j)).trim(); if (beanMap.get(headerKey) == null){ beanMap.put(headerKey, headerValue); } }else{ beanMap.put(headerKey, ""); } } if(beanMap.containsKey(null)){ beanMap.remove(null); } beanMap.put("row_num", i + 1);//excel中的行号 beanList.add(beanMap); } }catch(IOException e){ }finally{ input.close(); wb.close(); } return beanList; } /** * 根据 二维数组(数据)在指定路径下生成文件 * * @param fileFullPathName 绝对文件路径(包含文件名) * @param fieldNames 表头字段数组 * @param data 二维数组(数据)Object[行][列] * @return boolean (标识是否成功生成文件) * @author zhangjinkui */ public static boolean writeFile(String fileFullPathName,String[] fieldNames,Object[][] data) { boolean flag = false; HSSFWorkbook wb = new HSSFWorkbook(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { // 创建字体 Font font = wb.createFont(); // 创建列样式 CellStyle cellStyle = wb.createCellStyle(); Sheet sheet = wb.createSheet(); Row row = sheet.createRow(0); int colLength = fieldNames.length; for (int i = 0; i < colLength; i++) { row.setHeightInPoints(25); sheet.setColumnWidth(i, 256*16); ExcelUtils.createCell(row, i, fieldNames[i],createHeadCell(wb)); } int line = 0; for (line = 0; line < data.length; line++) { Row rowtemp = sheet.createRow(line +1); for (int col = 0; col < colLength; col++) { createCell2(rowtemp, col,data[line][col],createCellStyle(font,cellStyle)); } } wb.write(baos); File file = new File(fileFullPathName); FileUtils.writeByteArrayToFile(file, baos.toByteArray()); flag = true; } catch (Exception e) { flag = false; } finally { try { baos.close(); wb.close(); } catch (IOException e) { e.printStackTrace(); } } return flag; } /** * 得到字节流之后,可直接写入客户端,也可写入到指定文件 * * @param sheetName sheet页名称 * @param fieldNames 表头字段数组 * @param data 二维数组(数据)Object[行][列] * @return 返回字节数组 * @throws IOException * @author zhangjinkui */ public static byte[] writeExcel(String sheetName,String[] fieldNames,Object[][] data) throws IOException{ ByteArrayOutputStream baos = new ByteArrayOutputStream(); HSSFWorkbook wb = new HSSFWorkbook(); try { // 创建字体 Font font = wb.createFont(); // 创建列样式 CellStyle cellStyle = wb.createCellStyle(); Sheet sheet = null; if(StringUtils.isBlank(sheetName)){ sheet = wb.createSheet(""); }else{ sheet = wb.createSheet(sheetName); } Row row = sheet.createRow(0); int colLength = fieldNames.length; for (int i = 0; i < colLength; i++) { row.setHeightInPoints(25); sheet.setColumnWidth(i, 256*16); ExcelUtils.createCell(row, i, fieldNames[i], createHeadCell(wb)); } int line = 0; for (line = 0; line < data.length; line++) { Row rowtemp = sheet.createRow(line +1); for (int col = 0; col < colLength; col++) { createCell2(rowtemp, col,data[line][col],createCellStyle(font,cellStyle)); } } wb.write(baos); } catch (Exception e) { } finally { try { baos.close(); wb.close(); } catch (IOException e) { e.printStackTrace(); } } return baos.toByteArray(); } /** * 合并单元格 行 * @param sheet * @param columnNum 从第几列开始(0-based) * @param rowStart 从第几行开始(0-based) * @param rowspan 跨多少行 */ public static void mergedRegionRow(Sheet sheet, int columnNum, int rowStart, int rowspan){ sheet.addMergedRegion(new CellRangeAddress( rowStart, //first row (0-based) rowStart + rowspan-1, //last row (0-based) columnNum, //first column (0-based) columnNum //last column (0-based) )); } /** * 合并单元格 列 * @param sheet * @param rowNum 第几行 (0-based) * @param colStart 从第几列开始(0-based) * @param colspan 跨多少列 */ public static void mergedRegionColumn(Sheet sheet, int rowNum, int colStart, int colspan){ sheet.addMergedRegion(new CellRangeAddress( rowNum, //first row (0-based) rowNum, //last row (0-based) colStart, //first column (0-based) colStart + colspan - 1 //last column (0-based) )); } /** * 设置生成Cell单元格 * @param row * @param column * @param cellValue * @param cellStyle */ public static void createCell(Row row, Integer column, String cellValue, CellStyle cellStyle) { Cell cell = row.createCell(column); if(StringUtils.isEmpty(cellValue)) cellValue = ""; cell.setCellValue(cellValue); // 统一将单元格格式设置成字符串类型 cell.setCellType(Cell.CELL_TYPE_STRING); cell.setCellStyle(cellStyle); } public static void createCell2(Row row, Integer column, Object cellValue, CellStyle cellStyle) { Cell cell = row.createCell(column); if(StringUtils.isEmpty(String.valueOf(cellValue))) cellValue = ""; try { if (isNumeric(String.valueOf(cellValue))){ double num = Double.valueOf(String.valueOf(cellValue)); cell.setCellValue(num); cell.setCellType(Cell.CELL_TYPE_NUMERIC); } else { cell.setCellValue(String.valueOf(cellValue)); cell.setCellType(Cell.CELL_TYPE_STRING); } }catch(Exception e){ cell.setCellValue(String.valueOf(cellValue)); cell.setCellType(Cell.CELL_TYPE_STRING); } cell.setCellStyle(cellStyle); } private static boolean isNumeric(String value){ if (StringUtils.isBlank(value) ){ return false; } //http://blog.jobbole.com/96052/ //非负浮点数:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$ // String reg = "^\\d+(\\.\\d+)?$"; String reg = "^(0|([1-9]\\d{0,6}))(\\.\\d+)?$";//避免长数字出现科学计数法 return Pattern.compile(reg).matcher(value).find(); } /** * 设置生成Cell单元格 * @param row * @param column * @param cellValue */ public static void createCell(Row row, Integer column, String cellValue) { Cell cell = row.createCell(column); if(StringUtils.isEmpty(cellValue)) cellValue = ""; cell.setCellValue(cellValue); // 统一将单元格格式设置成字符串类型 cell.setCellType(Cell.CELL_TYPE_STRING); } /** * 设置生成Cell单元格 * @param row * @param column * @param cellValue */ public static void createCell(Row row, Integer column, Object cellValue) { Cell cell = row.createCell(column); if(StringUtils.isEmpty(String.valueOf(cellValue))) cellValue = ""; cell.setCellValue(String.valueOf(cellValue)); // 统一将单元格格式设置成字符串类型 cell.setCellType(Cell.CELL_TYPE_STRING); } /** * 获得excel列的值,以字符串格式返回 * 避免过大数字 以出现科学计数法形式出现 * @param cell * @return */ public static String getCellContent(Cell cell){ switch (cell.getCellType()) { case Cell.CELL_TYPE_STRING: return String.valueOf(cell.getRichStringCellValue().toString().trim()); case Cell.CELL_TYPE_NUMERIC: if (DateUtil.isCellDateFormatted(cell)) { return String.valueOf(cell.getDateCellValue()); } else { DecimalFormat df = new DecimalFormat("0"); return df.format(cell.getNumericCellValue()); } case Cell.CELL_TYPE_BOOLEAN: return String.valueOf(cell.getBooleanCellValue()); case Cell.CELL_TYPE_FORMULA: String strCell = null; try { strCell = String.valueOf(cell.getStringCellValue().trim()); } catch (IllegalStateException e) { strCell = String.valueOf(cell.getNumericCellValue()); } return strCell; default: return String.valueOf(cell.getRichStringCellValue().getString().trim()); } } /** * 正文 默认字体样式,setWrapText=true(自动换行) * @return */ public static CellStyle createCellStyle(Font font,CellStyle cellStyle) { // 设置字体颜色 (黑色) font.setColor(HSSFColor.BLACK.index); // 设置字体 font.setFontName("宋体"); // 设置粗体 font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL); // 设置字体大小 font.setFontHeightInPoints((short)12); cellStyle.setWrapText(true); // 设置字体 cellStyle.setFont(font); // 设置对齐 cellStyle.setAlignment(CellStyle.ALIGN_CENTER); // 垂直居中 cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); cellStyle.setLocked(false); return cellStyle; } /** * 正文 默认字体样式,setWrapText=false(不允许自动换行) * @return */ public static CellStyle createCellStyleWrapTextFalse(Font font,CellStyle cellStyle) { // 设置字体颜色 (黑色) font.setColor(HSSFColor.BLACK.index); // 设置字体 font.setFontName("宋体"); // 设置粗体 font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL); // 设置字体大小 font.setFontHeightInPoints((short)12); cellStyle.setWrapText(false); // 设置字体 cellStyle.setFont(font); // 设置对齐 cellStyle.setAlignment(CellStyle.ALIGN_CENTER); // 垂直居中 cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); cellStyle.setLocked(false); return cellStyle; } /** * 允许换行 * @param wb * @return */ public static CellStyle createBrCellStyle(HSSFWorkbook wb) { // 创建列样式 CellStyle style = wb.createCellStyle(); // 创建字体 Font font = wb.createFont(); // 设置字体颜色 (黑色) font.setColor(HSSFColor.BLACK.index); // 设置字体 font.setFontName("宋体"); // 设置粗体 font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL); // 设置字体大小 font.setFontHeightInPoints((short)12); // 设置不换行 style.setWrapText(true); // 设置字体 style.setFont(font); // 设置对齐 style.setAlignment(CellStyle.ALIGN_LEFT); // 垂直居中 style.setVerticalAlignment(CellStyle.ALIGN_LEFT); style.setLocked(false); return style; } /** * 表头默认样式:宋体 12号字体,加粗 * @return */ public static CellStyle createHeadCell(HSSFWorkbook wb) { // 创建字体 Font font = wb.createFont(); // 创建列样式 CellStyle cellStyle = wb.createCellStyle(); // 设置字体颜色 (黑色) font.setColor(HSSFColor.BLACK.index); font.setFontName("宋体"); // 设置粗体 font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); // 设置字体大小 font.setFontHeightInPoints((short)12); // 设置不允许自动换行 cellStyle.setWrapText(false); // 设置字体 cellStyle.setFont(font); // 设置对齐 cellStyle.setAlignment(CellStyle.ALIGN_CENTER); cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); cellStyle.setLocked(false); return cellStyle; } /** * 特殊格式自定义,主要用在表头上 * @return */ public static CellStyle createHSSFCellStyle(HSSFWorkbook wb,short boldweight, short fontheight, short alignment) { // 创建列样式 CellStyle style = wb.createCellStyle(); // 创建字体 Font font = wb.createFont(); // 设置字体颜色 (黑色) font.setColor(HSSFColor.BLACK.index); // 设置字体 font.setFontName("宋体"); // 设置粗体 font.setBoldweight(boldweight); // 设置字体大小 font.setFontHeightInPoints(fontheight); // 设置不换行 style.setWrapText(false); // 设置字体 style.setFont(font); // 设置对齐 style.setAlignment(alignment); // 垂直居中 style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); style.setLocked(false); return style; } /** * 获取合并单元格的值 * @return */ public static String getMergedRegionValue(Sheet sheet, int row, int column) { int sheetMergeCount = sheet.getNumMergedRegions(); for (int i = 0; i < sheetMergeCount; i++) { CellRangeAddress ca = sheet.getMergedRegion(i); int firstColumn = ca.getFirstColumn(); int lastColumn = ca.getLastColumn(); int firstRow = ca.getFirstRow(); int lastRow = ca.getLastRow(); if (row >= firstRow && row <= lastRow) { if (column >= firstColumn && column <= lastColumn) { Row fRow = sheet.getRow(firstRow); Cell fCell = fRow.getCell(firstColumn); return ExcelUtils.getCellContent(fCell); } } } return null; } /** * 得到合并区域 * * @param sheet * @param row * @param column * @return */ public static CellRangeAddress getMergedRegion(Sheet sheet, int row, int column) { int sheetMergeCount = sheet.getNumMergedRegions(); for (int i = 0; i < sheetMergeCount; i++) { CellRangeAddress region = sheet.getMergedRegion(i); int firstColumn = region.getFirstColumn(); int lastColumn = region.getLastColumn(); int firstRow = region.getFirstRow(); int lastRow = region.getLastRow(); if (row >= firstRow && row <= lastRow) { if (column >= firstColumn && column <= lastColumn) { return region; } } } return null; } /** * 判断合并了行 * * @param sheet * @param row * @param column * @return */ public static boolean isMergedRow(Sheet sheet, int row, int column) { int sheetMergeCount = sheet.getNumMergedRegions(); for (int i = 0; i < sheetMergeCount; i++) { CellRangeAddress range = sheet.getMergedRegion(i); int firstColumn = range.getFirstColumn(); int lastColumn = range.getLastColumn(); int firstRow = range.getFirstRow(); int lastRow = range.getLastRow(); if (row == firstRow && row == lastRow) { if (column >= firstColumn && column <= lastColumn) { return true; } } } return false; } /** * 判断指定的单元格是否是合并单元格 * * @param sheet * 工作表 * @param row * 行下标 * @param column * 列下标 * @return */ public static boolean isMergedRegion(Sheet sheet, int row, int column) { int sheetMergeCount = sheet.getNumMergedRegions(); for (int i = 0; i < sheetMergeCount; i++) { CellRangeAddress range = sheet.getMergedRegion(i); int firstColumn = range.getFirstColumn(); int lastColumn = range.getLastColumn(); int firstRow = range.getFirstRow(); int lastRow = range.getLastRow(); if (row >= firstRow && row <= lastRow) { if (column >= firstColumn && column <= lastColumn) { return true; } } } return false; } 页面部分分为三步:1、上传文件2、设置数据更新方式3、提示(比如说Excel中有重复记录,也需要提示出来,让用户修改后重新导入) #结语记录备忘之。]]></content>
</entry>
<entry>
<title><![CDATA[itext实现录取通知书、成绩单]]></title>
<url>%2F2017%2F07%2F03%2Fitext-how%2F</url>
<content type="text"><![CDATA[itext5、jfreechart生成成绩分析图表,并写入成绩单pdf浏览器中展示图表,一般都是用百度的ECharts来展现。但是后台导出成绩单,必须要绕过浏览器才最方便。 在maven中引入itext5、jfreechart、ssj <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.10</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-pdfa</artifactId> <version>5.5.10</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-xtra</artifactId> <version>5.5.10</version> </dependency> <dependency> <groupId>com.itextpdf.tool</groupId> <artifactId>xmlworker</artifactId> <version>5.5.10</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-asian</artifactId> <version>5.2.0</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-math3</artifactId> <version>3.0</version> </dependency> <dependency> <groupId>org.jfree</groupId> <artifactId>jfreechart</artifactId> <version>1.0.14</version> <exclusions> <exclusion> <groupId>com.lowagie</groupId> <artifactId>itext</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>ca.umontreal.iro.simul</groupId> <artifactId>ssj</artifactId> <version>3.2.1</version> <exclusions> <exclusion> <groupId>jfree</groupId> <artifactId>jfreechart</artifactId> </exclusion> </exclusions> </dependency> 示例如图: 中位数、标准差、峰度、偏度等使用 org.apache.commons.math3.analysis.function.*直接函数调用,很方便。 结语菜头叔每篇公号文章都有个 禅定时刻,很是喜欢。在此有样学样吧。 一个酒鬼的自述“一个人活得拧巴是值得理解的,甚至是值得赞美的,这证明他内心还有冲突,并不甘于和人生妥协。但是,通过酒来发泄显得太过脆弱而虚伪,且对不起那瓶好酒。酒带给人们的应该是被压抑的快乐,而不是被压抑的痛苦。” 不是酒鬼,不咋饮酒,但是挺喜欢这句话。]]></content>
</entry>
<entry>
<title><![CDATA[Mac上使用Homebrew进行MySQL卸载、安装,解决乱码]]></title>
<url>%2F2017%2F06%2F22%2FMySQL-how%2F</url>
<content type="text"><![CDATA[Mac上使用Homebrew进行MySQL卸载、安装,解决乱码Mac上使用Homebrew进行MySQL卸载系统环境 Mac 10.12Homebrew 1.2.3MySQL 5.6.36_1homebrew 卸载 $ brew remove [email protected] $ brew cleanup $ launchctl unload -w ~/Library/LaunchAgents/[email protected] 删除文件 $ sudo rm -f /etc/my.cnf $ sudo rm -rf /usr/local/var/mysql $ sudo rm ~/Library/LaunchAgents/[email protected] Mac上使用Homebrew安装MySQL$ brew install [email protected] 让 MySQL 开机自行启动$ ln -sfv /usr/local/opt/[email protected]/*.plist ~/Library/LaunchAgents $ sudo find /usr/local/Cellar/[email protected]/5.6.36_1/ -name "[email protected]" -exec cp {} ~/Library/LaunchAgents/ \; $ launchctl load -w ~/Library/LaunchAgents/[email protected] 指定MySQL数据存放路径$ mysql_install_db --verbose --user=`whoami` --basedir="/usr/local/Cellar/[email protected]/5.6.36_1" --datadir=/usr/local/var/mysql --tmpdir=/tmp $ cd . ; /usr/local/Cellar/[email protected]/5.6.36_1/bin/mysqld_safe & 配置MySQL修改 /etc/my.cnf,没有就从MySQL安装目录拷贝一个模板过来。# For advice on how to change settings please see # http://dev.mysql.com/doc/refman/5.6/en/server-configuration-defaults.html [mysqld] port=3306 datadir=/usr/local/var/mysql # Remove leading # and set to the amount of RAM for the most important data # cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%. # innodb_buffer_pool_size = 128M # Remove leading # to turn on a very important data integrity option: logging # changes to the binary log between backups. # log_bin # These are commonly set, remove the # and set as required. # basedir = ..... # datadir = ..... # port = ..... # server_id = ..... # socket = ..... # Remove leading # to set options mainly useful for reporting servers. 将mysql加入系统环境变量执行vim ~/.bash_profile在该文件中添加如下语句,完成后,按esc,然后输入wq保存。export PATH=/usr/local/opt/[email protected]/bin:$PATH最后在命令行输入source ~/.bash_profile ok ,可以启动MySQL了。$ mysql.server start权限配置参见官网:https://dev.mysql.com/doc/refman/5.7/en/resetting-permissions.html 设置密码默认是没有密码的,进去mysql后,执行语句: mysql> set password for 'root'@'localhost'=password('root'); Query OK, 0 rows affected (0.01 sec) 接下来使用密码登录MySQL: $ mysql -uroot -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 395 Server version: 5.6.36 Homebrew Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show variables like 'character%'; +--------------------------+------------------------------------------------------------+ | Variable_name | Value | +--------------------------+------------------------------------------------------------+ | character_set_client | utf8 | | character_set_connection | utf8 | | character_set_database | utf8 | | character_set_filesystem | binary | | character_set_results | utf8 | | character_set_server | utf8 | | character_set_system | utf8 | | character_sets_dir | /usr/local/Cellar/[email protected]/5.6.36_1/share/mysql/charsets/ | +--------------------------+------------------------------------------------------------+ 8 rows in set (0.04 sec) 看到utf8,编码就不会出问题了。 结语之所以写这篇,原因是从Windows转到Mac环境搞开发,碰到了乱码问题,各种配置都试了也没解决。卸载重装妥妥的。]]></content>
</entry>
<entry>
<title><![CDATA[Docker初探]]></title>
<url>%2F2017%2F06%2F16%2Fdocker-how-1%2F</url>
<content type="text"><![CDATA[初始容器与Dockerhttps://docs.docker.com/engine/docker-overview/ 什么是DockerDocker开源项目背景Docker是基于Go语言实现的开源容器项目,诞生于2013年年初,最初发起者是dotCloud公司。Docker自开源后受到广泛的关注和讨论,目前已有多个相关项目(包括Docker三剑客、Kubernetes等),逐渐形成了围绕Docker容器的生态体系。由于Docker在业界造成的影响力实在太大,dotCloud公司后来也直接改名为Docker Inc,并专注于Docker相关技术和产品的开发。 对于Docker,目前的定义是一个开源的容器引擎,可以方便地对容器(关于容器,将在第2章详细介绍)进行管理。其对镜像的打包封装,以及引入的Docker Registry对镜像的统一管理,构建了方便快捷的“Build,Ship and Run”流程,它可以统一整个开发、测试和部署的环境和流程,极大地减少运维成本。 Docker在开发和运维中的优势对开发和运维(DevOps)人员来说,可能最梦寐以求的效果就是一次创建或配置,之后可以在任意地方、任意时间让应用正常运行。 1.更快速的交付和部署。使用Docker,开发人员可以使用镜像来快速构建一套标准的开发环境;开发完成之后,测试和运维人员可以直接使用完全相同环境来部署代码。只要开发测试过的代码,就可以确保在生产环境无缝运行。Docker可以快速创建和删除容器,实现快速迭代,大量节约开发、测试、部署的时间。并且,整个过程全程可见,使团队更容易理解应用的创建和工作过程。2.更高效的资源利用。Docker容器的运行不需要额外的虚拟化管理程序(Virtual Machine Manager以及Hypervisor)支持,它是内核级的虚拟化,可以实现更高的性能,同时对资源的额外需求很低。3.更轻松的迁移和扩展。4.更简单的更新管理。使用Dockerfile,只需要小小的配置修改,就可以替代以往大量的更新工作。并且所有修改都以增量的方式被分发和更新,从而实现自动化并且高效的容器管理。 核心概念1.Docker镜像镜像是创建Docker容器的基础。通过版本管理和增量的文件系统,Docker提供了一套十分简单的机制来创建和更新现有的镜像。与容器相对应,如果说容器提供了一个完整的、隔离的运行环境,那么镜像则是这个运行环境的静态体现,是一个还没有运行起来的“运行环境”。Docker镜像通常是通过Dockerfile来创建的,Dockerfile提供了镜像内容的定制,同时也体现了层级关系的建立。 ps:镜像自身是只读的。容器从镜像启动的时候,会在镜像的最上层创建一个可写层。2.Docker容器在功能上,Docker通过Libcontainer实现对容器生命周期的管理、信息的设置和查询,以及监控和通信等功能。而容器也是对镜像的完美诠释,容器以镜像为基础,同时又为镜像提供了一个标准的和隔离的执行环境。在概念上,容器则很好地诠释了Docker集装箱的理念,集装箱可以存放任何货物,可以通过邮轮将货物运输到世界各地。运输集装箱的邮轮和装载卸载集装箱的码头都不用关心集装箱里的货物,这是一种标准的集装和运输方式。类似的,Docker的容器就是“软件界的集装箱”,它可以安装任意的软件和库文件,做任意的运行环境配置。 3.Docker仓库是Docker集中存放镜像文件的场所。 Install Docker for Machttps://docs.docker.com/docker-for-mac/install/ ~ docker version Client: Version: 17.03.1-ce API version: 1.27 Go version: go1.7.5 Git commit: c6d412e Built: Tue Mar 28 00:40:02 2017 OS/Arch: darwin/amd64 Server: Version: 17.03.1-ce API version: 1.27 (minimum version 1.12) Go version: go1.7.5 Git commit: c6d412e Built: Fri Mar 24 00:00:50 2017 OS/Arch: linux/amd64 Experimental: true 我们看到Client和Server均有输出,则说明Docker for Mac已经正常启动。 CentOS环境下安装DockerOS requirementsTo install Docker, you need the 64-bit version of CentOS 7.我是在Mac上安装的VirtualBox,然后装上CentOS 7镜像。 对于CentOS 7系统,CentOS-Extras源中已内置Docker yum安装[root@centos-docker yum.repos.d]# sudo tee /etc/yum.repos.d/docker.repo <<-'EOF' > [dockerrepo] > name=Docker Repository > baseurl=https://yum.dockerproject.org/repo/main/centos/$releasever/ > enabled=1 > gpgcheck=1 > gpgkey=https://yum.dockerproject.org/gpg > EOF 之后更新yum软件源缓存,并安装docker-engine 即可。 $ sudo yum install -y yum-utils $ sudo yum update $ sudo yum makecache fast $ sudo yum install docker-engine 这是最新的版本。要想随意指定要安装的版本,如下命令,官网上如下。1.List the available versions: $ yum list docker-engine.x86_64 –showduplicates |sort -r 2.Install a specific version by adding the version after docker-engine, separated by a hyphen (-):$ sudo yum install docker-engine-version 脚本安装1.更新系统包到最新。$ yum -y update 2.执行Docker安装脚本 $ curl -fsSL https://get.docker.com/ | sh 获取镜像Docker Hub 镜像站点 安装/升级你的Docker客户端您可以通过阿里云的镜像仓库下载:mirrors.aliyun.com/help/docker-engine 或执行以下命令: curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh - 如何使用Docker加速器针对Docker客户端版本大于1.10的用户 您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器: sudo mkdir -p /etc/dockersudo tee /etc/docker/daemon.json <<-‘EOF’{ “registry-mirrors”: [“https://wgqgbfsb.mirror.aliyuncs.com“]}EOFsudo systemctl daemon-reloadsudo systemctl restart docker 镜像是运行容器的前提,官方的Docker Hub网站已经提供了数十万个镜像供大家开放下载。可以使用docker pull命令直接从Docker Hub镜像源来下载镜像。该命令的格式为docker pull NAME[:TAG]。其中,NAME是镜像仓库的名称(用来区分镜像),TAG是镜像的标签(往往用来表示版本信息)。通常情况下,描述一个镜像需要包括“名称+标签”信息。 现在想要获得centos的Docker镜像,1.docker search –no-trunc centos2.docker pull docker.io/jdeathe/centos-ssh 查看镜像信息1.使用images命令列出镜像2.使用tag命令添加镜像标签3.使用inspect命令查看详细信息4.使用history命令查看镜像历史(docker history –no-trunc centos-ssh) 搜寻镜像使用docker search命令可以搜索远端仓库中共享的镜像,默认搜索官方仓库中的镜像。用法为docker search TERM,支持的参数主要包括:·–automated=true|false:仅显示自动创建的镜像,默认为否;·–no-trunc=true|false:输出信息不截断显示,默认为否;·–filter=stars=X:指定仅显示评价为指定星级以上的镜像,默认为0,即输出所有镜像。例如: $ docker search --filter=stars=3 ubuntu $ docker search -f stars=25 centos 删除镜像使用标签删除镜像使用docker rmi命令可以删除镜像,命令格式为docker rmi IMAGE[IMAGE…],其中IMAGE可以为标签或ID。 创建镜像创建镜像的方法主要有三种:基于已有镜像的容器创建、基于本地模板导入、基于Dockerfile创建。本节将重点介绍前两种方法。最后一种基于Dockerfile创建的方法将在后续章节专门予以详细介绍。 基于已有镜像的容器创建该方法主要是使用docker commit命令。命令格式为docker commit[OPTIONS]CONTAINER[REPOSITORY[:TAG]],主要选项包括:·-a,–author=””:作者信息;·-c,–change=[]:提交的时候执行Dockerfile指令,包括CMD|ENTRYPOINT|ENV|EXPOSE|LABEL|ONBUILD|USER|VOLUME|WORKDIR等;·-m,–message=””:提交消息;·-p,–pause=true:提交时暂停容器运行。 基于本地模板导入要直接导入一个镜像,可以使用OpenVZ提供的模板来创建,或者用其他已导出的镜像模板来创建。OPENVZ模板的下载地址为http://openvz.org/Download/templates/precreated 存出和载入镜像1.存出镜像 [root@centos-docker docker]# docker save -o centos_7.tar.gz daocloud.io/centos:7 [root@centos-docker docker]# ls centos_7.tar.gz certs.d daemon.json key.json 2.载入镜像 [root@centos-docker docker]# docker load --input centos_7.tar.gz Loaded image: daocloud.io/centos:7 或者$ docker load < centos_7.tar.gz这将导入镜像及其相关的元数据信息(包括标签等)。 创建&启动一个容器:$ docker run -d -p 10022:22 -v /dfile/:/dfile/ -h "centos-d" --name centos-d centos-ssh /usr/sbin/sshd -D $ mount -t vboxsf docker_files /docker [root@centos-d /]# netstat -tunlp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1/sshd tcp6 0 0 :::22 :::* LISTEN 1/sshd 其中10022是宿主主机的端口,22是容器的SSH服务监听端口:-p 10022:22使用HostPort:ContainerPort格式将本地的10022端口映射到容器的22端口。 在宿主主机或其他主机上,可以通过SSH访问10022端口来登录容器。 使用docker inspect来查看容器的基础信息。参见:https://docs.docker.com/engine/reference/commandline/inspect/ -v /dfile(主机):/dfile(容器):ro上面的命令加载主机的/dfile目录到容器的/dfile目录。ps:本地目录的路径必须是绝对路径,如果目录不存在,Docker会自动创建。 Docker挂载数据卷的默认权限是读写(rw),用户也可以通过ro指定为只读。 mount -t vboxsf the_share_name /a_folder_nameps:VirtualBox与Mac共享文件夹为:docker_filesps: $ docker ps -a查看容器。 [root@centos-docker docker]# docker start centos-d centos-d [root@centos-docker docker]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0ffb8ab3f777 centos-ssh "/usr/sbin/sshd -D" 11 weeks ago Up 12 seconds 0.0.0.0:10022->22/tcp centos-d $ docker-enter centos-d 进入容器。可以按Ctrl+d或输入exit命令来退出容器,通过exit命令或Ctrl+d来退出终端时,所创建的容器立刻终止,处于stopped状态。 利用ssh进入到docker中的centos里然后 我们试着从宿主机直接进入到docker中的centos里: ~ ssh [email protected] -p 10022 [email protected]'s password: Last login: Thu Jun 29 09:03:57 2017 from 192.168.99.1 [root@centos-d ~]# 避免了先进入虚拟机系统,然后再进入docker中的centos里: ~ ssh [email protected] -p 22 [email protected]'s password: Last login: Thu Jun 29 17:11:29 2017 from 192.168.99.1 [root@centos-docker ~]# docker-enter centos-d Last login: Thu Jun 29 09:21:21 UTC 2017 from 192.168.99.1 on pts/0 [root@centos-d ~]# create命令与容器运行模式相关的选项-d, –detach=true|false (是否在后台运行容器,默认为否)-P, –publish-all=true|false (通过NAT机制将容器标记暴露的端口自动映射到本地主机的临时端口)-p, –publish=[] (指定如何映射到本地主机端口)–rm=true|false (容器退出后是否自动删除,不能跟-d同时使用)-i, –interactive=true|false (保持标准输入打开,默认为false)-t, –tty=true|false (是否分配一个伪终端,默认是false)–expose=[] (指定容器会暴露出来的端口或端口范围)–group-add=[] (运行容器的用户组)-v|–volume[=[[HOST-DIR:]CONTAINER-DIR[:OPTIONS]]] (挂载主机上的文件卷到容器内)-w, –workdir=”” (容器内的默认工作目录) create命令与容器环境和配置相关的选项–add-host=[] (在容器内添加一个主机名到IP地址的映射关系(通过/etc/hosts文件))-h, –hostname=”” (指定容器内的主机名)–name=”” (指定容器的别名) create命令与容器资源限制和安全保护相关的选项–privileged=true|false (是否给容器以高权限,这意味着容器内应用将不受权限下限制,一般不推荐)–read-only=true|false (是否让容器内的文件系统只读) 启动容器说明当利用docker run来创建并启动容器时,Docker在后台运行的标准操作包括: ·检查本地是否存在指定的镜像,不存在就从公有仓库下载;·利用镜像创建一个容器,并启动该容器;·分配一个文件系统给容器,并在只读的镜像层外面挂载一层可读写层;·从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中;·从网桥的地址池配置一个IP地址给容器;·执行用户指定的应用程序;·执行完毕后容器被自动终止。 终止容器可以使用docker stop来终止一个运行中的容器。该命令的格式为docker stop[-t|–time[=10]][CONTAINER…]。首先向容器发送SIGTERM信号,等待一段超时时间(默认为10秒)后,再发送SIGKILL信号来终止容器。 进入容器在使用-d参数时,容器启动后会进入后台,用户无法看到容器中的信息,也无法进行操作。这个时候如果需要进入容器进行操作,有多种方法,包括使用官方的attach或exec命令,以及第三方的nsenter工具等。下面分别介绍一下。 attach命令attach是Docker自带的命令,命令格式为: 支持三个主要选项:·–detach-keys[=[]]:指定退出attach模式的快捷键序列,默认是CTRL-p CTRL-q;·–no-stdin=true|false:是否关闭标准输入,默认是保持打开;·–sig-proxy=true|false:是否代理收到的系统信号给应用进程,默认为true。ps:当多个窗口同时用attach命令连到同一个容器的时候,所有窗口都会同步显示。不常用。 exec命令Docker从1.3.0版本起提供了一个更加方便的exec命令,可以在容器内直接执行任意命令。比较重要的参数有:·-i,–interactive=true|false:打开标准输入接受用户输入命令,默认为false;·–privileged=true|false:是否给执行命令以高权限,默认为false;·-t,–tty=true|false:分配伪终端,默认为false;·-u,–user=””:执行命令的用户名或ID。例如进入到刚创建的容器中,并启动一个bash: [root@centos-docker docker]# docker exec -it centos-d /bin/bash [root@centos-d /]# pwd / 可以看到,一个bash终端打开了,在不影响容器内其他应用的前提下,用户可以很容易与容器进行交互。注意通过指定-it参数来保持标准输入打开,并且分配一个伪终端。通过exec命令对容器执行操作是最为推荐的方式。 nsenter工具在util-linux软件包版本2.23+中包含nsenter工具。 [root@centos-docker docker]# docker start centos-d centos-d [root@centos-docker docker]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0ffb8ab3f777 centos-ssh "/usr/sbin/sshd -D" 11 weeks ago Up 6 seconds 0.0.0.0:10022->22/tcp centos-d [root@centos-docker docker]# PID=$(docker inspect --format "{{ .State.Pid }}" centos-d) [root@centos-docker docker]# nsenter --target $PID --mount --uts --ipc --net --pid [root@centos-d /]# ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 06:04 ? 00:00:00 /usr/sbin/sshd -D root 5 0 0 06:07 ? 00:00:00 -bash root 19 5 0 06:09 ? 00:00:00 ps -ef 删除容器可以使用docker rm命令来删除处于终止或退出状态的容器,命令格式为docker rm[-f|–force][-l|–link][-v|–volumes]CONTAINER[CONTAINER…]。主要支持的选项包括:·-f,–force=false:是否强行终止并删除一个运行中的容器;·-l,–link=false:删除容器的连接,但保留容器;·-v,–volumes=false:删除容器挂载的数据卷。 导入和导出容器某些时候,需要将容器从一个系统迁移到另外一个系统,此时可以使用Docker的导入和导出功能。这也是Docker自身提供的一个重要特性。 导出容器导出容器是指导出一个已经创建的容器到一个文件,不管此时这个容器是否处于运行状态,可以使用docker export命令,该命令的格式为docker export[-o|–output[=””]]CONTAINER。其中,可以通过-o选项来指定导出的tar文件名,也可以直接通过重定向来实现。ps:实现容器的迁移 [root@centos-docker docker]# docker export -o test_centos-d.tar.gz centos-d [root@centos-docker docker]# ls a.txt b.txt c.txt epel-release-7-9.noarch.rpm test_centos-d.tar.gz [root@centos-docker docker]# docker export centos-d >test2_centos-d.tar.gz [root@centos-docker docker]# ls a.txt b.txt c.txt epel-release-7-9.noarch.rpm test2_centos-d.tar.gz test_centos-d.tar.gz 实际上,既可以使用docker load命令来导入镜像存储文件到本地镜像库,也可以使用docker import命令来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也更大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。 参考在此:Docker技术入门与实践Docker进阶与实战 作者:华为Docker实践小组]]></content>
</entry>
<entry>
<title><![CDATA[Systemd 入门教程:命令篇]]></title>
<url>%2F2017%2F05%2F25%2Fsystemd%2F</url>
<content type="text"><![CDATA[Systemd 入门教程:命令篇Systemd 是 Linux 系统工具,用来启动守护进程,已成为大多数发行版的标准配置。 本文介绍它的基本用法,分为上下两篇。今天介绍它的主要命令,下一篇介绍如何用于实战。 一、由来历史上,Linux 的启动一直采用init进程。 下面的命令用来启动服务。 [root@localhost /]# service httpd start Redirecting to /bin/systemctl start httpd.service ps:Centos7已经不支持了喔! 这种方法有两个缺点。 一是启动时间长。init进程是串行启动,只有前一个进程启动完,才会启动下一个进程。 二是启动脚本复杂。init进程只是执行启动脚本,不管其他事情。脚本需要自己处理各种情况,这往往使得脚本变得很长。 二、Systemd 概述Systemd 就是为了解决这些问题而诞生的。它的设计目标是,为系统的启动和管理提供一套完整的解决方案。 根据 Linux 惯例,字母d是守护进程(daemon)的缩写。 Systemd 这个名字的含义,就是它要守护整个系统。 (上图为 Systemd 作者 Lennart Poettering) 使用了 Systemd,就不需要再用init了。Systemd 取代了initd,成为系统的第一个进程(PID 等于 1),其他进程都是它的子进程。 $ systemctl --version 上面的命令查看 Systemd 的版本。 Systemd 的优点是功能强大,使用方便,缺点是系统庞大,非常复杂。事实上,现在还有很多人反对使用 Systemd,理由就是它过于复杂,与操作系统的其他部分强耦合,违反“keep simple, keep stupid”的Unix 哲学。 (上图为 Systemd 架构图) 三、系统管理Systemd 并不是一个命令,而是一组命令,涉及到系统管理的方方面面。 3.1 systemctlsystemctl是 Systemd 的主命令,用于管理系统。 # 重启系统 $ sudo systemctl reboot # 关闭系统,切断电源 $ sudo systemctl poweroff # CPU停止工作 $ sudo systemctl halt # 暂停系统 $ sudo systemctl suspend # 让系统进入冬眠状态 $ sudo systemctl hibernate # 让系统进入交互式休眠状态 $ sudo systemctl hybrid-sleep # 启动进入救援状态(单用户状态) $ sudo systemctl rescue 3.2 systemd-analyzesystemd-analyze命令用于查看启动耗时。 # 查看启动耗时 $ systemd-analyze # 查看每个服务的启动耗时 $ systemd-analyze blame # 显示瀑布状的启动过程流 $ systemd-analyze critical-chain # 显示指定服务的启动流(eg:sshd.service) $ systemd-analyze critical-chain sshd.service 3.3 hostnamectlhostnamectl命令用于查看当前主机的信息。 # 显示当前主机的信息 $ hostnamectl # 设置主机名。 $ sudo hostnamectl set-hostname CentOS-Docker 3.4 localectllocalectl命令用于查看本地化设置。 # 查看本地化设置 $ localectl # 设置本地化参数。 $ sudo localectl set-locale LANG=zh_CN.UTF-8 $ sudo localectl set-keymap cn 3.5 timedatectltimedatectl命令用于查看当前时区设置。 # 查看当前时区设置 $ timedatectl # 显示所有可用的时区 $ timedatectl list-timezones # 设置当前时区 $ sudo timedatectl set-timezone America/New_York 3.6 loginctlloginctl命令用于查看当前登录的用户。 # 列出当前session $ loginctl list-sessions # 列出当前登录用户 $ loginctl list-users # 列出显示指定用户的信息 $ loginctl show-user root 四、Unit4.1 含义Systemd 可以管理所有系统资源。不同的资源统称为 Unit(单位)。 Unit 一共分成12种。 Service unit:系统服务 Target unit:多个 Unit 构成的一个组 Device Unit:硬件设备 Mount Unit:文件系统的挂载点 Automount Unit:自动挂载点 Path Unit:文件或路径 Scope Unit:不是由 Systemd 启动的外部进程 Slice Unit:进程组 Snapshot Unit:Systemd 快照,可以切回某个快照 Socket Unit:进程间通信的 socket Swap Unit:swap 文件 Timer Unit:定时器 systemctl list-units命令可以查看当前系统的所有 Unit 。 # 列出正在运行的 Unit $ systemctl list-units # 列出所有Unit,包括没有找到配置文件的或者启动失败的 $ systemctl list-units --all # 列出所有没有运行的 Unit $ systemctl list-units --all --state=inactive # 列出所有加载失败的 Unit $ systemctl list-units --failed # 列出所有正在运行的、类型为 service 的 Unit $ systemctl list-units --type=service 4.2 Unit 的状态systemctl status命令用于查看系统状态和单个 Unit 的状态。 # 显示系统状态 $ systemctl status # 显示单个 Unit 的状态 $ sysystemctl status httpd.service # 显示远程主机的某个 Unit 的状态 $ systemctl -H [email protected] status httpd.service 除了status命令,systemctl还提供了三个查询状态的简单方法,主要供脚本内部的判断语句使用。 # 显示某个 Unit 是否正在运行 $ systemctl is-active httpd.service # 显示某个 Unit 是否处于启动失败状态 $ systemctl is-failed httpd.service # 显示某个 Unit 服务是否建立了启动链接 $ systemctl is-enabled httpd.service 4.3 Unit 管理对于用户来说,最常用的是下面这些命令,用于启动和停止 Unit(主要是 service)。 # 立即启动一个服务 $ sudo systemctl start httpd.service # 立即停止一个服务 $ sudo systemctl stop httpd.service # 重启一个服务 $ sudo systemctl restart httpd.service # 杀死一个服务的所有子进程 $ sudo systemctl kill httpd.service # 重新加载一个服务的配置文件 $ sudo systemctl reload httpd.service # 重载所有修改过的配置文件 $ sudo systemctl daemon-reload # 显示某个 Unit 的所有底层参数 $ systemctl show httpd.service # 显示某个 Unit 的指定属性的值 $ systemctl show -p CPUShares httpd.service 4.4 依赖关系Unit 之间存在依赖关系:A 依赖于 B,就意味着 Systemd 在启动 A 的时候,同时会去启动 B。 systemctl list-dependencies命令列出一个 Unit 的所有依赖。 $ systemctl list-dependencies nginx.service 上面命令的输出结果之中,有些依赖是 Target 类型(详见下文),默认不会展开显示。如果要展开 Target,就需要使用--all参数。 $ systemctl list-dependencies --all nginx.service 五、Unit 的配置文件5.1 概述每一个 Unit 都有一个配置文件,告诉 Systemd 怎么启动这个 Unit 。 Systemd 默认从目录/etc/systemd/system/读取配置文件。但是,里面存放的大部分文件都是符号链接,指向目录/usr/lib/systemd/system/,真正的配置文件存放在这个目录。 systemctl enable命令用于在上面两个目录之间,建立符号链接关系。 $ sudo systemctl enable sshd.service # 等同于 $ sudo ln -s '/usr/lib/systemd/system/sshd.service' '/etc/systemd/system/multi-user.target.wants/sshd.service' 如果配置文件里面设置了开机启动,systemctl enable命令相当于激活开机启动。 与之对应的,systemctl disable命令用于在两个目录之间,撤销符号链接关系,相当于撤销开机启动。 $ sudo systemctl disable sshd.service 配置文件的后缀名,就是该 Unit 的种类,比如sshd.socket。如果省略,Systemd 默认后缀名为.service,所以sshd会被理解成sshd.service。 5.2 配置文件的状态systemctl list-unit-files命令用于列出所有配置文件。 # 列出所有配置文件 $ systemctl list-unit-files # 列出指定类型的配置文件 $ systemctl list-unit-files --type=service 这个命令会输出一个列表。 $ systemctl list-unit-files UNIT FILE STATE chronyd.service enabled [email protected] static sshd.service disabled 这个列表显示每个配置文件的状态,一共有四种。 enabled:已建立启动链接 disabled:没建立启动链接 static:该配置文件没有[Install]部分(无法执行),只能作为其他配置文件的依赖 masked:该配置文件被禁止建立启动链接 注意,从配置文件的状态无法看出,该 Unit 是否正在运行。这必须执行前面提到的systemctl status命令。 $ systemctl status httpd.service 一旦修改配置文件,就要让 Systemd 重新加载配置文件,然后重新启动,否则修改不会生效。 $ sudo systemctl daemon-reload $ sudo systemctl restart httpd.service 5.3 配置文件的格式配置文件就是普通的文本文件,可以用文本编辑器打开。 systemctl cat命令可以查看配置文件的内容。注意,配置文件的区块名和字段名,都是大小写敏感的。 每个区块内部是一些等号连接的键值对。 [Section] Directive1=value Directive2=value . . . 注意,键值对的等号两侧不能有空格。 5.4 配置文件的区块[Unit]区块通常是配置文件的第一个区块,用来定义 Unit 的元数据,以及配置与其他 Unit 的关系。它的主要字段如下。 Description:简短描述 Documentation:文档地址 Requires:当前 Unit 依赖的其他 Unit,如果它们没有运行,当前 Unit 会启动失败 Wants:与当前 Unit 配合的其他 Unit,如果它们没有运行,当前 Unit 不会启动失败 BindsTo:与Requires类似,它指定的 Unit 如果退出,会导致当前 Unit 停止运行 Before:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之后启动 After:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之前启动 Conflicts:这里指定的 Unit 不能与当前 Unit 同时运行 Condition...:当前 Unit 运行必须满足的条件,否则不会运行 Assert...:当前 Unit 运行必须满足的条件,否则会报启动失败 [Install]通常是配置文件的最后一个区块,用来定义如何启动,以及是否开机启动。它的主要字段如下。 WantedBy:它的值是一个或多个 Target,当前 Unit 激活时(enable)符号链接会放入/etc/systemd/system目录下面以 Target 名 + .wants后缀构成的子目录中 RequiredBy:它的值是一个或多个 Target,当前 Unit 激活时,符号链接会放入/etc/systemd/system目录下面以 Target 名 + .required后缀构成的子目录中 Alias:当前 Unit 可用于启动的别名 Also:当前 Unit 激活(enable)时,会被同时激活的其他 Unit [Service]区块用来 Service 的配置,只有 Service 类型的 Unit 才有这个区块。它的主要字段如下。 Type:定义启动时的进程行为。它有以下几种值。 simple:默认值,执行ExecStart指定的命令,启动主进程 forking:以 fork 方式从父进程创建子进程,创建后父进程会立即退出 oneshot:一次性进程,Systemd 会等当前服务退出,再继续往下执行 dbus:当前服务通过D-Bus启动 notify:当前服务启动完毕,会通知Systemd,再继续往下执行 idle:若有其他任务执行完毕,当前服务才会运行 ExecStart:启动当前服务的命令 ExecStartPre:启动当前服务之前执行的命令 ExecStartPost:启动当前服务之后执行的命令 ExecReload:重启当前服务时执行的命令 ExecStop:停止当前服务时执行的命令 ExecStopPost:停止当其服务之后执行的命令 RestartSec:自动重启当前服务间隔的秒数 Restart:定义何种情况 Systemd 会自动重启当前服务,可能的值包括always(总是重启)、on-success、on-failure、on-abnormal、on-abort、on-watchdog TimeoutSec:定义 Systemd 停止当前服务之前等待的秒数 Environment:指定环境变量 Unit 配置文件的完整字段清单,请参考官方文档。 六、Target简单说,Target 就是一个 Unit 组,包含许多相关的 Unit 。启动某个 Target 的时候,Systemd 就会启动里面所有的 Unit。从这个意义上说,Target 这个概念类似于“状态点”,启动某个 Target 就好比启动到某种状态。 传统的init启动模式里面,有 RunLevel 的概念,跟 Target 的作用很类似。不同的是,RunLevel 是互斥的,不可能多个 RunLevel 同时启动,但是多个 Target 可以同时启动。 # 查看当前系统的所有 Target $ systemctl list-unit-files --type=target # 查看一个 Target 包含的所有 Unit $ systemctl list-dependencies multi-user.target # 查看启动时的默认 Target $ systemctl get-default # 设置启动时的默认 Target $ sudo systemctl set-default multi-user.target # 切换 Target 时,默认不关闭前一个 Target 启动的进程, # systemctl isolate 命令改变这种行为, # 关闭前一个 Target 里面所有不属于后一个 Target 的进程 $ sudo systemctl isolate multi-user.target Target 与 传统 RunLevel 的对应关系如下。 Traditional runlevel New target name Symbolically linked to... Runlevel 0 | runlevel0.target -> poweroff.target Runlevel 1 | runlevel1.target -> rescue.target Runlevel 2 | runlevel2.target -> multi-user.target Runlevel 3 | runlevel3.target -> multi-user.target Runlevel 4 | runlevel4.target -> multi-user.target Runlevel 5 | runlevel5.target -> graphical.target Runlevel 6 | runlevel6.target -> reboot.target 它与init进程的主要差别如下。 (1)默认的 RunLevel(在/etc/inittab文件设置)现在被默认的 Target 取代,位置是/etc/systemd/system/default.target,通常符号链接到graphical.target(图形界面)或者multi-user.target(多用户命令行)。 (2)启动脚本的位置,以前是/etc/init.d目录,符号链接到不同的 RunLevel 目录 (比如/etc/rc3.d、/etc/rc5.d等),现在则存放在/lib/systemd/system和/etc/systemd/system目录。 (3)配置文件的位置,以前init进程的配置文件是/etc/inittab,各种服务的配置文件存放在/etc/sysconfig目录。现在的配置文件主要存放在/lib/systemd目录,在/etc/systemd目录里面的修改可以覆盖原始设置。 七、日志管理Systemd 统一管理所有 Unit 的启动日志。带来的好处就是,可以只用journalctl一个命令,查看所有日志(内核日志和应用日志)。日志的配置文件是/etc/systemd/journald.conf。 journalctl功能强大,用法非常多。 # 查看所有日志(默认情况下 ,只保存本次启动的日志) $ sudo journalctl # 查看内核日志(不显示应用日志) $ sudo journalctl -k # 查看系统本次启动的日志 $ sudo journalctl -b $ sudo journalctl -b -0 # 查看上一次启动的日志(需更改设置) $ sudo journalctl -b -1 # 查看指定时间的日志 $ sudo journalctl --since="2012-10-30 18:17:16" $ sudo journalctl --since "20 min ago" $ sudo journalctl --since yesterday $ sudo journalctl --since 09:00 --until "1 hour ago" # 显示尾部的最新10行日志 $ sudo journalctl -n # 显示尾部指定行数的日志 $ sudo journalctl -n 20 # 实时滚动显示最新日志 $ sudo journalctl -f # 查看指定服务的日志 $ sudo journalctl /usr/lib/systemd/systemd # 查看指定进程的日志 $ sudo journalctl _PID=1 # 查看某个路径的脚本的日志 $ sudo journalctl /usr/bin/bash # 查看指定用户的日志 $ sudo journalctl _UID=33 --since today # 查看某个 Unit 的日志 $ sudo journalctl -u nginx.service $ sudo journalctl -u nginx.service --since today # 实时滚动显示某个 Unit 的最新日志 $ sudo journalctl -u nginx.service -f # 合并显示多个 Unit 的日志 $ journalctl -u nginx.service -u php-fpm.service --since today # 查看指定优先级(及其以上级别)的日志,共有8级 # 0: emerg # 1: alert # 2: crit # 3: err # 4: warning # 5: notice # 6: info # 7: debug $ sudo journalctl -p err -b # 日志默认分页输出,--no-pager 改为正常的标准输出 $ sudo journalctl --no-pager # 以 JSON 格式(单行)输出 $ sudo journalctl -b -u nginx.service -o json # 以 JSON 格式(多行)输出,可读性更好 $ sudo journalctl -b -u nginx.service -o json-pretty # 显示日志占据的硬盘空间 $ sudo journalctl --disk-usage # 指定日志文件占据的最大空间 $ sudo journalctl --vacuum-size=1G # 指定日志文件保存多久 $ sudo journalctl --vacuum-time=1years 八、结语转载于http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html 引申阅读: LINUX PID 1 和 SYSTEMD]]></content>
</entry>
<entry>
<title><![CDATA[Git 学习笔记 - 基本操作]]></title>
<url>%2F2017%2F05%2F11%2Fgit-how%2F</url>
<content type="text"><![CDATA[#Git 闲话 1、最近阅读《数学之美》、《浪潮之巅》惊叹于大神的眼界、文化功底,所以就在得到专栏上订阅了吴军博士的硅谷来信。总之,就是膜拜了。想了解一个人,就先了解一个的思想对不对,所谓见贤与之思齐就是这样了。2、接下来说一说我心目中的另一位大神 林纳斯•托瓦兹,编程界公认的啊。“我不是个有远见的人,我是一名工程师,”托瓦兹说,“我非常乐意跟梦想家在一起,他们行走四方,仰望苍穹……但我是低头看路的那种人,我只想填好眼前这个坑,不让自己掉进去。“只干了两件事啊,毫不夸张的说:惊天地泣鬼神。第一件是开发出Linux内核,驱动了因特网,第二件是开发出Git,一种源代码管理系统,被全世界开发者广泛使用。再接下来,Git 就是我们的主题了,记录以备忘。 Git安装与配置安装Mac 上brew安装算是最便捷的了 ~ brew install git ~ brew --version Homebrew 1.1.13 Homebrew/homebrew-core (git revision ea163; last commit 2017-04-20) ~ git --version git version 2.11.0 配置可以通过 git config –list –global 命令来查看: ~ git config --list --global [email protected] user.name=千古不见一人闲 color.ui=auto alias.st=status alias.lg=log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit 可以看到有两个alias出现,这里使用了别名。 配置别名 这个功能在shell中是很常用的。我们可以做一些别名来取代比较复杂的指令。比如上面就是使用了以下两个配置 ~ git config --global alias.st status ~ git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit" 身份认证当本地git仓库与git远程仓库通信的时候,需要进行SSH身份认证。打开根目录下的.ssh目录: ~/.ssh la . .. config github_rsa github_rsa.pub id_rsa id_rsa.pub known_hosts 如果没有id_rsa和id_rsa.pub这两个文件,就通过如下的命令生成: ssh-keygen -t rsa -C “[email protected]”id_rsa和id_rsa.pub这两个文件,就是SSH Key的秘钥对,id_rsa是私钥,id_rsa.pub是公钥,用在github上表明身份。在GitHub上的SSH keys中添加刚刚生成的key。(id_rsa.pub) 创建Git仓库创建一个目录,并cd到目录下,通过调用git init来将现有目录初始化为git仓库,或者直接在git init后面跟上目录名,同样也可以创建一个新的仓库。 git clone 直接clone一个远程仓库也是可以的。 提交修改~/Documents/workspace git_springboot ~/Documents/workspace/git_springboot(master ✔) la . .. .git ~/Documents/workspace/git_springboot(master ✔) touch README.md ~/Documents/workspace/git_springboot(master ✗) vim README.md ~/Documents/workspace/git_springboot(master ✗) git add README.md ~/Documents/workspace/git_springboot(master ✗) git commit -m "add README.md" [master be9081a] add README.md 1 file changed, 1 insertion(+) create mode 100644 README.md ~/Documents/workspace/git_springboot(master ✔) 查看修改修改README.md文件,git st查看修改 ~/Documents/workspace/git_springboot(master ✗) git st On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: README.md no changes added to commit (use "git add" and/or "git commit -a") Git 比较不同版本文件差异的常用命令格式: git diff 查看尚未暂存的文件更新了哪些部分 git diff filename 查看尚未暂存的某个文件更新了哪些 git diff –cached 查看已经暂存起来的文件和上次提交的版本之间的差异 git diff –cached filename 查看已经暂存起来的某个文件和上次提交的版本之间的差异 使用git diff README.md 命令看一下修改的具体内容 diff –git a/README.md b/README.mdindex e8281cd..f1729fb 100644— a/README.md+++ b/README.md@@ -1 +1 @@-this’s ok.+this’s ok,modify. add和commit之后,我们都使用status来查看下状态,可以发现,在commit之后,git提示我们,工作区是干净的。 ~/Documents/workspace/git_springboot(master ✗) git st On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: README.md no changes added to commit (use "git add" and/or "git commit -a") ~/Documents/workspace/git_springboot(master ✗) git add README.md ~/Documents/workspace/git_springboot(master ✗) git commit -m "modify README.md" [master a77107b] modify README.md 1 file changed, 1 insertion(+), 1 deletion(-) ~/Documents/workspace/git_springboot(master ✔) git st On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) nothing to commit, working tree clean 版本记录使用git lg 命令来查看也可以使用gitk命令来查看图形化的log记录 工作区与暂存区Git通常是工作在三个区域上: 工作区暂存区历史区其中工作区就是我们平时工作、修改代码的区域;而历史区,用来保存各个版本;而暂存区,则是Git的核心所在。Git官网图解Git 版本回退回退版本是必不可少的操作啊 我们来考虑以下常见的几种情况: 文件已经修改,但是还没有git add 文件已经add到暂存区,又作了修改 文件的修改已经add到了暂存区 分别执行以下操作: ➜git checkout – README.md修改被删除,完全还原到上次commit的状态,也就是服务器版本(1.)最后的修改被删除,还原到上次add的状态,也就是修改前的暂存区状态(2.)➜git reset HEAD README.md(3.) ~/Documents/workspace/git_springboot(master ✗) git st On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: README.md ~/Documents/workspace/git_springboot(master ✗) git reset HEAD README.md Unstaged changes after reset: M README.md ~/Documents/workspace/git_springboot(master ✗) git st On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: README.md no changes added to commit (use "git add" and/or "git commit -a") 通过git reset HEAD README.md,我们就把暂存区的文件清除了。这样,在本地就是add前的状态,通过checkout操作,就可以进行修改回退了。在Git中,用HEAD表示当前版本,上一个版本就是HEAD^,上上一个版本就是HEAD^^。(git reset –hard HEAD)要回退到哪个版本,也可以写commit id。 前进版本如果我们回退到了旧的版本,但是却后悔了想回到后面某个新的版本,git reflog 查看操作历史。找到 commit id。版本号没必要写全,前7位就可以了,Git会自动去找。 文件暂存这里的暂存不是前面说的暂存区,而是只一次备份与恢复操作。git stash指令来将当前修改暂存,这样就可以切换到其他分支或者就在当前干净的分支上checkout了。比如你checkout了一个issue分支,修改了bug,使用git merge合并到了master分支,删除issue分支,切换到dev分支,想继续之前的新功能开发。这时候,就需要恢复现场了: git stash list指令来查看当前暂存的内容记录。然后,通过git stash apply或者git stash pop来进行恢复,它们的区别是,前者不会删除记录(当然你可以使用git stash drop来删除),而后者会。 远程仓库&同步协作 Git关联远程仓库 Git学习资料*Git学习资料]]></content>
</entry>
</search>