fz00x0zf's blog


  • 首页

  • 日志

  • 标签

  • 分类

  • 玩儿

  • 关于

何为技术领导力

Posted on 2019-11-12 | In 转载

转自:陈皓专栏-《左耳听风》

以下未正文:

我先说明一下,我们要谈的并不是“如何成为一名管理者”。我想谈的是技术上的领先,技术上的优势,而不是一个职称,一个人事组织者。另外,我不想在理论上泛泛而谈这个事,我想谈得更落地、更实际一些,所以,我需要直面一些问题。

首先,要考虑的问题是——做技术有没有前途?我们在很多场合都能听到:技术做不长,技术无用商业才有用等这样的言论。所以,在谈技术领导力前,我需要直面这个问题,否则,技术领导力就成为一个伪命题了。

技术重要吗?

在中国,程序员把自己称做“码农”,说自己是编程的农民工,干的都是体力活,加班很严重,认为做技术没有什么前途,好多人都拼命地想转管理或是转行。这是中国技术人员的一个现实问题。

与国外相比,似乎中国的程序员在生存上遇到的问题更多。为什么会有这样的问题?我是这么理解的,在中国,需要解决的问题很多,而且人口众多。也就是说,中国目前处于加速发展中,遍地机会,公司可以通过“野蛮开采”来实现自身业务的快速拓展和扩张。而西方发达国家人口少一些,相对成熟一些,竞争比较激烈,所以,更多的是采用“精耕细作”的方式。

此外,中国的基础技术还正在发展中,技术能力不足,所以,目前的状态下,销售、运营、地推等简单快速的业务手段显得更为有效一些,需要比拼的是如何拿到更多的“地”。而西方的“精耕细作”需要比拼的是在同样大小的一块田里,如何才能更快更多地种出“粮食”,这完全就是在拼技术了。

每个民族、国家、公司和个人都有自己的发展过程。而总体上来说,中国公司目前还处于“野蛮开采”阶段,所以,这就是为什么很多公司为了快速扩张,要获得更多的用户和市场 ,需要通过加班、加人、烧钱、并购、广告、运营、销售等这些相对比较“野蛮”的方式发展自己,而导致技术人员在其中跟从和被驱动。这也是为什么很多中国公司要用“狼性”、要用“加班”、要用“打鸡血”来驱动员工完成更多的工作。

但是,这会成为常态吗?中国和中国的公司会这样一直走下去吗?我并不觉得。

这就好像人类的发展史一样。在人类发展的初期,蛮荒民族通过野蛮地掠夺来发展自己的民族更为有效,但我们知道资源是有限的,一旦没有太多可以掠夺的资源,就需要发展“自给自主”的能力,这就是所谓的“发展文明”。所以,我们也能看到,一些比较“文明”的民族在初期搞不过“野蛮”的民族,但是,一旦“文明”发展起来,就可以从质上完全超过“野蛮”民族。

从人类历史的发展规律中,我们可以看到,各民族基本都是通过“野蛮开采”来获得原始积累,然后有一些民族开始通过这些原始积累发展自己的“文明”,从而达到强大,吞并弱小的民族。

所以,对于一个想要发展、想要变强大的民族或公司来说,野蛮开采绝不会是常态,否则,只能赢得一时,长期来说,一定会被那些掌握先进技术的民族或公司所淘汰。

从人类社会的发展过程中来看,基本上可以总结为几个发展阶段。

第一个阶段:野蛮开采。这个阶段的主要特点是资源过多,只需要开采就好了。

第二个阶段:资源整合。在这个阶段,资源已经被不同的人给占有了,但是需要对资源整合优化,提高利用率。这时通过管理手段就能实现。

第三个阶段:精耕细作。这个阶段基本上是对第二阶段的精细化运作,并且通过科学的手段来达到。

第四个阶段:发明创造。 在这个阶段,人们利用已有不足的资源来创造更好的资源,并替代已有的马上要枯竭的资源。这就需要采用高科技来达到了。

这也是为什么像亚马逊、Facebook 这样的公司,最终都会去发展自己的核心技术,提高自己的技术领导力,从早期的业务型公司转变成为技术型公司的原因。那些本来技术很好的公司,比如雅虎、百度,在发展到一定程度时,将自己定位成了一个广告公司,然后开始变味、走下坡路。

同样,谷歌当年举公司之力不做技术做社交也是一个失败的案例。还好拉里·佩奇(Larry Page)看到苗头不对,重新掌权,把产品经理全部移到一边,让工程师重新掌权,于是才有了无人车和 AlphaGo 这样真正能够影响人类未来的惊世之作。

微软在某段时间由一个做电视购物的销售担任 CEO,也出现了技术领导力不足的情况,导致公司走下坡路。苹果公司,在聘任了一个非技术的 CEO 后也几近破产。

尊重技术的公司和不尊重技术的公司在初期可能还不能显现,而长期来看,差距就很明显了。

所以,无论是一个国家,一个公司,还是一个人,在今天这样技术浪潮一浪高过一浪的形势下,拥有技术不是问题,而问题是有没有拥有技术领导力。

说的直白一点,技术领导力就是,你还在用大刀长矛打战的时候,对方已经用上了洋枪大炮;你还在赶马车的时候,对方已经开上了汽车……

什么是技术领导力?

但是,这么说还是很模糊,还是不能清楚地说明什么是技术领导力。我认为,技术领导力不仅仅是呈现出来的技术,而是一种可以获得绝对优势的技术能力。所以,技术领导力也有一些特征,为了说清楚这些特征,先让我们来看一下人类历史上的几次工业革命。

第一次工业革命。第一次工业革命开始于 18 世纪 60 年代,一直持续到 19 世纪 30 年代至 40 年代。在这段时间里,人类生产逐渐转向新的制造过程,出现了以机器取代人力、兽力的趋势,以大规模的工厂生产取代个体工厂手工生产的一场生产与科技革命。由于机器的发明及运用成为了这个时代的标志,因此历史学家称这个时代为机器时代(the Age of Machines)。

这个时期的标志技术是——“蒸汽机”。在瓦特改良蒸汽机之前,生产所需的动力依靠人力、畜力、水力和风力。伴随蒸汽机的发明和改进,工厂不再依河或溪流而建,很多以前依赖人力与手工完成的工作逐渐被机械化生产取代。世界被推向了一个崭新的“蒸汽时代”。

第二次工业革命。第二次工业革命指的是 1870 年至 1914 年期间的工业革命。英国、德国、法国、丹麦和美国以及 1870 年后的日本,在这段时间里,工业得到飞速发展。第二次工业革命紧跟着 18 世纪末的第一次工业革命,并且从英国向西欧和北美蔓延。

第二次工业革命以电力的大规模应用为代表,以电灯、电报以及无线电通信的发明为标志。这些发明把人类推向了“电力”时代。电力和内燃技术的出现,让人类进入了真正的工业时代。随着这些技术的发展,工人阶级开始受到关注,并逐渐出现了有专业知识的中产阶级,而且人数众多。

第三次工业革命。第三次工业革命又名信息技术革命或者数字化革命,指第二次世界大战后,因计算机和电子数据的普及和推广而在各行各业发生的从机械和模拟电路再到数字电路的变革。第三次技术革命使传统工业更加机械化、自动化。它降低了工作成本,彻底改变了整个社会的运作模式,也创造了电脑工业这一高科技产业。

它是人类历史上规模最大、影响最深远的科技革命,至今仍未结束。主要技术是“计算机”。计算机的发明是人类智力发展道路上的里程碑,因为它可以代替人类进行一部分脑力活动。

而且,我们还可以看到,科学技术推动生产力的发展,转化为直接生产力的速度在加快。而科学技术密切结合,相互促进,在各个领域相互渗透。

近代这几百年的人类发展史,从蒸汽机时代,到电力时代,再到信息时代,我们可以看到这样的一些信息。

关键技术。蒸汽机、电、化工、原子能、炼钢、计算机,如果只看这些东西的话,似乎没什么用。但这些核心技术的突破,可以让我们建造很多更牛的工具,而这些工具能让人类干出以前干不出来的事。

自动化。这其中最重要的事就是自动化。三次革命中最重要的事就是用机器来自动化。通信、交通、军事、教育、金融等各个领域都是在拼命地自动化,以提高效率——用更低的成本来完成更多的事。

解放生产力。把人从劳动密集型的工作中解放出来,去做更高层次的知识密集型的工作。说得难听一点,就是取代人类,让人失业。值得注意的是,今天的 AI 在开始取代人类的知识密集型的工作……

因此,我们可以看到的技术领导力是:

尊重技术,追求核心基础技术。

追逐自动化的高效率的工具和技术,同时避免无效率的组织架构和管理。

解放生产力,追逐人效的提高。

开发抽象和高质量的可以重用的技术组件。

坚持高于社会主流的技术标准和要求。

如何拥有技术领导力?

前面这些说的比较宏大,并不是所有的人都可以发明或创造这样的核心技术,但这不妨碍我们拥有技术领导力。因为,我认为,这世界的技术有两种,一种是像从马车时代到汽车时代这样的技术,也就是汽车的关键技术——引擎,另一种则是工程方面的技术,而工程技术是如何让汽车更安全更有效率地行驶。对于后者来说,我觉得所有的工程师都有机会。

那么作为一个软件工程师怎样才算是拥有“技术领导力”呢?我个人认为,是有下面的这些特质。

能够发现问题。能够发现现有方案的问题。

能够提供解决问题的思路和方案,并能比较这些方案的优缺点。

能够做出正确的技术决定。用什么样的技术、什么解决方案、怎样实现来完成一个项目。

能够用更优雅,更简单,更容易的方式来解决问题。

能够提高代码或软件的扩展性、重用性和可维护性。

能够用正确的方式管理团队。所谓正确的方式,一方面是,让正确的人做正确的事,并发挥每个人的潜力;另一方面是,可以提高团队的生产力和人效,找到最有价值的需求,用最少的成本实现之。并且,可以不断地提高自身和团队的标准。

