9

这里有一个源码调试方法,短小精悍,简单粗暴,但足够好用。 - why技术

 1 year ago
source link: https://www.cnblogs.com/thisiswhy/p/17421865.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

这里有一个源码调试方法,短小精悍,简单粗暴,但足够好用。

你好呀,我是歪歪。

上周发布了《我试图通过这篇文章告诉你,这行源码有多牛逼。》这篇文章。

文章中有这样的一段描述:

20230521160311.png

然后有个读者来问我:

是怎么把 JDK 源码中的一行代码给注释掉的?

这个问题确实不错,属于一个偶尔用一下能起到奇效的源码调试技巧。所以我决定写个文章来说明一下这个问题。

但是这个技巧确实非常的简单,简单到一句话就能说明白,所以正如标题说到的“短小精悍,简单粗暴,但足够好用”,这篇文章也会非常的短。

首先,把问题换个问法,既然我能把源码注释了,那说明我能修改源码。所以,问题就变成了:我怎么去修改 JDK 的源码呢?

这个问题有很多个回答,但是我这里的回答很简单。把源码拷贝一份出来,原模原样的放一份到自己的项目中即可。

就像是这样:

20230521164659.png

然后你在使用的时候,直接用你 CV 过来的源码,就行了:

20230521164907.png

但是我一般使用这个方法的时候,CV 过来时,会把类名称重命名一下,以示区分,其他的啥都不改。

反正不管怎么样吧,这样在你的项目里面有一份“源码”了,这个“源码”和 JDK 里面的源码一模一样,这样你就能随便进行修改了。

比如,我在调用 put 方法的时候,加一点日志输出:

20230521170936.png

这样测试用例跑起来的时候,就能直接输出你添加的内容:

20230521170958.png

你都能添加代码了,注释代码,甚至是修改代码逻辑,那还不是手到擒来的事情吗?

对于一些比较复杂的场景,比如异步或者循环等等场景,当你想要在源码中加入输出语句方便进行学习和调试的时候,你就可以用到这招。

这就是我这篇文章要教你的一个关于 JDK 源码的调试技巧。

整体用处不大,但是当你能想到用它的时候,就是发挥奇效的时候。

既然话题都到这里了,那么我再给你补充一个关于第三方框架的类似的调试技巧。

还是先举个例子。

比如我在项目中使用到了 @Async 注解,然后有一个自定义线程池,发起一个请求之后可以看到确实是使用了我的自定义线程池:

20230521171801.png

然后,问题就来了。

假设,我想让 @Async 注解支持 EL 表达式,也就是这样的写法:

20230521172406.png

目前,Spring 是不支持这样的配置的,当你这样配置并发起调用,会抛出这样的一个异常:

20230521172232.png

它会把 ${thread-pool.name} 认为是一个 Bean,然后 Spring 里面并没有这样的一个 Bean,所以抛出找不到 Bean 的异常。

那么怎么才能让 @Async 注解支持 EL 表达式呢?

我之前写过《舒服,给Spring贡献一波源码。》这篇文章,里面用的就是这个案例,有兴趣的话可以去看看,我就不展开说了。

在文章里面,经过分析,我们知道只需要在 org.springframework.aop.interceptor.AsyncExecutionAspectSupport.findQualifiedExecutor(BeanFactory,String) 这个方法中,加入这几行代码就行了:

if (beanFactory instanceof ConfigurableBeanFactory) {
 EmbeddedValueResolver embeddedValueResolver = new EmbeddedValueResolver((ConfigurableBeanFactory)beanFactory);
 qualifier = embeddedValueResolver.resolveStringValue(qualifier);
}

但是我当时采取的方案是通过 idea 的 Evaluate Expression 功能:

20230521172936.png

经过评论区提醒,其实用 CV 大法,更加直接、方便。

同样的道理,直接把 AsyncExecutionAspectSupport 这个类粘到我们自己的项目中去:

20230521173547.png

这里需要注意的是,要保证包名称也一模一样,因为这个方法的底层逻辑是基于类加载机制实现的。

这样,我们就能针对我们自己项目中的 AsyncExecutionAspectSupport 类进行修改:

20230521175046.png

再次发起调用,这事儿就算成了:

20230521175232.png

这个方法,适用于任何你能拿到源码的任何第三方框架。

虽然,很多第三方框架里面都会主动留下足够多的扩展点,以便使用者进行定制化开发。

所以我提供的这个方法好像用处并不是很大,但是我当年看 Dubbo 源码的时候,就是这样的看的。

就像是这样,在源码里面加入了大量的输出语句,然后基于输出语句去做分析:

20230521203707.png
20230521203731.png

虽然现在想起来,更加正确的操作应该是基于它的 SPI 机制去做。

但是,管它呢,反正当时我就是靠这种歪门邪道,也看的明明白白的。

好了,以上就本文的全部内容。

突出的就是一个短小精悍,简单粗暴,又足够好用。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK