《远见》之读书笔记

《远见》之读书笔记

D瓜哥
最近向一个朋友了解一家公司情况时,聊到职业发展的问题。就随手推荐了《远见:如何规划职业生涯3大阶段》这本书。正好利用这个机会,把以前的读书摘要发布出来。 这本书,D瓜哥在 告别 2019,迎接 2020:《远见》 中也提到过。这里把当时写的读书笔记直接拷贝过来: 本书讲人生的职业生涯分为三个阶段: 第一阶段是强势开局的时候。你在职业上的努力必须着重于为前方的漫长道路挖掘和装备自己。你的学习曲线要比职位、职称更加重要。在这一阶段,要为职业生涯打好基础并建立起良好的早期习惯。 第二阶段是聚焦长板的时候。该阶段的首要目标是寻找自己的甜蜜区,即你所擅长的、所热爱的和这个世界所需要的这三者之间的交集。这个时候你要展现自我,让自己鹤立鸡群,想方设法平稳地走在那条收获最大的职场路径上。你要专注于自己的长板,且大可忽略自己的短板。 第三阶段致力于实现持续的影响力,以及寻找一条可以稳定延续到60多岁甚至70多岁的新的可持续职业道路。你要在第三阶段完成三个关键任务:完成继任计划、保持关联性,以及为自己点燃一团新的职业之火。 用一句话来总结:第一阶段:加添燃料,强势开局; 第二阶段:聚焦长板,达到高点; 第三阶段:优化长尾,持续发挥影响力。 三大职场燃料来源:可迁移技能、有意义的经验和持久的关系。 5个数字,树立正确的职场思维 职业生涯的长度:用62减去你目前的年龄。 精通一项技能所需的时间:要花多少小时才能在某一方面达到“精通”? 40岁之后能赚到的个人财富百分比:在40岁之后,你赚到的钱会占你一生个人财富的百分之多少?大部分人的估计是60%。 社交货币:你有多少社交网络好友? 职场支持者的人数:你认为能在“职业生涯的天堂”里遇到多少人,也就是说有多少人能对你的职业生涯和人生带来真正的变化? 这本书强烈推荐给对未来职业有追求的小伙伴! 好戏开始,下面👇是读书摘要: PART 1 远见思维与工具箱 远见思维:多行动,少忧虑 职业生涯的持续时间长得惊人,包括了三个截然不同的阶段。 第一阶段是强势开局的时候。你在职业上的努力必须着重于为前方的漫长道路挖掘和装备自己。你的学习曲线要比职位、职称更加重要。 第二阶段是聚焦长板的时候。该阶段的首要目标是寻找自己的甜蜜区,即你所擅长的、所热爱的和这个世界所需要的这三者之间的交集。 第三阶段致力于实现持续的影响力,以及寻找一条可以稳定延续到 60多岁甚至 70多岁的新的可持续职业道路。 职场燃料很重要,因为职业生涯的基础决定结果。 这种燃料有三个主要来源:可迁移技能、有意义的经验和持久的关系。 职业生涯需要通过对时间的巧妙投资来构建。 职业生涯并不是以线性或者可预测的方式发展的。 职业生涯远不止于一份工作,而是生活的一大部分。 实现职业规划要做到的5件事 学习职场数学,树立正确的长期思维方式。 盘点职场清单,梳理你最有用处的技能、经验和关系。 进行“ 100小时测试”并完成一份“个人时间档案”,从而了解你目前的时间投资状况。 在尝试建立新的职场路径或者在多个选项中抉择时,运用“职场路径向导”( Career Path Navigator)。 时刻更新你的职业生涯 我如何避免被机器取代? 我能在哪里以什么方式找到工作? 未来我将如何分配时间? 我会把钱花光吗? 工作如何能让我更幸福? 三大阶段,聚焦 45 年职业生涯 第一阶段:加添燃料,强势开局; 第二阶段:聚焦长板,达到高点; 第三阶段:优化长尾,持续发挥影响力。 第一阶段:加添燃料,强势开局 职业生涯前 15年的唯一目标就是为接下来的两个阶段打好基础。 第一阶段是探索和弥补自身短板的时候。如果你是个糟糕的演讲者,那就去参加相关的培训课程。如果你对待团队成员过于强势或弱势,那就去参加领导力培训。学习要比纯粹的成功更重要。有时跌倒并不可怕,只要你能吸取教训,并将这些经验加以利用就行。 第二阶段:锚点甜蜜区,聚焦长板 第二阶段是在你的长板、你的爱好以及这个世界的需求之间寻找交集的时候。 坦率地承认自己的短板,针对它们招募盟友,你就可以把大多数时间放在核心长板上了。 第三阶段:优化长尾,持续发挥影响力 第三阶段的主要目的是确定接班人,即给继任计划画上完美的句号,从执行或领导的角色转变成顾问或辅助的角色。 保持关联性是你在第三阶段的工作之一。 储备三大职场燃料 你的领导力是由你的学习意愿助燃前行的。
Spring AOP 源码分析:创建代理(二)