创新能力。能够使用新的方法新的方式解决问题,追逐新的工具和技术。

我们可以看到,要做到这些其实并不容易,尤其,在面对不同问题的时候,这些能力也会因此不同。但是,我们不难发现,在任何一个团队中,大多数人都是在提问题,而只有少数人在回答这些人的问题,或是在提供解决问题的思路和方案。

是的,一句话,总是在提供解决问题的思路和方案的人才是有技术领导力的人。

那么,作为一个软件工程师,我们怎么让自己拥有技术领导力呢?总体来说,是四个方面,具体如下:

扎实的基础技术;

非同一般的学习能力;

坚持做正确的事;

不断提高对自己的要求标准;

好了。今天要聊的内容就是这些,希望你能从中有所收获。而对于如何才能拥有技术领导力,你不妨结合我上面分享的四个点来思考一下,欢迎在留言区给出你的想法,下一篇文章,我也将会和你继续聊这个话题。

以上

(全文完)

转自:陈皓专栏-《左耳听风》https://time.geekbang.org/column/article/288

技术人员的发展之路

Posted on 2019-09-29 | In 转载

(转载本站文章请注明作者和出处 酷 壳 – CoolShell ,请勿用于任何商业用途)

2012年的时候写过一篇叫《程序算法与人生选择》的文章,我用算法来类比如何做选择,说白了就是怎么去计算,但是并没有讲程序员可以发展的方向有哪些。所以,就算是有这些所谓的方法论,我们可能对自己的发展还是会很纠结和无所事从,尤其是人到了30岁,这种彷徨和迷惑越来越重。虽然我之前也写过一篇《编程年龄和编程技能》的文章,但是还是有很多做技术的人对于自己能否在年纪大时还能去做技术感到没有信心。我猜测,这其中,最大的问题的是,目前从事技术工作的种种负面的经历(比如经常性的加班,被当成棋子或劳动力等等),让人完全看不到希望和前途,尤其是随着年纪越来越大,对未来的越来越没有信心。

同时,也是因为在GIAC的大会被问到,程序员老了怎么办?而在年底这段时间,也和几个朋友在交流中不断地重复谈到个人发展的这个话题。我的人生过半,活到“不惑”的年纪,自然经常性的对什么事都会回头看看总结归纳,所以,在交谈过程中和交谈过后,自己也有一些思考想记录下来。因为我本人也是在这条路上的人,所以,谈不上给他人指导,我同样也是在瞎乱折腾同样每天在思考自己要去哪儿的“一尘世间迷途老生”。况且,我的经历和眼界非常有限,因此,下面的这些关于个人发展的文字和思考必然是受我的眼界和经历所局限的。也欢迎大家补充和指正。

这些东西不一定对,也不一定就是全部,期许可以让你在年底的时候有所思考,在明年的时候有所计划。

一个重要阶段和标志
在讲个人发展之前,我需要先说一下人生中的一个非常重要的阶段——20到30岁!

这个阶段的首要任务,就是提升自己学习能力和解决难题的能力。这是一个非常非常关键的时间段!这个时间段几乎决定着你的未来。

30岁以前,这个时间段,应该是人学习和积累的时间段,这个时间段,就是努力学习的时间段。这个时间段,你一定要把时间花在解决问题的技能上。就是说,你一定要练就成的技能是——你能解决大多数人不能解决的问题。使蛮力埋头加班苦干,当一个搬砖老黄牛的是肯定没有前途的。如果你不幸呆在了一个搬砖的地方,天天被业务压得喘不过气来,我建议你宁可让你的项目延期被老板骂,也要把时间挤出来努力学习基础知识,多掌握一些技术(很多技术在思路上是相通的),然后才能有机会改变自己目前的状况。因为,比起你的个人未来,项目延期被老板骂、绩效不好拿不到奖金,都不是什么事儿。

总结一下,你在30岁前,工作5-7年,你需要拥有:

高效的学习能力。这意味着——基础知识扎实、触类旁通、读英文文档不费劲、有寻找前沿知识的能力、能够看到问题和技术的本质、善于思辩、能独立思考。
解决问题的能力。这意味着——你要高效的学习能力、见过很多的场景、犯过或是处理很多错误、能够防火而不是救火。
如果你拥有这两个能力的现象是—— 在团队或身边的人群中的显现出Leadership。

Leadership并不是当领导和经理,而是一种特征,这种特征有如下两个简单的表象:

帮人解问题。团队或身边中大多数人都在问:“这问题怎么办?”,而总是你能站出来告诉大家这事该怎么办?
被人所依赖。团队或身边中大多数人在做比较关键的决定时,都会来找你咨询你的意见和想法。
一但你在在30岁之间出现了Leadership这样的特征,那么,你会进入一个正循环的阶段:

因为你学习能力强,所以,你会有更多的机会解决难题。
你有更多的机会解决难题,你就会学更多的东西,于是你就会更强。
上面这个循环,只要循环上几年,就会让你人生的各种可能性大大的增加。
【 注意 】

要达到这样的特质,需要找到自己的长处、以及适合自己的环境。就像鱼的特长是呆在水里,让鱼儿去追求陆上动物的刺激生活并不靠谱。
一般说来,有这样的潜质的人,在学校中就应该要出现。如果你在大学中还没有出现这样的潜质,那么,你在工作当中要加倍努力了(注:所谓的加倍努力,不是让你使蛮力加班,而是让你多学习成长,使蛮力拼命是弥补不了能力、思维、眼界上的缺陷的)。
Leadership也有范围的,比如,身边的朋友,工作中的团队/部分,圈内,整个行业。Leadership的范围越大,你的个人发展的选择性就越高。反之则越小。
如果已到了30岁左右,还是没有出现这样的特征。那么,可能未来你也很难有这样的Leadership了。而你的个人发展的可能性可能也就不多了(sigh…)
读到这里,我必需要说一下,如果你已开始显现出你的Leadership,那么你才谈得上个人发展,这篇文章后续的内容也可能才会对你有意义。

个人发展的三个方向
以我个人短浅的经历和视野,目前只看到的人的发展有如下三个大方向(他们之间可能会有重叠):

1)在职场中打拼

2)去经历有意义有价值的事

3)追求一种自由的生活

这三个方向,我个人或多或少都体验过,我也见过身边的很多人走这三个方向走的比较成功。也许还有别的方向,没办法,现在,我的视野就这么大,所以,我在这里,我主要就是谈谈这三个方向。Again,人有资格去走这三个方向的前提是——已有了上面我说的Leadership那种特质!

一、在职场中发展
在职场中发展应该是绝大多数人的选择。通过加入公司来达到人生的发展。

我们经常可以看到很多所谓的“职业规划”,但是大多数职业规划只不过人力资源搞出来的东西,和实际其实是有很大出入的。我的人生经历中,有18年左右是在公司中度过的,在过银行,小公司,大公司,民营公司,外国公司,传统IT公司,互联网公司,不同的公司完全有不同的玩法和文化,我的经历还算丰富,但也不算特别成功,这里只分享一些我在职场中的心得(不一定对,仅供参考)。

1、去顶尖公司

去顶尖公司的一个目的就是让你的Leadership的范围的可能性扩大。

因为公司和公司的差距也不小,所以,就算你在低端公司里是骨干份子,但在高端公司里可能只是一个普通员工(就像中国足球队的主力到了英超可能都无法入选)。所以,在职场中,如果你要让你的个人价值最大化的话,你一定要去顶尖的公司。因为顶尖公司里有非常不错的工作方法和场景,这并不是能看书或是交流得来的,这是必需要去亲身体验的。所以说,在顶尖公司掌握的技能,开阔的眼界,通常来说都会比低端公司的要多得多。

另外,每个公司的工作级别都是有相互对标的,比如:阿里的P几对应于百度的T几。国内的一线公司职位还相当,但是如果和国外一线公司的比,那就有差距了,而且差距还很大。比如,Google或Facebook的某个高级工程师,可能就对应于阿里的P8/P9甚至更高。

是的,对于职场来说,如果你在顶尖公司是骨干,那么,你去低端公司,则有很大机会会成为他们高管和核心。就好像你在Facebook里干三五年成为他们的技术骨干,那么你到BAT去成成为高管概率是非常大的。反过来,如果你毕业主去了BAT成为了一个螺丝钉,在天天加班中度过你的青春,你干个十年能成为BAT的高管的概率可能会非常的低。

2、去真正的创业公司

去顶尖公司和去创业公司在某些时候并不冲突。不过,这里我想讲的是,一个技术能力强的人在大公司可能会被埋没掉。因为大公司业务成功后,

成功的公司在招聘各种高级技术人才都不会成为问题,于是少你一个不少,多你一个不多。
成功的公司其整个技术体系已经完成,Legacy的问题也比较多,所以,可以供你发挥的余地不大。
成功的公司更多的可能会想要稳定的系统,稳定必然会产生保守,而保守则产生不思进取。
所以,对于中高级人才来说,在大公司里的能产生的个人价值,可能远远不如那些求贤若渴、没有包袱、可以尽情施展、相对更为灵活和自由的创业型公司。

不过,去创业公司需要小心仔细的挑选和评估,创业公司的不确定因素很多,也和创始人的因素太大了,所以,你需要小心了解创始人和他们的业务情况,想法和理念差不多才能更好的共事。

好多创业公司其实并不是真正的创业公司,他们创业有很大的侥幸和驱利心理,要小心甄别。因为那不是真正的创业公司。

3、职业生涯的发展阶段

首先,有一个不争事实——整个社会是会把最重要的工作交给30岁左右的这群人的。也就是说,30岁左右这群人是这个社会的做事的中坚力量。

所以,这是一个机遇!如果你有了Leadership,你就一定能在这个时间段内赶得上这个机遇——公司和领导对你寄于信任和厚望,并把重要的团队和工作交给你。

