中小公司的Java工程师应该如何走出迷茫(转)

转自 在我万分的迷茫之中,看到了这个,我想,我将不再如此前那般迷茫。 目录 (1)80% Java工程师都有的迷茫 (2)你的技术为啥十年八年都无法进步? (3)追求卓越,自己设立技术挑战 (4)幻想一步登天?那只是你的黄粱美梦 (5)不断提升自己,最后进入BAT (6)最后的寄语 (1)80% Java工程师都有的迷茫 这篇文章,跟大家聊一聊很多很多很多人问我的一个问题:中小公司的Java工程师应该如何规划准备,才能跳槽进入BAT这类一线互联网公司? 之所以我用了三个 “很多” 来形容这个问题,是因为实在这个问题太普遍了,因为国内Java工程师至少好几十万,但是在国内互联网大厂里干过的码农可能也就十分之一,或者五分之一的比例。 所以,其实这个也是符合28法则的,少部分人在大厂里干过,发展的很好。但是大部分人还是在中小型公司,或者外包类传统IT公司里工作。 这些同学可能对自己的技术成长,职业发展感到非常的迷茫,自己有点追求,也想去一下大厂,但是又不知道怎么规划。 开始本文之前,同样强调一点:像这种讲职业规划发展的文章,有可能很多同学会以为是广告。但是这篇文章,笔者特意声明:纯干货、非广告。 因为我个人在国内几个最大的互联网公司先后有着十余年工作经历,面试和招聘过大量各种水平的开发人员。包括初、中、高级开发,技术专家,高级技术专家,都面过。 同样,也指导过很多同学的职业发展规划,看过大量的同学不顺利的职业发展,所以打算从我个人的角度来聊聊这个问题:中小公司的同学应该如何一步一步实现逆袭进入BAT。 我相信以下情形很多同学应该都有类似体会:一直徘徊在各种中小公司里开发一些没技术难度的Java系统,主要就是CRUD。 哪怕是用了用MQ、缓存、分库分表,但是也没什么并发量,数据量也不算特别大,自己的技术成长极为缓慢。 然后就是三五年,七八年,甚至十多年,职业发展和技术水平都停滞在这个状态,无法有更进一步的发展。 随着现在寒冬到来,到处裁员,中年码农的危机,加不动班,体力越来越差,孩子压力越来越大,对自己何去何从很迷茫。 有一些同学是一直徘徊在那种中小型互联网公司里碰到上述情况,有一些同学是在一些外包类的IT公司里碰到上述情况。 (2)你的技术为啥十年八年都无法进步? 先来搞清楚一个问题,你的技术到底为什么十年八年都无法进步? 拆解一下,你的能力集中在哪几块: 技术广度 对MQ、缓存、NoSQL、大数据、高并发、高可用、微服务,等一系列的相关技术都有一定的了解,熟悉常见功能 在自己的项目里落地使用过,有一定的技术使用经验 这可以解释为技术广度。 技术深度 读过Kafka的底层源码? 对消息中间件的架构设计思想有深刻的理解? 对分布式事务框架/中间件的架构设计有过研究? 在每秒百万并发场景下做过底层系统的深入优化和故障处理? 如果你有类似这种过人之处,那么你才能说你有某些技术深度。 项目经验 你有没有整体负责过几亿注册用户,几千万日活用户的大规模、高并发、分布式、高可用、高复杂度的系统架构设计? 或者你负责的一直都是那种公司内部使用的,几十个人用的OA系统,CRM系统? 这些就是你的项目经验 团队管理 你在互联网公司里带过20的团队? 或者你在一个传统IT公司里带过3个人的小组? 这都是你的团队管理经验。 拆解过后,再来看看,如果你在一些小型互联网公司,或者是做一些传统软件开发,为什么技术无法进步? 其实道理很简单,可能你的公司推出了一款APP,但是不好意思,用户量总共就100万,日活用户就10万人。 那你觉得你的系统有技术挑战吗?没有。 既然没有技术挑战,你把系统搞那么复杂干嘛?或者你的架构师搞那么复杂干嘛?不需要。 大家简单做一做,主要crud写一下功能,最多现在spring cloud流行了,上一下拆成微服务的就够了。 然后这套系统就稳定支撑你公司的业务了,那你接触不到很大的技术挑战,所以技术进入停滞状态,不是很正常么? 或者你做一些传统的软件开发,比如说建筑类软件,办公自动化软件,类似这种的。总共就几十个人用一个系统,或者几百人用,那你就更是如此了。 […]

