SpringBoot (走读源码)静态方法中调用spring注入的对象,注入对象为null?

x33g5p2x  于2022-07-07 转载在 Spring  
字(1.0k)|赞(0)|评价(0)|浏览(414)

大家都开始玩springboot了, 其实肯定已经知道 平常写代码,如果在静态方法里面调用 spring ioc容器里面的bean,是不允许的。

就像这样,在写代码的时候就告诉你不能这么写:

然后我们根据提示,改成这样写哈哈哈哈, 可以了(静态拿静态,没毛病):

然后我们真正去调用,会发现报错:

取出来的tradeService 是null :

为什么?  怎么办 ?

怎么办我不展开说其实很多方案,可以把这个tardeService直接拿出来。

我这一篇文章想给大家讲讲是为什么 ?

我觉得大部分人可能都不会去关注这个东西。

静态方法提前加载啊, 肯定拿不到bean的实例啦 ,这么理解确实没有错。
 

我抛出一个问题:

 

如果给你去实现,我就要你静态方法加载的时候,去取实例,你去封装一下spring框架,

你能不能实现 ?

答案是: 必然可以的。

所以我现在要揭开 为什么不能的真面目了

源码:

AutowiredAnnotationBeanPostProcessor 的 buildAutowiringMetadata 函数,看到那个isStatic方法了么?

没错,其实就是spring框架这里拦截判断如果是static,直接return,不再注入,所以后面我们拿到null了。

可能这么一句话说,看不懂源码的初学者可能不太信。

OK,那我现在就通过debug方式,魔改一下这个判断。

①首先我把debug打好,卡在前面:

②来了,主角来了:

③ 动手:
 

可以看到 isStatic()的源码, 

也就是说如果 field.getModifiers() 改成0,就能绕过这个静态检测 。

就这么做,直接改成0:
 

可以看到成功绕过了,绕过后立刻改回来还原原来的值 10:
 

如果被拦截是有日志打印的:

现在我们绕过之后:

现在我们再来调用一下看看效果,不再是null了:

看到这里,大家都知道为啥了、 就是 spring 的作者在设计上的考虑,这个isStatic就是真凶。

深思

从做开源框架的角度上去考虑, 是不是什么都做,是好框架?

那么spring容器的职责、初衷是什么?

(当然,现在这一小段分析都是我个人的想法,可能不够成熟。)

IOC的初衷,是用来管理 bean的实例的。

如果说一个属性是 static修饰, 那么这个静态成员其实不是实例的, 它是类的。

不是我们的饭, 我们能吃,但是能够吃么? 该吃么? 什么时候会去吃?

别说光看这个问题了,不管工作上,生活中,我们是不是都应该想一想。

如果你有看法,欢迎留言。

相关文章