于是,你的30岁到40岁就成了一个职业生涯的发展期,也就是你的事业上升期。如果你到40岁都没有赶上,那么你的职业生涯也就这样了,老有所成的人是少数。

在你事业的上升期,你需要更多的软技能,比如:

带领产品和业务的发展的能力
推行自己喜欢的文化的能力
项目管理的能力——在任务重、时间紧中求全
沟通和说服别人的能力
解决冲突的能力
管理和发展团队的能力
解决突发事件的应急能力
…… ……
另外,你还要明白在职场里的几个冷酷的事实:

你开始要关心并处理复杂的人事。尤其在大公司,大量的人都是屁股决定脑袋,利益关系复杂,目标不一致,每个人心里都有不一样的想法。这个时候再也不是talk is cheap, show me the code!而是,code is cheap,talk is the matter。你需要花大量的时间去思考和观察形形色色的人。需要耗费大量的精力在不同的人之间周旋,而不是花时间去创造些什么有价值的东西。
你要开始学会使用各种政治手段。办公室政治不可避免,越大的公司越重,自从你开始成为一线的leader的那一天起,你就开始成为“里外不是人”的角色,需要在下属和领导,员工和公司之间周旋。随而你的级别越来越高,你需要使用更多的政治手段,你会学会审时度世的站队,学会迎合员工和领导,学会用官员的语言说话,学会此一时彼一时,学会妥协和交换,学会忍气吞声,学会在在适当的时机表现自己,学会波澜不惊,学会把自己隐藏起来,甚至你还会迷失自我,开始学会一些厚黑学,比如不得不在适当的时机在背后捅人刀子……你可能会成为一个你自己都讨厌的人
听上去真的好无聊,所以,你现在也明白为什么高层们都看上去很忙很累,而且抽不出时间来关心细节问题,因为,他们更多的是要协调整个组织和系统来运转,甚至还要四处周旋,各种博弈,没办法,这是职场的必需的东西!听起来是不是感觉人类很愚蠢?这真是没办法的事。如果你不想或是也没有能力玩这些东西,那么你需要去那些可以让技术人员安安心心做技术的公司。这类的公司,我见过Microsoft、Google、Amazon或是一些创业公司里都有。国内的大公司中也有让技术人员成长的职业成长线,但老实说,表面上看似是一个让人专心做技术的升职成长线,但其实还是管理岗位。

所以,技术人员在职场中的归宿有两条路 —— 到真正的技术公司成为一个专心做技术的人,或是在成为一个职业的经理人。

二、追求人生的经历
先说三个故事,

第一个,是在阿里的时候,有一天在内网里看到一个贴子,一个做产品的女孩说自己准备离职要去法国学烘培厨艺,引得大家热评。
第二个,是在亚马逊的美国老板,他每年都要去报个培训班学一个技能,比如:厨艺、开双翼飞机、夜总会里的DJ……、甚至去华盛顿去学当一个政客。
第三个,是在汤森路透工作时,一个英国的同事,有一天他说他离职了,和自己的老婆准备用余生去周游世界,我问他是不是有足够多的钱了?他和我说,钱不够,他俩口子的计划是,边旅游边打工,打工打够到下一站的钱就走。他还说,那种用假期去另一个城市的旅游太没意思了,如果你不在那个地方生活上一段时间 ,你怎么能算是好的旅游体验呢?好吧,无法反驳。
我是觉得他们把自己的人生过得如此有意思,令我很佩服。虽然跨界跨得有点猛,但是 Why Not?

在这里,我想说,去追求一种和众人不一样的人生经历也是一件挺好的事,我个人感觉,比起在职场里有趣地多多了。如果你厌倦了职场,其实为什么不去追求一下不同的人生经历呢。就算你不想去追求跨度比较大的人生经历,那么,在技术圈里,也有很多有价值有意思的经历也可以去的。追求刺激有意义的与众不同的经历的人,其实也能算是一种人生的成功,不是吗?

如果只说技术方面,我个人看到的去追求经历的人,有两种追求的人其实也很成功的:

到技术创新的发源地去经历创新。计算机互联网各种技术的创新引擎,基本上来说,就是在美国了。我们赶上了这个时代,也选对了这个时代最火热的行业,那么,有什么理由不去这个时代的技术发动机那里去经历呢?在美国硅谷湾区,无论是大公司,还是创业公司,都在迸发着各式各样的创新,如果有能力有机会,为什么不努力去经历一下呢?不经历一下,老了不会觉得错过了是一种后悔吗?
去经历下一个热点技术的发展。从IT,到互联网、再到移动互联网、云计算、大数据,再到未来的AI,VR,IoT……,技术创新的浪潮一波接一波的过来,你是想在那继续搬砖搬下去,是想迎浪而上去经历浪潮,还是想成为一个随波逐流的人?
打工也好,创业也好,在国内也好,在国外也好,这些都是形式,不是内容。内容则是你有没有和有想法的人去经历有意义有价值事?人生苦短,白驹过隙,我们技术人员最大的幸运就是生在这样一个刺激的时代,那么,你还有什么理由不去追逐这些前沿刺激的经历呢?

三、追求自由的生活
我相信“自由”这个事,是所有人的心中都会想去追求的。“生命诚可贵,爱情价更高,…… ”(哈哈)

但一说起自由,绝大多数人都想到的是“财富自由”或是“财务自由”,其实,并不完全是这样的,在自由的通路上,我个人的经历告诉我,其实,你会有很多的不同类型的自由。下面,是我对几个层次的“自由”的理解。

第一层自由——工作自由。人的第一层自由的境界是——“工作自由”,我到不是说你在工作单位上可以很自由,虽然有特例,但并不普遍。我想说的“工作自由”是——你不会有失业危机感了。也就是说,你成了各个公司的抢手货,你不但不愁找不到工作,而且你是完全不愁找不到好工作。试想一下,如果是工作来找你,一方面,你就有真正意义上的工作选择权了,另一方面,你都不愁工作了,你完全就可以随时离职去干你想干的事了。此时,你就达到了“工作自由”。

第二层自由——技能自由。工作自由已是不错,不过前提是你还是需要依赖于别人提供的工作机会。而技能自由则是你可以用自己的技能养活自己,而不需要去公司里工作。也就是所谓的自由职业者了,社会上,这样的人也不少,比如,一些健身体育教练、设计师、翻译者、作者……这些都可以算是自由职业者,程序员这个职业中只要不是搬砖的,有想法的,就有可以成为自由积业者的潜质,想一想,你拥有的编程能力,其实是一种创造的能力,也就是创造力,只要你Make Something People Want(YC创业公司的slogan),你是完全可以通过自己的技能来养活自己的。如果你通过某些自动化的东西,或是你在App上做了一个软件个体户,让自己的收入不断,甚至你做了一个开源软件,社区每个月都给你捐款捐到比你打工挣的还多,那么你就真正的有了技能自由了。

第三层自由——物质自由。我把财务自由换了一种说法。我个人觉得,除了有个好爸爸之外这种特例的情况,如果你想有物质自由的话,本质上来说,你一定要学会投资,投资不一定是你的钱,时间也是一种财富,年轻更是,你怎么投资你的时间还有你的青春?你要把你的投资投到什么样的事,什么样的人?对于投资这个事,风险也比较大。但是,人生不敢冒险可能才是最大的冒险。这个世界有很多技术不是你能看书学来的,而要只能在实战中学会的,比如:游泳。投资可能也是一种。只有真正懂投资的人,或是运气非常好的人,才可能实现物质自由。

追求自由的生活,其实也是个人发展道路上的一个不错的选择。通常来说,自由的人,能力都不差,钱也不会少。因为,他们懂得投资。

也就是说,拥有追求自由能力的的人,

不但有领导力和创造力(也可指导大多数人并走在大多数人前面)
同时他还懂得怎么投资(知道时间和精力和金钱应该投在什么地方)
(注:这里我没有提精神自由,老实说,精神上的自由我也不清楚是什么东西,因为我还没有见过,眼界有限,所以先按不表了,不然真成鸡汤文了)

总结
无论是在职场中打拼,还是追求精彩的经历,还是去实现自由,我觉得都是不错的个人发展的方向。

他们都有重叠,比如:

你可以在职场中去追求那些刺激的经历的公司。
同样也可以通过加入有潜力高速发展的公司来达到自由。
你也可以通过追寻不一样的经历来达到人生的自由。
……
总之,这里的逻辑是——

能够去规划自己的个人发展的人,通常都是有很多机会和可能性的人。
有很多机会和可能性的人,通常都是有Leadership,喜欢冒险的人。
有Leadership喜欢冒险的人,通常都是学习能力强,思维活跃,喜欢折腾,懂得“投资”的人。
学习能力强思维活跃的人,通常来说,都是喜欢看书,喜欢实践和新鲜事物,不怕艰难和挑战,用智力而不是使蛮力的人。
懂得“投资”的人,通常来说,他们更多的关注的是未来和长远的成长,而不是当下的KPI、奖金和晋升。
(全文完)

(转载本站文章请注明作者和出处 酷 壳 – CoolShell ,请勿用于任何商业用途)

什么是 I/O 多路复用

Posted on 2019-07-10 | In Java , I/O

在高并发环境下,web 服务器需要处理成千上万的客户端连接,如何最大限度发挥单台机器的性能,使之在处理大量连接时仍保持较低的负载,这是个很重要的课题。本文介绍下解决此类问题的一种很经典的方式:I/O 多路复用。
传统 I/O

为了了解 I/O 多路复用是怎么产生的,我们先看下传统的网络 I/O 模式,也被称为 BIO(Blocking IO)。
在编写服务端网络程序时,传统的方式是这样的:创建套接字并绑定端口,然后用一个 while 循环,在循环里调用 accept,程序会阻塞,一旦有连接到来,accept 就返回,然后针对该连接做相应的读写处理。形式像下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 创建套接字
ServerSocket serverSocket = new ServerSocket();
// 绑定套接字
serverSocket.bind(new InetSocketAddress(2345));