JPMS- 模块API

转自 推荐去出处看,这个系列关于JPMS讲的还不错 一. 什么是模块API 模块API由可以让你对模块进行编程访问的类和接口组成。 使用API,可以通过编程方式: 读取,修改和构建模块描述符 加载模块 读取模块的内容 搜索加载的模块 创建新的模块层 模块API很小。 它由大约15个类和接口组成,分布在两个包中: java.lang java.lang.module Module,ModuleLayer和LayerInstantiationException类在java.lang包中,其余的在java.lang.module包中。 下表包含模块API中的类的列表,每个类的简要说明。 列表未排序。 首先列出了Module和ModuleDescriptor,因为应用程序开发人员最常使用它们。 所有其他类通常由容器和类库使用。 该列表不包含Module API中的异常类。 类 描述 Module 表示运行时模块。 ModuleDescriptor 表示模块描述。 这是不可变类。 ModuleDescriptor.Builder 用于以编程方式构建模块描述的嵌套构建器类。 ModuleDescriptor.Exports 表示模块声明中的exports语句的嵌套类。 ModuleDescriptor.Opens 表示模块声明中的opens语句的嵌套类。 ModuleDescriptor.Provides 表示模块声明中的provides语句的嵌套类。 ModuleDescriptor.Requires 表示模块声明中的requires语句的嵌套类。 ModuleDescriptor.Version 表示模块版本字符串的嵌套类。 它包含一个从版本字符串返回其实例的parse(String v)工厂方法。 ModuleDescriptor.Modifier 枚举类,其常量表示在模块声明中使用的修饰符,例如打开模块的OPEN。 ModuleDescriptor.Exports.Modifier 枚举类,其常量表示在模块声明中用于exports语句的修饰符。 ModuleDescriptor.Opens.Modifier 枚举类,其常量表示在模块声明中的opens语句上使用的修饰符。 ModuleDescriptor.Requires.Modifier 枚举类,其常量表示在模块声明中的requires语句上使用的修饰符。 ModuleReference 模块的内容的引用。 它包含模块的描述及其位置。 ResolvedModule […]

JVM性能调优