Spring AOP 源码分析:创建代理(二)

D瓜哥
Spring AOP 源码分析:入门 中,梳理出来了 Spring AOP 的入口。 Spring AOP 源码分析:获得通知 中着重介绍了如何获取通知。上一篇文章 Spring AOP 源码分析:创建代理(一) 重点介绍了一下切面链的组装和基于 JDK 动态代理的 AOP 的实现,这篇文章介绍一下基于 cglib 的代理类是生成。 cglib 简介 CGLIB(Code Generator Library)是一个高性能的代码生成库,被广泛应用于 AOP 框架(Spring)中以提供方法拦截功能,主要以继承目标类的方式来进行拦截实现,因此 CGLIB 可以对无接口的类进行代理。 CGLIB代理主要通过操作字节码的方式为对象引入方法调用时访问操作,底层使用了ASM来操作字节码生成新的类,ASM是一个短小精悍的字节码操作框架。CGLIB的应用栈如下: 最新版的 Hibernate 已经把字节码库从 cglib 切换为 Byte Buddy。 JDK 动态代理是通过实现 InvocationHandler 接口,在其 invoke 方法中添加切面逻辑。而 cglib 则是通过实现 MethodInterceptor 接口,在其 invoke 方法中添加切面逻辑。 下面看一下在 Spring 中,是如何实现利用 cglib 来实现 AOP 编程的? CglibAopProxy 先看一下创建代理对象的方法: CglibAopProxy#getProxy(ClassLoader) @Override public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.
Spring AOP 源码分析:创建代理(一)

Spring AOP 源码分析:创建代理(一)

D瓜哥
Spring AOP 源码分析:入门 中,梳理出来了 Spring AOP 的入口。上一篇文章 Spring AOP 源码分析:获得通知 中着重介绍了如何获取通知。接着上一篇文章,这篇文章介绍一下如何创建代理。 AbstractAutoProxyCreator#createProxy protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClassConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } // 创建代理工厂对象 ProxyFactory proxyFactory = new ProxyFactory(); // 获取当前类的属性 proxyFactory.copyFrom(this); //如果没有使用CGLib代理 if (!proxyFactory.isProxyTargetClass( { // 是否可能使用CGLib代理 // 决定对于给定的 Bean 是否应该使用 targetClass 而不是他的接口代理 if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { // 查看beanClass对应的类是否含有InitializingBean.class/DisposableBean.class/Aware.class接口 // 无则采用JDK动态代理,有则采用CGLib动态代理 evaluateProxyInterfaces(beanClass, proxyFactory); } } // 获得所有关联的Advisor集合(该分支待补充) Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.
Spring AOP 源码分析:获得通知

Spring AOP 源码分析:获得通知

D瓜哥
在文章 Spring AOP 处理流程概述 中,对 Spring AOP 有了一个整体认识。在文章 Spring AOP 源码分析:入门 中,对 Spring AOP 的相关入口做了分析。这篇文章就带大家看一看,Spring AOP 是如何获取通知的? 示例代码 在 如何阅读 Spring 源码?: 示例代码 中,已经给出了一个完整的 AOP 示例代码。为了节省篇幅,请直接参考那篇文章的示例代码,这里就不在赘述。 注册 Advice(通知/增强) 请根据 Spring AOP 源码分析:入门 中提到的关键方法入口处,打上断点,开始调试。 首先,需要明确一点的是:对于切面(使用 @Aspect 注解标注过的类)在 Spring 容器中,也是被统一f封装为 BeanDefinition 实例的,也需要通过一个方式,将其注册到 Spring 容器中。比如,就像 示例代码 那样,通过 ImportSelector 方式,使用类名,将其注册到容器中。这样,就可以利用 Spring 容器对 Bean 的 API 来统一处理了。 Advice(通知/增强)几乎是在意想不到的地方完成注册的:在第一次调用 AbstractAutoProxyCreator#postProcessBeforeInstantiation 方法时,通过 AspectJAwareAdvisorAutoProxyCreator#shouldSkip 方法,完成了切面的注册。下面,我们对这个过程抽丝剥茧,逐步分析。 先来看看 findCandidateAdvisors 方法: AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors @Override protected List<Advisor> findCandidateAdvisors() { // Add all the Spring advisors found according to superclass rules.
如何阅读 Spring 源码?

如何阅读 Spring 源码?