// 循环
while(true) {
// 调用 accept 等待客户端连接,程序阻塞,当有连接到达时才返回
Socket socket = serverSocket.accept();
// 对套接字读写
handle(socket);

}
// 关闭套接字
serverSocket.colse();

一般我们在刚学网络编程时,都会用这种的方式,也被称为单线程模式,这种模式的特点就是简单直白,方式固定,写起来较容易。但有个致命问题:同一时间,它只能处理一个客户端请求,因为它直接是在主线程中处理请求的,只有在上一个请求处理完毕,才能接着处理下一个请求,一旦某个请求处理较慢,那后面的请求只能等待。
把上面的单线程模式改下,对每个连接,新开一个线程单独进行读写处理,这样就可以同时处理多个连接了,形式如下面这样:

1
2
3
4
5
6
7
8
9
10
// 创建和绑定步骤不变
// ...

while(true) {
Socket socket = serverSocket.accept();
// 新开一个线程,对套接字读写
new Thread(() -> {
handle(socket);
}).start();
}

这种模式就是多线程模式,比上面的那种要高级一点,它可以同时处理多个连接,因为对每个连接的处理都是在一个单独的线程中,和主线程分离开来,主线程可以继续 accept 客户端连接。
但这种模式仍然存在问题:
线程的创建和销毁的成本是很高的,创建线程需要消耗内存,1 个线程需要耗费 512K 到 1M 的内存,几十上百个可能看不出来,成千上万的话,内存很快就耗尽。
线程池能解决部分问题,但当请求过多,线程池仍然处理不过来,导致大量的请求超时,更严重的是,大量的线程会导致大量的线程切换,线程切换,或者说上下文切换是需要 CPU 开销的,线程切换越频繁,真正分配给业务的 CPU 资源就越少。
上面的两种模式,不管是单线程模式还是多线程模式,我们都称之为阻塞模式(Blocking I/O),是因为它们对连接的处理,都是以线程为基石,在一个线程中处理一个 socket 的读写,但实际情况是,线程的大部分时间都是在等待数据的到来。当调用 recvfrom 时,线程会等待着客户端的数据到达网卡,然后网卡把数据交给内核,然后内核再把数据拷贝到用户进程空间,这时 recvfrom 才会返回。这个过程
中,线程的绝大部分时间都是处于等待数据状态,什么也做不了。而下面要介绍的 I/O 多路复用,就是为解决此问题而生。
I/O 多路复用

上面我们分析了由线程直接处理网络 I/O 的低效原因,想象下,当我们调用 recvfrom,发现数据还没准备好,就不傻等了,而是告诉系统:等数据准备好了,你告诉我下,我再来读。这时线程可以先去干点别的,比如去检查下有没有其他的连接。过了一会儿,系统产生了一个可读事件,告诉我们,你要的数据准备好了,可以来读了,这时就可以继续回到刚才的地方读取数据。这样效率不是就好多了吗?因为在等数据的同时,我还可以干其他的事情。这是一种非阻塞模式,那么这种“数据好了通知我们”的机制怎么实现呢?
其实,操作系统已经给我们提供了 select,poll,epoll,kqueue 这样的系统调用,来完成我们上面的要求,这些系统调主要干一件事:监听一个或多个文件描述符上的各类事件,一旦文件描述符上有事件产生,就返回。文件描述符,是 Unix 系统下的一个叫法,也称为 fd(file descriptor),下文统称为 fd,fd 对应于 Windows 平台下的句柄(handle),一个文件描述符唯一标识了某进程打开的某个文件,Unix 的设计哲学就是一切皆文件,socket 也是文件,可以作为 fd 被监听。监听哪些事件呢?有:连接事件(acceptable),可读事件(readable),可写事件(writeable),关闭事件(closeable)等。于是通过这类系统调用,监听多个 fd,一旦某个 fd 上有某个事件产生,调用就会返回,于是我们知道“有事发生”,然后根据事件的类型,做不同的处理。因此,有时也把这种模型称为事件驱动模型,或者 Reactor 模式。
I/O 多路复用的关键,是它可以让内核监听 fd 的事件,而且可以同时监听多个 fd,和用一个线程处理一个 socket 连接有根本的区别,它只需要一个线程或进程,就管理了多个连接,我们可以用一句话来概括 I/O 多路复用:在一个线程或一个进程中,监听了多个 fd。这里的复用,指的是多个 fd,或者说多个连接,复用了一个线程或者进程。
I/O 多路复用的三种方式

select

首先来看 select,它的原型如下:

1
int select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

nfds 为需要监听的最大 fd 个数+1。
中间的三个参数 readfds、writefds 和 exceptfds 指定我们要让内核监听读、写和异常条件的 fd。如果对某一个的条件不感兴趣,就可以把它设为空指针。fd_set 结构体可以理解为集合,存放的是 fd,可以通过下面的宏处理这三种 fd_set:

1
2
3
4
FD_CLR(inr fd, fd_set *fdset);   // 清除 fd set 中相关 fd 的位
FD_ISSET(int fd, fd_set *fdset); // 测试 fd set 中相关 fd 的位是否为真
FD_SET(int fd, fd_set *fdset); // 设置 fd set 中相关 fd 的位
FD_ZERO(fd_set *fdset); // 清除 fd set 的全部位

select 的使用方法,我们看下面的例子,为了简单起见,我们只传入了可读事件的 fd,对其他的字段设置为 NULL,表示我们不感兴趣。在 for 事件循环中,调用 select,一旦 fd 有可读事件,就调用 read 处理读事件。其中判断可读是通过调用 FD_ISSET 来完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ssize_t nbytes;
for (;;) {
/* select call happens here */
if (select(FD_SETSIZE, &read_fds, NULL, NULL, NULL) < 0) {
perror("select");
exit(EXIT_FAILURE);
}
for (int i = 0; i < FD_SETSIZE; i++) {
if (FD_ISSET(i, &read_fds)) {
/* read call happens here */
if ((nbytes = read(i, buf, sizeof(buf))) >= 0) {
handle_read(nbytes, buf);
} else {
/* real version needs to handle EINTR correctly */
perror("read");
exit(EXIT_FAILURE);
}
}
}
}

运行后,程序会阻塞在 select,一旦 fds 中有可读事件,select 即返回,然后就可以遍历,查看到底是那个 fd 可读,并做相应处理。
I/O 多路复用概念被提出来后,select 是第一个实现它的系统调用,它是一个古老的实现,在 20 世纪 80 年代就诞生了,几乎所有的平台上都支持,良好跨平台支持也是它的一个优点。然而,它的缺点也不可忽视:
监听的 fd 数量存在最大限制,在 Linux 上这个最大值是 1024,这在 select 诞生的那个年代来说足够了,但对现在互联网信息爆炸时代来说,极大限制了 select 的可用性。
其次,一旦监听的 fd 上有事件产生,select 仅仅会返回,但并不会告诉我们是哪些 fd 产生了事件,这时需要自己遍历所有的 fdset,依次检查每个 fd 上的事件标志位。显然,遍历的这个过程时间复杂度是 O(n)。因此,即使把上面的最大监听数改大,但带来的问题是效率的降低。
poll

再来看 poll,它是 select 的改进版,主要改进点有:
去掉了 1024 这个最大监听数的限制。用户可以自定义监听 fd 数。
简化了 select 调用方式,它的原型如下:
1
int poll (struct pollfd *fds, unsigned int nfds, int timeout);
不同于 select 使用三个位图来表示三个 fdset 的方式,poll 使用一个 pollfd 的指针实现,pollfd 结构如下:

1
2
3
4
5
typedef struct pollfd {
int fd; // file descriptor
short events; // requested events to watch
short revents; // returned events witnessed
} pollfd_t;

pollfd 结构包含了要监听的 event 和发生的 event,不再使用 select “参数-值”传递的方式,使得 poll 支持的 fd 集合限制远大于 select 的 1024。但是,poll 并没有解决 select 最根本的问题:它依然需要遍历所有 fd 来检查事件,遍历的时间复杂度依然是 O(n)。
epoll

再来看看 epoll,epoll 和上面的 select 和 poll 有着本质的区别,除了没有最大监听数限制外,它还有一个最大特点:只返回有事件发生的 fd,所以不需要遍历所有监听的 fd 来找到哪些 fd 产生了事件。因此,它的时间复杂度为 O(k),其中 k 为产生事件的 fd 数。因此,epoll 的效率不会像 select 和 poll 那样,随着监听 fd 的数量的增长而下降,那么它是怎么做的呢?来看下使用 epoll 时需要的三个系统调用:

1
2
3
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);

epoll_create:创建一个 epoll 的句柄,size 用来告诉内核这个监听的数目一共有多大,这个参数不同于 select 中的第一个参数,给出最大监听的 fd+1 的值,参数 size 并不是限制了 epoll 所能监听的描述符最大个数,只是对内核初始分配内部数据结构的一个建议。
epoll_ctl:对指定 fd 执行 op 操作,epfd 是 epoll_create 的返回值。op 表示操作,用三个宏来表示:添加 EPOLL_CTL_ADD,删除 EPOLL_CTL_DEL,修改 EPOLL_CTL_MOD。分别添加、删除和修改对 fd 的监听事件,epoll_event 告诉内核需要监听什么事。
epoll_wait:等待 epfd 上的 io 事件,最多返回 maxevents 个事件。
上面对函数的解释可能比较抽象,简单来讲:当我们调用 epoll_create 时,内核就创建了一棵红黑树和一个就绪(Ready)链表,其中,红黑数用于存储后面 epoll_ctl 传过来的 fd,以支持高效的查找、插入和删除。就绪链表用于存储准备就绪的事件,当 epoll_wait 调用时,仅仅观察这个就绪链表里有没有数据即可。有数据就返回,没有数据就 sleep,等到 timeout 时间到后即使链表没数据也返回。使用 epoll 的方式大概长这样:

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

#define MAX_EVENTS 10;
int event_count;
// 这里是创建网络程序的一般步骤
// ... socket(), bind(), listen()