转自 JVM调优目标 JVM调优目标:使用较小的内存占用来获得较高的吞吐量或者较低的延迟。 程序在上线前的测试或运行中有时会出现一些大大小小的JVM问题,比如cpu load过高、请求延迟、tps降低等,甚至出现内存泄漏(每次垃圾收集使用的时间越来越长,垃圾收集频率越来越高,每次垃圾收集清理掉的垃圾数据越来越少)、内存溢出导致系统崩溃,因此需要对JVM进行调优,使得程序在正常运行的前提下,获得更高的用户体验和运行效率。 这里有几个比较重要的指标: 内存占用:程序正常运行需要的内存大小。 延迟:由于垃圾收集而引起的程序停顿时间。 吞吐量:用户程序运行时间占用户程序和垃圾收集占用总时间的比值。 当然,和CAP原则一样,同时满足一个程序内存占用小、延迟低、高吞吐量是不可能的,程序的目标不同,调优时所考虑的方向也不同,在调优之前,必须要结合实际场景,有明确的的优化目标,找到性能瓶颈,对瓶颈有针对性的优化,最后进行测试,通过各种监控工具确认调优后的结果是否符合目标。 JVM调优工具 调优相关依照 调优可以依赖、参考的数据有系统运行日志、堆栈错误信息、gc日志、线程快照、堆转储快照等。 ①系统运行日志:系统运行日志就是在程序代码中打印出的日志,描述了代码级别的系统运行轨迹(执行的方法、入参、返回值等),一般系统出现问题,系统运行日志是首先要查看的日志。 ②堆栈错误信息:当系统出现异常后,可以根据堆栈信息初步定位问题所在,比如根据“java.lang.OutOfMemoryError: Java heap space”可以判断是堆内存溢出;根据“java.lang.StackOverflowError”可以判断是栈溢出;根据“java.lang.OutOfMemoryError: PermGen space”可以判断是方法区溢出等。 ③GC日志:程序启动时用 -XX:+PrintGCDetails 和 -Xloggc:/data/jvm/gc.log 可以在程序运行时把gc的详细过程记录下来,或者直接配置“-verbose:gc”参数把gc日志打印到控制台,通过记录的gc日志可以分析每块内存区域gc的频率、时间等,从而发现问题,进行有针对性的优化。比如如下一段GC日志: 上面一共是4条GC日志,来看第一行日志,“2018-08-02T14:39:11.560-0800”是精确到了毫秒级别的UTC 通用标准时间格式,配置了“-XX:+PrintGCDateStamps”这个参数可以跟随gc日志打印出这种时间戳,“10.171”是从JVM启动到发生gc经过的秒数。第一行日志正文开头的“[GC”说明这次GC没有发生Stop-The-World(用户线程停顿),第二行日志正文开头的“[Full GC”说明这次GC发生了Stop-The-World,所以说,[GC和[Full GC跟新生代和老年代没关系,和垃圾收集器的类型有关系,如果直接调用System.gc(),将显示[Full GC(System)。接下来的“[PSYoungGen”、“[ParOldGen”表示GC发生的区域,具体显示什么名字也跟垃圾收集器有关,比如这里的“[PSYoungGen”表示Parallel Scavenge收集器,“[ParOldGen”表示Serial Old收集器,此外,Serial收集器显示“[DefNew”,ParNew收集器显示“[ParNew”等。再往后的“30128K->4091K(30208K)”表示进行了这次gc后,该区域的内存使用空间由30128K减小到4091K,总内存大小为30208K。每个区域gc描述后面的“51092K->50790K(98816K), 0.0140970 secs”进行了这次垃圾收集后,整个堆内存的内存使用空间由51092K减小到50790K,整个堆内存总空间为98816K,gc耗时0.0140970秒。 ④线程快照:顾名思义,根据线程快照可以看到线程在某一时刻的状态,当系统中可能存在请求超时、死循环、死锁等情况是,可以根据线程快照来进一步确定问题。通过执行虚拟机自带的“jstack pid”命令,可以dump出当前进程中线程的快照信息,更详细的使用和分析网上有很多例,这篇文章写到这里已经很长了就不过多叙述了,贴一篇博客供参考:http://www.cnblogs.com/kongzhongqijing/articles/3630264.html ⑤堆转储快照:程序启动时可以使用 “-XX:+HeapDumpOnOutOfMemory” 和 “-XX:HeapDumpPath=/data/jvm/dumpfile.hprof”,当程序发生内存溢出时,把当时的内存快照以文件形式进行转储(也可以直接用jmap命令转储程序运行时任意时刻的内存快照),事后对当时的内存使用情况进行分析。 JVM调优工具 ①用 jps(JVM process Status)可以查看虚拟机启动的所有进程、执行主类的全名、JVM启动参数,比如当执行了JPSTest类中的main方法后(main方法持续执行),执行jps -l可看到下面的JPSTest类的pid为31354,加上-v参数还可以看到JVM启动参数jps -l -v。 ②用jstat(JVM Statistics Monitoring Tool)监视虚拟机信息jstat -gc pid 500 […]

SpringBoot jar包启动的原理

转自 针对这个问题,之前一直不清楚,只知道jar可直接运行,war包要放到web容器中。 近期在做JPMS改造,当下在IDEA中已可以成功运行,但未找到jar部署的方式,以此为契机,正好把这个疑问解决一下。 感觉这篇文章还不错,就转了过来。因为当前站点主题对代码支持很不好,要结合源码来看。 Jar包结构 首先,先准备一个jar包,我这里准备了一个demo-0.0.1-SNAPSHOT.jar;先来看看jar包里面的目录结构: ├── BOOT-INF│   ├── classes│   │   ├── application.properties│   │   └── com│   │       └── sf│   │           └── demo│   │               └── DemoApplication.class│   └── lib│       ├── […]

lWoHvYe 无悔,专一