大家都开始玩springboot了, 其实肯定已经知道 平常写代码,如果在静态方法里面调用 spring ioc容器里面的bean,是不允许的。
就像这样,在写代码的时候就告诉你不能这么写:
然后我们根据提示,改成这样写哈哈哈哈, 可以了(静态拿静态,没毛病):
然后我们真正去调用,会发现报错:
取出来的tradeService 是null :
为什么? 怎么办 ?
怎么办我不展开说其实很多方案,可以把这个tardeService直接拿出来。
我这一篇文章想给大家讲讲是为什么 ?
我觉得大部分人可能都不会去关注这个东西。
静态方法提前加载啊, 肯定拿不到bean的实例啦 ,这么理解确实没有错。
我抛出一个问题:
如果给你去实现,我就要你静态方法加载的时候,去取实例,你去封装一下spring框架,
你能不能实现 ?
答案是: 必然可以的。
所以我现在要揭开 为什么不能的真面目了
源码:
AutowiredAnnotationBeanPostProcessor 的 buildAutowiringMetadata 函数,看到那个isStatic方法了么?
没错,其实就是spring框架这里拦截判断如果是static,直接return,不再注入,所以后面我们拿到null了。
可能这么一句话说,看不懂源码的初学者可能不太信。
OK,那我现在就通过debug方式,魔改一下这个判断。
①首先我把debug打好,卡在前面:
②来了,主角来了:
③ 动手:
可以看到 isStatic()的源码,
也就是说如果 field.getModifiers() 改成0,就能绕过这个静态检测 。
就这么做,直接改成0:
ps: 评论区有兄弟对这个改debug的值感兴趣,我补一张操作图,平时dubug调试的时候,看个人使用习惯,也可以这样去调试一些业务场景。
可以看到成功绕过了,绕过后立刻改回来还原原来的值 10:
如果被拦截是有日志打印的:
现在我们绕过之后:
现在我们再来调用一下看看效果,不再是null了:
看到这里,大家都知道为啥了、 就是 spring 的作者在设计上的考虑,这个isStatic就是真凶。
深思
从做开源框架的角度上去考虑, 是不是什么都做,是好框架?
那么spring容器的职责、初衷是什么?
(当然,现在这一小段分析都是我个人的想法,可能不够成熟。)
IOC的初衷,是用来管理 bean的实例的。
如果说一个属性是 static修饰, 那么这个静态成员其实不是实例的, 它是类的。
不是我们的饭, 我们能吃,但是能够吃么? 该吃么? 什么时候会去吃?
别说光看这个问题了,不管工作上,生活中,我们是不是都应该想一想。
如果你有看法,欢迎留言。