// 创建epoll文件描述符,出错返回 -1
// int epoll_create(int size) 从Linux2.6.8开始,size 值被忽略,不过为保持兼容需要设定为一个正整数
int epollfd = epoll_create(1024);
struct epoll_event ev, events_in[MAX_EVENTS]; // 记录套接字相关信息
ev.events = EPOLLIN; // 监视有数据可读事件
ev.data.fd = fd; // 文件描述符数据,其实这里可以放任何数据。

// 加入监听列表,当fd上有对应事件产生时,epoll_wait会将epoll_event填充到events_in数组里
// 出错返回 -1
epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);

while(1) {
// 等待事件,epoll_wait 会将事件填充至 events_in 内
// 返回获得的事件数量,若超时且没有任何事件返回0,出错返回 -1。timeout 设置为 -1 表示无限等待。
int event_count = epoll_wait(epollfd, events_in, MAX_EVENTS, -1);
for (int i = 0; i<event_count; i++) { // 遍历所有事件
if (events_in[i].data.fd == fd) { // 新连接请求
int new_fd = accept(fd, NULL, NULL);
ev.events = EPOLLIN;
setnonblocking(new_fd); // 如果要使用Edge Trigger还需将 new_fd 设为非阻塞
ev.data.fd = new_fd;
epoll_ctl(epollfd, EPOLL_CTL_ADD, new_fd, &ev); // 将新连接加入监视列表
} else { // 其他的事件处理,如读写事件
int new_fd = events_in[i].data.fd;
// ... handle(new_fd);
epoll_ctl(epollfd, EPOLL_CTL_DEL, new_fd, NULL); // 不再监听fd,最后一个参数被忽略
close(new_fd);
}
}
}

epoll 有两种工作模式:LT(level trigger)模式和 ET(edge trigger)模式,也叫水平触发和边沿触发,默认的是 LT 模式
LT 模式:当 epoll_wait 检测到 fd 事件发生并将此事件通知应用程序,应用程序可以不立即处理该事件。下次调用 epoll_wait 时,会再次响应应用程序并通知此事件。
ET 模式:当 epoll_wait 检测到 fd 事件发生,只有当 fd 事件变化时,即从 unreadable 变为 readable 或从 unwritable 变为 writable 时,它才返回事件 fd,因此应用程序必须立即处理该事件。如果不处理,下次调用 epoll_wait 时,不会再次响应应用程序并通知此 fd 事件。
一句话:如果 fd 上有事件发生,LT 模式下会一直通知你,ET 模式只会通知一次。
因此,如果 epoll 工作在 ET 模式,正确的读写方式应该如下所述,具体描述可以参考这篇文章,这里只说结论:
读:只要可读,就一直读,直到返回 0,或者 errno = EAGAIN
写:只要可写,就一直写,直到数据发送完,或者 errno = EAGAIN
ET 模式也称为高速模式,在很大程度上减少了 epoll 事件被重复触发的次数,因此效率要比 LT 模式高。epoll 工作在 ET 模式的时候,必须使用非阻塞套接字模式,以避免由于一个 fd 的阻塞读/阻塞写操作把处理多个 fd 的任务饿死,如上面代码的第 25 行:

1
setnonblocking(new_fd);

epoll 的上述特点,使 I/O 多路复用系统的性能提升到一个新的台阶。当管理的连接数不多时,使用 select/poll 和使用 epoll 的差别不大,但是当连接数上十万百万时,就会发现 epoll 的效率远高于 select/poll。因为在互联网大量并发的连接场景下,实际同一时刻,真正活跃(Active)的连接,其实只占少数,其他的都是空闲(idle)状态。epoll 不遍历所有连接,只对活跃的连接做处理。
需要注意的是:epoll 是 Linux 2.6 内核版本引入,只用于 Linux 平台,BSD 或 MacOS 对应的实现就是 kqueue,Windows 下就是 IOCP。
怎么使用

实际上,当我们使用 I/O 多路复用时,也很少会直接调用 select/poll/epoll,这样开发周期长,对开发者有较高要求,出问题难以调试,直接使用现有的库会大大降低开发难度,如 libevent,netty 等,他们对于不同的平台底层使用不同的方式,比如你是 MacOS,底层就用 kqueue,如果是 Linux 2.6或更新,则用 epoll。这些库提供了一套统一的 API,好处是允许你的代码在不同平台上运行而不需要改变任何代码,用户只需直接使用即可。
I/O 多路复用的问题

细心的同学会发现,I/O 多路复用是单线程的,不能充分利用多核;同时,单线程模型事件处理中,不能有阻塞,一旦发生阻塞,会大大降低该模型性能,甚至不如多线程模型的 BIO ,这就对开发者的技术有更高的要求了。
另一方面,基于事件驱动的 I/O 多路复用,仍然属于阻塞型 I/O,它会阻塞在等待事件发生的系统调用。
I/O 多路复用案例

I/O 多路复用技术,已经在很多高性能软件和系统中得到广泛使用,只要弄明白了 I/O 多路复用的底层原理,也就明白那些优秀的软件为何性能很高了。经典的如 Redis,我们知道 Redis 是一个高性能的缓存服务器,它是单线程的,但它的性能并没有因为单线程而降低,反而特别高效,其中一个很重要的原因就是使用的 I/O 多路复用。在 Redis 内部,将客户端的套接字以文件事件进行抽象,客户端的连接,读写等操作,均会在 Redis 产生相应的文件事件,然后由相应的事件处理器进行处理,而 Redis 的单线程,可以监听成千上万个套接字,从而保证了高效的网络通信。同时,Redis 有良好的跨平台特性,由此我们可以断定,Redis 底层并没有写死使用 epoll 方式,因为那样会限制它只能运行于 Linux 平台,实际上,在我们编译 Redis 时,Redis 会根据平台情况,选择使用最合适的方式。
再如 Nginx,Nginx 是一款优秀的,抗并发能力很强的 web 服务器,在它的 Worker 进程中,也是通过 kqueue、epoll 等事件通知机制循环处理连接请求,可以使 Nginx 在高并发的情况下,仍然保持较低的 CPU 使用率,同时它也有良好的跨平台特性。nginx 的架构模型可以参考这篇文章
再如 Netty,Netty 是 Java 写的高性能网络编程框架,它是 Java NIO 库的进一步封装,大大简化了 NIO 的使用方式,Netty 的网络部分使用了经典的 Reactor 模式,其中的 IO 线程 NioEventLoop 聚合了多路复用器,称为 Selector,根据平台选择不同的 I/O 多路复用,如 kqueue、epoll。同时,它可以搭配线程池使用,每个线程都是一个 Selector,成为多线程的 Reactor 模型。因此它的性能也非常强劲。Netty 的线程模型可以看这篇文章

总结

上面,我们讨论了传统的 BIO 模式的弊端,以及 I/O 多路复用的原理和经典使用案例,那么我们以后写网络程序,是不是无脑用 I/O 多路复用呢?得看场景:
如果你的应用并发量不大,用户的请求连接少,连接不是瓶颈,那么请直接使用 BIO+多线程方式,简单易调试,完全用不着 I/O 多路复用,这样只会增加代码的复杂度,出问题难以调试。
如果你的应用并发量高,需要同时处理海量的连接,那么请使用 I/O 多路复用方式。但是记住,你必须始终保持异步思想,事件处理中不要有任何阻塞操作。至于是用 select/poll 还是 epoll,请看这篇文章

1
2
3
4
5
6
7
参考
https://segmentfault.com/a/1190000003063859
https://eklitzke.org/blocking-io-nonblocking-io-and-epoll
https://people.eecs.berkeley.edu/~sangjin/2012/12/21/epoll-vs-kqueue.html
https://www.zhihu.com/question/20122137
http://kimi.it/515.html
https://segmentfault.com/a/1190000016875057

本文由 JimmyXu 发表,采用署名-非商业性使用-禁止演绎4.0进行许可
非商业转载请注明作者及出处,商业转载请联系作者本人
本文标题: 什么是 I/O 多路复用
本文链接: http://xujimmy.com/2019/06/27/what-is-io-multiplexing.html

Linux环境部署Elasticsearch 6.x和常见问题

Posted on 2018-01-21 | In ES , Elasticsearch

介绍

Elasticsearch(ES)是一个基于Lucene构建的开源、分布式、RESTful接口的全文搜索引擎。 Elasticsearch还是一个分布式文档数据库,其中每个字段均可被索引,而且每个字段的数据均可被搜索,ES能够横向扩展至数以百计的服务器存储以及处理PB级的数据。

本文内容基于Elastic 技术栈6.x版本;

准备工作

1
2
3
4
5
6
# lasticsearch-6-3-2

wget https://www.elastic.co/cn/downloads/past-releases/elasticsearch-6-3-2

# or
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.3.2.tar.gz

下载到指定目录~/path/,解压

1
tar -zxvf elasticsearch-6.3.2.tar.gz

由于elasticsearch 不允许使用root用户启动
创建一个用于启动elasticsearch 的用户

1
2
useradd  elastic 
passwd elastic

输入密码,并确认,完成特定用户创建

并为该用户授权elasticsearch相关目录

1
chown -R elastic:elastic elasticsearch*

切换到用户elastic ,创建elasticsearch目录软连接指向elastic用户的根目录

1
2
cd ~
ln -s /path/to/elasticsearch ./elasticsearch

进入该目录

1
cd ./elasticsearch

执行

1
./bin/elasticsearch

启动elasticsearch

后台启动 (daemonize)

1
./bin/elasticsearch  -d

常见问题

启动错误提示1:

1
2
3
4
5
6
7
8
9
10
11

ERROR: [4] bootstrap checks failed
[1]: max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]
[2]: max number of threads [1024] for user [elastic] is too low, increase to at least [4096]
[3]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
[4]: system call filters failed to install; check the logs and fix your configuration or disable system call filters at your own risk


[1]: max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]