D瓜哥
昨晚原计划给几个朋友简单介绍一下阅读 Spring 源码的方法。结果,大家因为各种原因没能及时参加。后来,就取消分享了。干脆写一篇文章出来,感兴趣欢迎自取。 代码准备 Spring Framework 是开源的,代码托管在 GitHub 上: Spring Framework。任何人都可以方便地获得它的源代码。所以,如果想阅读 Spring 的源代码,当然是直接把代码克隆到本地,然后直接在 IDE(推荐 IDEA)中进行调试了。另外,还需要存放自己写一些测试和文档。所以,最好把代码 fork 到自己的账户下,从 master 上切出一个新分支并 push 到自己的 Repo 中,这样自己就可以随意更新了。具体步骤如下: 克隆代码 # 直接克隆原始仓库为 origin git clone git@github.com:spring-projects/spring-framework.git fork 代码,D瓜哥直接 fork 到自己账户下了: diguage/spring-framework。 添加原创仓库地址: # 添加自己仓库为 diguage # 这样就能在所有项目中保持命名的一致性,方便标识 git remote add diguage git@github.com:diguage/spring-framework.git 创建新分支 # 创建新分支 git switch -c analysis # 将新分支 push 到自己的 Repo 中 git push diguage analysis 这样,在这个新分支上,就可以随意折腾了。 下载依赖 # Mac or Linux .
Spring AOP 源码分析:入门

Spring AOP 源码分析:入门

D瓜哥
在上一篇文章 Spring AOP 处理流程概述 中,对 Spring AOP 有了一个整体认识。这篇文章就带大家做一个细致的源码分析。 登堂入室 使用 Spring AOP 也很简单,只需要在配置类上加上 @EnableAspectJAutoProxy 注解即可。这个注解处理过程与 Spring 扩展点实践:整合 MyBATIS 中 “@MapperScan 处理” 类似,不同的是,Spring AOP 注册了 AnnotationAwareAspectJAutoProxyCreator,它是一个 InstantiationAwareBeanPostProcessor。具体的类图如下: Figure 1. AnnotationAwareAspectJAutoProxyCreator 的继承体系 在正式开始源码分析之前,有一点必须强调一下:Spring AOP 只是借用了 AspectJ 的一些注解和个别关键 API,而整体实现是 Spring 自己完成的,并不是基于 AspectJ 实现的。这一点跟很多人的认识是不一样的,需要特别指出。 D瓜哥在 Spring Bean 生命周期概述 中指出:创建 AOP 代理对象,有两个时机: 调用 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 时,通过调用 AnnotationAwareAspectJAutoProxyCreator 对象的 postProcessBeforeInstantiation 方法来创建对象; 调用 BeanPostProcessor#postProcessAfterInitialization 时,通过调用 AnnotationAwareAspectJAutoProxyCreator 对象的 postProcessAfterInitialization 方法来创建对象; 下面分别对这两个方法做更详细的介绍。 AnnotationAwareAspectJAutoProxyCreator#postProcessBeforeInstantiation AnnotationAwareAspectJAutoProxyCreator 的 postProcessBeforeInstantiation 方法是从 AbstractAutoProxyCreator 继承过来的。代码如下:
TCP 三次握手和四次挥手

TCP 三次握手和四次挥手