Make sure to increase the limit on the number of open files descriptors for the user running Elasticsearch to 65,536 or higher. For the .zip and .tar.gz packages, set ulimit -n 65536 as root before starting Elasticsearch, or set nofile to 65536 in /etc/security/limits.conf .

解决:切换到root用户,编辑limits.conf 添加相关配置

1
vi /etc/security/limits.conf

添加如下内容:

1
2
3
4
* soft nofile 65536
* hard nofile 131072
* soft nproc 2048
* hard nproc 4096

启动错误提示2:

1
[2]: max number of threads [1024] for user [elastic] is too low, increase to at least [4096]

对于第二条错误同意需要切换到root用户,进入limits.d目录下修改配置文件。

1
vi /etc/security/limits.d/90-nproc.conf

修改如下内容:

1
* soft nproc 1024

#修改为

1
* soft nproc 4096

错误提示3

1
[3]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

第三条错误需要切换到root用户修改配置sysctl.conf
vi /etc/sysctl.conf

添加下面配置:

1
vm.max_map_count=655360

并执行命令:

1
sysctl -p

错误提示4:

1
[4]: system call filters failed to install; check the logs and fix your configuration or disable system call filters at your own risk

原因:
这是在因为Centos6不支持SecComp,而ES 6.x默认bootstrap.system_call_filter为true进行检测,所以导致检测失败,失败后直接导致ES不能启动。

解决:
在elasticsearch.yml中配置bootstrap.system_call_filter为false,注意要在Memory下面:

1
2
bootstrap.memory_lock: false
bootstrap.system_call_filter: false

操作完成,现在所有的机器都能访问Linux服务器的HTTP服务了。

监控健康状况
http://[es_host]:9200/_cat/health?v
监控节点情况
http://[es_host]:9200/_cat/nodes?v
监控索引情况
http://[es_host]:9200/_cat/indices?v

Spring Cloud 学习资料汇总

Posted on 2017-01-20 | In Java , Spring Cloud

Spring Cloud是一系列框架的有序集合。 它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。

网站

Spring Cloud 官网
Spring Cloud 中国社区
Spring Cloud 中文网
网易云课堂 Spring Cloud 视频
Spring Cloud 参考指南- 英文版
Nepxion

推荐博客

纯洁的微笑 Spring Cloud 系列文章
程序猿DD Spring Cloud 从入门到精通
windmt一spring cloud
方志朋 Spring Cloud 专栏
许进 跟我学 Spring Cloud
liaokailin的专栏 Spring Cloud
猿天地尹吉欢 Spring Cloud
唐亚峰 Battcn 起来学SpringCloud
yjclsx spring cloud之路
aoho spring cloud
江南一点雨 Spring Cloud

开源

纯洁的微笑的 Spring Cloud 示例
spring cloud + vue 全家桶实战,模拟商城,完整的购物流程
PiggyMetrics-一个供个人处理财务的解决方案
基于Spring Cloud Netflix的TCC柔性事务和EDA事件驱动示例
方志朋 SpringCloudLearning
一套基于springcloud + mybatis + vue全家桶
cloudE 基于spring cloud的分布式系统架构
shop spring cloud最佳实践项目实例
Cloud-Admin是国内首个基于Spring Cloud微服务化开发平台
spring-boot-cloud综合练手项目
基于Spring Cloud的在线考试系统
基于SpringCloud的微服务架构实战案例项目,以一个简单的购物流程为示例
XxPay 使用Spring Cloud实现的聚合支付
FCat项目基于 Angular 4 + Spring Cloud 的企业级基础功能框架
基于Spring Cloud、oAuth2.0开发基于Vue前后分离的开发平台

其它

Spring Boot 中文索引
程序员导航网站
IT行业中文资源大全

Redis系列之应用范围

Posted on 2016-05-01 | In NoSQL , Redis

Redis 是互联网技术领域使用最为广泛的存储中间件,它是「Remote Dictionary Service」的首字母缩写,也就是「远程字典服务」。Redis 以其超高的性能、完美的文档、简洁易懂的源码和丰富的客户端库支持在开源中间件领域广受好评。

例如:
1.记录帖子的点赞数、评论数和点击数 (hash)。
2.记录用户的帖子 ID 列表 (排序),便于快速显示用户的帖子列表 (zset)。
3.记录帖子的标题、摘要、作者和封面信息,用于列表页展示 (hash)。
4.记录帖子的点赞用户 ID 列表,评论 ID 列表,用于显示和去重计数 (zset)。
5.缓存近期热帖内容 (帖子内容空间占用比较大),减少数据库压力 (hash)。
6.记录帖子的相关文章 ID,根据内容推荐相关帖子 (list)。
7.如果帖子 ID 是整数自增的,可以使用 Redis 来分配帖子 ID(计数器)。
8.收藏集和帖子之间的关系 (zset)。
9.记录热榜帖子 ID 列表,总热榜和分类热榜 (zset)。
10.缓存用户行为历史,进行恶意行为过滤 (zset,hash)。

当然,实际情况下需求可能也没这么多,因为在请求压力不大的情况下,很多数据都是可以直接从数据库中查询的。但请求压力一大,以前通过数据库直接存取的数据则必须要挪到缓存里来。

Spring Boot(三):Spring Boot 中 Redis 的使用

Posted on 2016-03-06 | In Java , Spring Boot

Spring Boot 对常用的数据库支持外,对 Nosql 数据库也进行了封装自动化。

Redis 介绍

Redis 是目前业界使用最广泛的内存数据存储。相比 Memcached,Redis 支持更丰富的数据结构,例如 hashes, lists, sets 等,同时支持数据持久化。除此之外,Redis 还提供一些类数据库的特性,比如事务,HA,主从库。可以说 Redis 兼具了缓存系统和数据库的一些特性,因此有着丰富的应用场景。本文介绍 Redis 在 Spring Boot 中两个典型的应用场景。

如何使用

1、引入依赖包

1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>

Spring Boot 提供了对 Redis 集成的组件包:spring-boot-starter-data-redis,spring-boot-starter-data-redis依赖于spring-data-redis 和 lettuce 。Spring Boot 1.0 默认使用的是 Jedis 客户端,2.0 替换成 Lettuce,但如果你从 Spring Boot 1.5.X 切换过来,几乎感受不大差异,这是因为 spring-boot-starter-data-redis 为我们隔离了其中的差异性。

Lettuce 是一个可伸缩线程安全的 Redis 客户端,多个线程可以共享同一个 RedisConnection,它利用优秀 netty NIO 框架来高效地管理多个连接。

2、添加配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制) 默认 8
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
spring.redis.lettuce.pool.max-wait=-1
# 连接池中的最大空闲连接 默认 8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认 0
spring.redis.lettuce.pool.min-idle=0

#### 3、添加 cache 的配置类

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{

@Bean
public KeyGenerator keyGenerator() {
    return new KeyGenerator() {
        @Override
        public Object generate(Object target, Method method, Object... params) {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName());
            sb.append(method.getName());
            for (Object obj : params) {
                sb.append(obj.toString());
            }
            return sb.toString();
        }
    };
}

}

1
2
3
4

注意我们使用了注解:@EnableCaching来开启缓存。

好了,接下来就可以直接使用了

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestRedis {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private RedisTemplate redisTemplate;

@Test
public void test() throws Exception {
    stringRedisTemplate.opsForValue().set("aaa", "111");
    Assert.assertEquals("111", stringRedisTemplate.opsForValue().get("aaa"));
}

@Test
public void testObj() throws Exception {
    User user=new User("aa@126.com", "aa", "aa123456", "aa","123");
    ValueOperations<String, User> operations=redisTemplate.opsForValue();
    operations.set("com.neox", user);
    operations.set("com.neo.f", user,1, TimeUnit.SECONDS);
    Thread.sleep(1000);
    //redisTemplate.delete("com.neo.f");
    boolean exists=redisTemplate.hasKey("com.neo.f");
    if(exists){
        System.out.println("exists is true");
    }else{
        System.out.println("exists is false");
    }
   // Assert.assertEquals("aa", operations.get("com.neo.f").getUserName());
}

}

1
2
3
4

以上都是手动使用的方式,如何在查找数据库的时候自动使用缓存呢,看下面;

#### 4、自动根据方法生成缓存