D瓜哥
传输控制协议(英语:Transmission Control Protocol,缩写:TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由 IETF 的 RFC 793 定义。在简化的计算机网络 OSI 模型中,它完成第四层传输层所指定的功能。 毫不夸张地说,TCP 协议是目前整个互联网的基础。它解决了一系列的网络问题。带来的结果,就是协议本身非常复杂。考虑到文章篇幅问题,本文着重说明 TCP 建立连接时的三次握手过程和关闭连接时的四次挥手过程。 三次握手 Figure 1. TCP 三次握手 第一次握手(SYN=1, seq=x): 客户端发送一个 TCP 的 SYN 标志位置 1 的包,指明客户端打算连接的服务器的端口,以及初始序号 x,保存在包头的序列号(Sequence Number)字段里。 发送完毕后,客户端进入 SYN_SEND 状态。 第二次握手(SYN=1、seq=y;ACK=1、ACKnum=x+1): 服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为 1。服务器端选择自己 ISN 序列号,放到包头的序列号(Sequence Number)字段里,同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加 1,即 x+1。 发送完毕后,服务器端进入 SYN_RCVD 状态。 第三次握手(ACK=1,ACKnum=y+1) 客户端再次发送确认包(ACK),SYN 标志位为 0,ACK 标志位为 1,并且把服务器发来 ISN 的序号字段+1,放在确定字段中发送给对方,即数据段放写 y+1。 发送完毕后,客户端进入 ESTABLISHED 状态,当服务器端接收到这个包时,也进入 ESTABLISHED 状态,TCP 握手结束。 SYN Flood 攻击 在三次握手过程中,服务器发送 SYN-ACK 之后,收到客户端的 ACK 之前的 TCP 连接称为半连接(half-open connect)。此时服务器处于 SYN_RCVD 状态。当收到 ACK 后,服务器才能转入 ESTABLISHED 状态.
HikariCP 源码分析 --  FastList

HikariCP 源码分析 -- FastList

D瓜哥
在前面的文章 HikariCP 源码分析 — ConcurrentBag 中,D瓜哥分析了一下 HikariCP 中一个非常重要的数据结构 ConcurrentBag。 今天,继续再介绍 HikariCP 中另一个很关键的数据结构: FastList。 FastList 本身的实现非常简单,要理解它的奥秘,就需要结合 Java 原生集合类的 ArrayList 来比较性地看。 构造函数 先来对比一下两者的构造函数。先来看看 FastList: FastList public final class FastList<T> implements List<T>, RandomAccess, Serializable { private static final long serialVersionUID = -4598088075242913858L; private final Class<?> clazz; private T[] elementData; private int size; / * Construct a FastList with a default size of 32. * @param clazz the Class stored in the collection */ @SuppressWarnings("unchecked") public FastList(Class<?
使用 Hugo 搭建博客

使用 Hugo 搭建博客

D瓜哥
一个朋友对D瓜哥的博客感兴趣,觉得很好玩。问我怎么玩,D瓜哥也懒得手把手教了,干脆写篇文章来做个说明吧。也许对其他朋友也有所帮助。 潮起潮落 D瓜哥早在 2012年就使用 WordPress 搭建了一个博客: "地瓜哥"博客网—分享技术带来的喜悦,WordPress 不亏是全世界最流行的开源 CMS 系统,各种插件可以满足非常对的需求。当年D瓜哥还想研究一下它的源代码,可惜对 PHP(对,就是那个拍黄片的)无感,没有坚持下去。 但是,在熟悉了 MarkDown、 Asciidoctor(D瓜哥是 AsciiDoctor 的死忠粉,坚决支持它的发展) 等轻量级标记语言后,愈发觉得 WordPress 太繁琐:写作一个小时,排版发布一小时。实在是太浪费时间了。 先尝试了一下 Antora,之所以选它,是因为它是 AsciiDoctor 的作者发起的项目,对 AsciiDoctor 的支持性非常好。尝试了一段时间后,发现它更适合写产品说明书,更适合像阿里云等这种对外提供产品,需要提供在线产品说明书的情况。不适合做个人博客。 去年,经过多次测试后(主要测试对 AsciiDoctor 的支持性),发现现在D瓜哥用的这个主题对 AsciiDoctor 支持得不错,随后下定决心切换到了 Hugo。 Hugo 简介 关于 Hugo 的介绍,直接转摘维基百科的介绍了: Hugo 是一个用 Go 编写的静态网站生成器,2013由 Steve Francia 原创,自 v0.14 (2015年) 由 Bjørn Erik Pedersen 主力开发,并由全球各地的开发者和用户提交贡献。Hugo 以 Apache License 2.0 许可的开放源代码项目。 Hugo 一般只需几秒钟就能生成一个网站(每页少于 1 毫秒),被称为“世界上最快的网站构建框架”,也使 Hugo 大受欢迎,成为最热门的静态网站生成器之一,被广泛采用。例如,2015年7月,Netlify 推出专为 Hugo 而设的网站托管服务,而2017年,Smashing Magazine 推出重新设计的官方网站,从原来的 WordPress 迁移到基于 Hugo 的 JAMstack 解决方案。
源码剖析 Spring 循环依赖

源码剖析 Spring 循环依赖

D瓜哥
循环依赖在编程中是一个常见问题(当然,这并不是最佳实践)。并且,Spring 如何解决循环依赖这个问题在面试中也经常见。下面,D瓜哥就从源码的层面深入剖析一下这个问题。 示例程序 先展示一下示例程序: package com.diguage.truman.context; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.ImportSelector; import org.springframework.core.type.AnnotationMetadata; import org.springframework.stereotype.Component; /** * @author D瓜哥, https://www.diguage.com/ * @since 2020-05-24 13:02 */ public class CircularDependenceSingletonTest { public static final Log log = LogFactory.getLog(CircularDependenceSingletonTest.class); @Test public void test() { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); applicationContext.register(Config.class); applicationContext.refresh(); log.info(applicationContext.getBean(A.class)); log.info(applicationContext.getBean(B.class)); log.info(applicationContext.getBean(C.class)); log.info("-A--------"); A a = applicationContext.getBean(A.class); log.info(a); log.info(a.b); log.