@RestController
public class UserController {

@RequestMapping("/getUser")
@Cacheable(value="user-key")
public User getUser() {
    User user=new User("aa@126.com", "aa", "aa123456", "aa","123");
    System.out.println("若下面没出现“无缓存的时候调用”字样且能打印出数据表示测试成功");
    return user;
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13

其中 value 的值就是缓存到 Redis 中的 key

### 共享 Session
分布式系统中,Session 共享有很多的解决方案,其中托管到缓存中应该是最常用的方案之一,

#### Spring Session 官方说明
Spring Session provides an API and implementations for managing a user’s session information.

Spring Session 提供了一套创建和管理 Servlet HttpSession 的方案。Spring Session 提供了集群 Session(Clustered Sessions)功能,默认采用外置的 Redis 来存储 Session 数据,以此来解决 Session 共享的问题。

#### 如何使用
1、引入依赖


org.springframework.session
spring-session-data-redis

1
2

2、Session 配置:

@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400*30)
public class SessionConfig {
}

1
2
3
4
5
6
7
8

maxInactiveIntervalInSeconds: 设置 Session 失效时间,使用 Redis Session 之后,原 Spring Boot 的 server.session.timeout 属性不再生效。

好了,这样就配置好了,我们来测试一下

3、测试

添加测试方法获取 sessionid

@RequestMapping(“/uid”)
String uid(HttpSession session) {
UUID uid = (UUID) session.getAttribute(“uid”);
if (uid == null) {
uid = UUID.randomUUID();
}
session.setAttribute(“uid”, uid);
return session.getId();
}

1
登录 Redis 输入 keys '*sessions*'

t<spring:session:sessions:db031986-8ecc-48d6-b471-b137a3ed6bc4
t(spring:session:expirations:1472976480000
`

其中 1472976480000 为失效时间,意思是这个时间后 Session 失效,db031986-8ecc-48d6-b471-b137a3ed6bc4 为 sessionId,登录 http://localhost:8080/uid 发现会一致,就说明 Session 已经在 Redis 里面进行有效的管理了。

如何在两台或者多台中共享 Session

其实就是按照上面的步骤在另一个项目中再次配置一次,启动后自动就进行了 Session 共享。

示例代码-github

示例代码-码云

文章内容已经升级到 Spring Boot 2.x

参考
Redis的两个典型应用场景
SpringBoot应用之分布式会话

原文地址

(转载本站文章请注明作者和出处 纯洁的微笑-ityouknow)

Spring Boot(二):Web 综合开发

Posted on 2016-02-03 | In Java , Spring Boot

Web 开发

Spring Boot Web 开发非常的简单,其中包括常用的 json 输出、filters、property、log 等

json 接口开发

在以前使用 Spring 开发项目,需要提供 json 接口时需要做哪些配置呢

  1. 添加 jackjson 等相关 jar 包
  2. 配置 Spring Controller 扫描
  3. 对接的方法添加 @ResponseBody

就这样我们会经常由于配置错误,导致406错误等等,Spring Boot 如何做呢,只需要类添加 @RestController 即可,默认类中的方法都会以 json 的格式返回

1
2
3
4
5
6
7
8
9
10
@RestController
public class HelloController {
@RequestMapping("/getUser")
public User getUser() {
User user=new User();
user.setUserName("小明");
user.setPassWord("xxxx");
return user;
}
}

如果需要使用页面开发只要使用@Controller注解即可,下面会结合模板来说明

自定义 Filter

我们常常在项目中会使用 filters 用于录调用日志、排除有 XSS 威胁的字符、执行权限验证等等。Spring Boot 自动添加了 OrderedCharacterEncodingFilter 和 HiddenHttpMethodFilter,并且我们可以自定义 Filter。

两个步骤:

  1. 实现 Filter 接口,实现 Filter 方法
  2. 添加@Configuration 注解,将自定义Filter加入过滤链

好吧,直接上代码

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
@Configuration
public class WebConfiguration {
@Bean
public RemoteIpFilter remoteIpFilter() {
return new RemoteIpFilter();
}

@Bean
public FilterRegistrationBean testFilterRegistration() {

FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MyFilter());
registration.addUrlPatterns("/*");
registration.addInitParameter("paramName", "paramValue");
registration.setName("MyFilter");
registration.setOrder(1);
return registration;
}

public class MyFilter implements Filter {
@Override
public void destroy() {
// TODO Auto-generated method stub
}

@Override
public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain filterChain)
throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest request = (HttpServletRequest) srequest;
System.out.println("this is MyFilter,url :"+request.getRequestURI());
filterChain.doFilter(srequest, sresponse);
}

@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
}
自定义 Property

在 Web 开发的过程中,我经常需要自定义一些配置文件,如何使用呢

配置在 application.properties 中

1
2
com.neo.title=风中追风
com.neo.description=编程、算法

自定义配置类

1
2
3
4
5
6
7
8
9
10
@Component
public class NeoProperties {
@Value("${com.neo.title}")
private String title;
@Value("${com.neo.description}")
private String description;

//省略getter settet方法

}

log配置
配置输出的地址和输出级别

1
2
3
4
logging.path=/user/local/log
logging.level.com.favorites=DEBUG
logging.level.org.springframework.web=INFO
logging.level.org.hibernate=ERROR

path 为本机的 log 地址,logging.level 后面可以根据包路径配置不同资源的 log 级别

数据库操作

在这里我重点讲述 Mysql、spring data jpa 的使用,其中 Mysql 就不用说了大家很熟悉。Jpa 是利用 Hibernate 生成各种自动化的 sql,如果只是简单的增删改查,基本上不用手写了,Spring 内部已经帮大家封装实现了。

下面简单介绍一下如何在 Spring Boot 中使用

1、添加相 jar 包
1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
2、添加配置文件
1
2
3
4
5
6
7
8
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql= true

其实这个 hibernate.hbm2ddl.auto 参数的作用主要用于:自动创建 更新 验证数据库表结构,有四个值:

1
2
3
4
create: 每次加载 hibernate 时都会删除上一次的生成的表,然后根据你的 model 类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。
create-drop :每次加载 hibernate 时根据 model 类生成表,但是 sessionFactory 一关闭,表就自动删除。
update:最常用的属性,第一次加载 hibernate 时根据 model 类会自动建立起表的结构(前提是先建立好数据库),以后加载 hibernate 时根据 model 类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等 应用第一次运行起来后才会。
validate :每次加载 hibernate 时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。

dialect 主要是指定生成表名的存储引擎为 InnoDBD
show-sql 是否打印出自动生成的 SQL,方便调试的时候查看

3、添加实体类和 Dao
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Entity
public class User implements Serializable {

private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
private Long id;
@Column(nullable = false, unique = true)
private String userName;
@Column(nullable = false)
private String passWord;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = true, unique = true)
private String nickName;
@Column(nullable = false)
private String regTime;

//省略getter settet方法、构造方法

}

dao 只要继承 JpaRepository 类就可以,几乎可以不用写方法,还有一个特别有尿性的功能非常赞,就是可以根据方法名来自动的生成 SQL,比如findByUserName 会自动生成一个以 userName 为参数的查询方法,比如 findAlll 自动会查询表里面的所有数据,比如自动分页等等。。

Entity 中不映射成列的字段得加 @Transient 注解,不加注解也会映射成列

1
2
3
4
public interface UserRepository extends JpaRepository<User, Long> {
User findByUserName(String userName);
User findByUserNameOrEmail(String username, String email);
}
4、测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class UserRepositoryTests {

@Autowired
private UserRepository userRepository;

@Test
public void test() throws Exception {
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
String formattedDate = dateFormat.format(date);

userRepository.save(new User("aa1", "aa@126.com", "aa", "aa123456",formattedDate));
userRepository.save(new User("bb2", "bb@126.com", "bb", "bb123456",formattedDate));
userRepository.save(new User("cc3", "cc@126.com", "cc", "cc123456",formattedDate));

Assert.assertEquals(9, userRepository.findAll().size());
Assert.assertEquals("bb", userRepository.findByUserNameOrEmail("bb", "cc@126.com").getNickName());
userRepository.delete(userRepository.findByUserName("aa1"));
}

}

当让 Spring Data Jpa 还有很多功能,比如封装好的分页,可以自己定义 SQL,主从分离等等,这里就不详细讲了

Thymeleaf 模板

Spring Boot 推荐使用 Thymeleaf 来代替 Jsp,Thymeleaf 模板到底是什么来头呢,让 Spring 大哥来推荐,下面我们来聊聊

Thymeleaf 介绍

Thymeleaf 是一款用于渲染 XML/XHTML/HTML5 内容的模板引擎。类似 JSP,Velocity,FreeMaker 等,它也可以轻易的与 Spring MVC 等 Web 框架进行集成作为 Web 应用的模板引擎。与其它模板引擎相比,Thymeleaf 最大的特点是能够直接在浏览器中打开并正确显示模板页面,而不需要启动整个 Web 应用。

好了,你们说了我们已经习惯使用了什么 Velocity,FreMaker,beetle之类的模版,那么到底好在哪里呢?

比一比吧

Thymeleaf 是与众不同的,因为它使用了自然的模板技术。这意味着 Thymeleaf 的模板语法并不会破坏文档的结构,模板依旧是有效的XML文档。模板还可以用作工作原型,Thymeleaf 会在运行期替换掉静态值。Velocity 与 FreeMarke r则是连续的文本处理器。 下面的代码示例分别使用 Velocity、FreeMarker 与 Thymeleaf 打印出一条消息:

1
2
3
Velocity: <p>$message</p>
FreeMarker: <p>${message}</p>
Thymeleaf: <p th:text="${message}">Hello World!</p>

注意,由于 Thymeleaf 使用了 XML DOM 解析器,因此它并不适合于处理大规模的 XML 文件。

URL

URL 在 Web 应用模板中占据着十分重要的地位,需要特别注意的是 Thymeleaf 对于 URL 的处理是通过语法 @{…} 来处理的。Thymeleaf 支持绝对路径 URL:

1
<a th:href="@{http://www.thymeleaf.org}">Thymeleaf</a>

条件求值

1
<a th:href="@{/login}" th:unless=${session.user != null}>Login</a>

for循环

1
2
3
4
5
<tr th:each="prod : ${prods}">
<td th:text="${prod.name}">Onions</td>
<td th:text="${prod.price}">2.41</td>
<td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>

就列出这几个吧

页面即原型

在 Web 开发过程中一个绕不开的话题就是前端工程师与后端工程师的协作,在传统 Java Web 开发过程中,前端工程师和后端工程师一样,也需要安装一套完整的开发环境,然后各类 Java IDE 中修改模板、静态资源文件,启动/重启/重新加载应用服务器,刷新页面查看最终效果。

但实际上前端工程师的职责更多应该关注于页面本身而非后端,使用 JSP,Velocity 等传统的 Java 模板引擎很难做到这一点,因为它们必须在应用服务器中渲染完成后才能在浏览器中看到结果,而 Thymeleaf 从根本上颠覆了这一过程,通过属性进行模板渲染不会引入任何新的浏览器不能识别的标签,例如 JSP 中的 ,不会在 Tag 内部写表达式。整个页面直接作为 HTML 文件用浏览器打开,几乎就可以看到最终的效果,这大大解放了前端工程师的生产力,它们的最终交付物就是纯的 HTML/CSS/JavaScript 文件。

Gradle 构建工具

Spring 项目建议使用 Maven/Gradle 进行构建项目,相比 Maven 来讲 Gradle 更简洁,而且 Gradle 更适合大型复杂项目的构建。Gradle 吸收了 Maven 和 Ant 的特点而来,不过目前 Maven 仍然是 Java 界的主流,大家可以先了解了解。

一个使用 Gradle 配置的项目

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
buildscript {
repositories {
maven { url "http://repo.spring.io/libs-snapshot" }
mavenLocal()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.6.RELEASE")
}
}

apply plugin: 'java' //添加 Java 插件, 表明这是一个 Java 项目
apply plugin: 'spring-boot' //添加 Spring-boot支持
apply plugin: 'war' //添加 War 插件, 可以导出 War 包
apply plugin: 'eclipse' //添加 Eclipse 插件, 添加 Eclipse IDE 支持, Intellij Idea 为 "idea"

war {
baseName = 'favorites'
version = '0.1.0'
}

sourceCompatibility = 1.7 //最低兼容版本 JDK1.7
targetCompatibility = 1.7 //目标兼容版本 JDK1.7

repositories { // Maven 仓库
mavenLocal() //使用本地仓库
mavenCentral() //使用中央仓库
maven { url "http://repo.spring.io/libs-snapshot" } //使用远程仓库
}

dependencies { // 各种 依赖的jar包
compile("org.springframework.boot:spring-boot-starter-web:1.3.6.RELEASE")
compile("org.springframework.boot:spring-boot-starter-thymeleaf:1.3.6.RELEASE")
compile("org.springframework.boot:spring-boot-starter-data-jpa:1.3.6.RELEASE")
compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.6'
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.4'
compile("org.springframework.boot:spring-boot-devtools:1.3.6.RELEASE")
compile("org.springframework.boot:spring-boot-starter-test:1.3.6.RELEASE")
compile 'org.webjars.bower:bootstrap:3.3.6'
compile 'org.webjars.bower:jquery:2.2.4'
compile("org.webjars:vue:1.0.24")
compile 'org.webjars.bower:vue-resource:0.7.0'

}

bootRun {
addResources = true
}

WebJars

WebJars 是一个很神奇的东西,可以让大家以 Jar 包的形式来使用前端的各种框架、组件。

什么是 WebJars

WebJars 是将客户端(浏览器)资源(JavaScript,Css等)打成 Jar 包文件,以对资源进行统一依赖管理。WebJars 的 Jar 包部署在 Maven 中央仓库上。

为什么使用

我们在开发 Java web 项目的时候会使用像 Maven,Gradle 等构建工具以实现对 Jar 包版本依赖管理,以及项目的自动化管理,但是对于 JavaScript,Css 等前端资源包,我们只能采用拷贝到 webapp 下的方式,这样做就无法对这些资源进行依赖管理。那么 WebJars 就提供给我们这些前端资源的 Jar 包形势,我们就可以进行依赖管理。

如何使用

1、 WebJars主官网 查找对于的组件,比如 Vuejs

1
2
3
4
5
<dependency>
<groupId>org.webjars</groupId>
<artifactId>vue</artifactId>
<version>2.5.16</version>
</dependency>

2、页面引入

1
<link th:href="@{/webjars/bootstrap/3.3.6/dist/css/bootstrap.css}" rel="stylesheet"></link>

就可以正常使用了!

原文地址

(转载本站文章请注明作者和出处 纯洁的微笑-ityouknow)

Spring Boot(一):入门篇

Posted on 2016-01-06 | In Java , Spring Boot

简介

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot让我们的Spring应用变的更轻量化。可以仅仅依靠一个Java类来运行一个Spring引用。你也可以打包你的应用为jar并通过使用java -jar来运行你的Spring Web应用。

特点

· 创建独立的Spring应用程序
· 嵌入的Tomcat,无需部署WAR文件,内嵌式容器简化Web项目
· 简化Maven配置
· 自动配置Spring
· 提供生产就绪型功能,如指标,健康检查和外部配置
· 没有冗余代码生成和XML配置的要求
· 为所有Spring开发者更快的入门
· 开箱即用,提供各种默认配置来简化项目配置

基础项目结构介绍

Maven 构建项目

1、访问 http://start.spring.io/
2、选择构建工具 Maven Project、Java、Spring Boot 版本 2.1.3 以及一些工程基本信息,可参考下图所示:
3、点击 Generate Project 下载项目压缩包
4、解压后,使用 Idea 导入项目,File -> New -> Model from Existing Source.. -> 选择解压后的文件夹 -> OK,选择 Maven 一路 Next,OK done!
5、如果使用的是 Eclipse,Import -> Existing Maven Projects -> Next -> 选择解压后的文件夹 -> Finsh,OK done!

Idea 构建项目

1、选择 File -> New —> Project… 弹出新建项目的框
2、选择 Spring Initializr,Next 也会出现上述类似的配置界面,Idea 帮我们做了集成
3、填写相关内容后,点击 Next 选择依赖的包再点击 Next,最后确定信息无误点击 Finish。

Spring Boot的基础结构共三个文件:

~src/main/java 程序开发以及主程序入口
~src/main/resources 配置文件
~src/test/java 测试程序

Spingboot建议的目录结果如下:

root package 结构:com.example.myproject

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
com
+- example
+- myproject
+- Application.java
|
+- domain
| +- Customer.java
| +- CustomerRepository.java
|
+- service
| +- CustomerService.java
|
+- controller
| +- CustomerController.java
|

1、Application.java 建议放到跟目录下面,主要用于做一些框架配置
2、domain目录主要用于实体(Entity)与数据访问层(Repository)
3、service 层主要是业务类代码
4、controller 负责页面访问控制

采用默认配置可以省去很多配置,当然也可以根据自己的喜欢来进行更改
最后,启动Application main方法,至此一个java项目搭建好了!

引入 Web 模块

1、pom.xml中添加支持web的模块:

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

pom.xml文件中默认有两个模块:
spring-boot-starter:核心模块,包括自动配置支持、日志和YAML;
spring-boot-starter-test:测试模块,包括JUnit、Hamcrest、Mockito。

2、编写controller内容

1
2
3
4
5
6
7
@RestController
public class HelloWorldController {
@RequestMapping("/hello")
public String index() {
return "Hello World";
}
}

@RestController的意思就是controller里面的方法都以json格式输出,不用再写什么jackjson配置的了!

3、启动主程序,打开浏览器访问http://localhost:8080/hello,就可以看到效果了,有木有很简单!

如何做单元测试

打开的src/test/下的测试入口,编写简单的http请求来测试;使用mockmvc进行,利用MockMvcResultHandlers.print()打印出执行结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@RunWith(SpringRunner.class)
@SpringBootTest

public class HelloWorldControlerTests {
private MockMvc mvc;
@Before
public void setUp() throws Exception {
mvc = MockMvcBuilders.standaloneSetup(new HelloWorldController()).build();
}
@Test
public void getHello() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/hello").accept(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn();
}
}

开发环境的调试

热启动在正常开发项目中已经很常见了吧,虽然平时开发 web 项目过程中,改动项目启重启总是报错;但 Spring Boot 对调试支持很好,修改之后可以实时生效,需要添加以下的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>

该模块在完整的打包环境下运行的时候会被禁用。如果你使用java -jar启动应用或者用一个特定的classloader启动,它会认为这是一个“生产环境”。

总结

使用 Spring Boot 可以非常方便、快速搭建项目,使我们不用关心框架之间的兼容性,适用版本等各种问题,我们想使用任何东西,仅仅添加一个配置就可以,所以使用 Spring Boot 非常适合构建微服务。

原文地址

(转载本站文章请注明作者和出处 纯洁的微笑-ityouknow)

Spring Boot 学习资料汇总

Posted on 2016-01-01 | In Java , Spring Boot

网站

Spring boot 官网
Spring Boot 参考指南- 英文版

博客

纯洁的微笑-Spring Boot系列文章
林祥纤-从零开始学Spring Boot
Mkyong-Spring Boot教程(国外)
baeldung-Spring Boot教程(国外)
liaokailin的专栏-Spring Boot实战
catoop的专栏-Spring Boot 学习
方志朋-SpringBoot 非官方教程
嘟嘟-Spring-Boot干货系列
小柒-SpringBoot开发案例
江南一点雨-关于Spring Boot
天码营-Spring Boot
猿天地-Spring Boot

开源项目

纯洁的微笑 Spring Boot 示例
Spring Boot 官方示例
Spring Boot开源软件 云收藏
Docker+SpringBoot+Mybatis+thymeleaf等技术实现的Java博客系统
Spring boot & Shiro 权限管理系统
Spring Boot实现支付服务:支付宝,微信…
Spring Boot后台商城 h5 小程序
基于Spring Boot响应式文件浏览管理器
Spring Boot开源博客
邮件发送服务多种实现,队列,线程定时任务
Spring Boot视频展示项目
Spring Boot项目实践总结
Vue+SpringBoot实现的多用户博客管理平台
Vue+SpringBoot实现的人力资源管理系统
hsweb企业后台管理系统基础框架
一个基于spring boot 实现的股票指数💹爬虫
KKFileView-SpringBoot实现在线预览
boot-websocket-log-SpringBoot实现日志WEB输出
SpringBoot+MyBatis+ApacheShiro+Ehcahe基础平台
leelance Spring Boot各种示例
一个基于Spring Boot & MyBatis的种子项目,用于快速构建中小型API、RESTful API项目
JWT (Json Web Token) with Spring Security and Spring Boot 2
基于Spring-boot和bootstrap搭建的商城系统
Deployment scripts & config for Sock Shop
Spring Boot 开源博客-DBlog
Spring Boot 实现的简易社区
springboot+shiro+jwt 开源项目
Guns-基于SpringBoot的后台管理系统
halo-基于SpringBoot的博客系统
zhudyos/duic Distributed configuration center(分布式配置中心)
Spring Boot后端 + Vue管理员前端 + 微信小程序用户前端
mall-SpringBoot+MyBatis 电商系统
基于Spring Boot2.0微服务脚手架

12

风中追风

15 posts
10 categories
18 tags
© 2020 风中追风
Powered by Hexo
|
Theme — NexT.Muse v5.1.4