代码之家  ›  专栏  ›  技术社区  ›  Craig Otis

当被Spring代理类访问时,Kotlin实例变量为null

  •  12
  • Craig Otis  · 技术社区  · 7 年前

    @Service
    @Transactional
    open class MyService { ... }
    

    如果我删除 open @Transactional 注释调整。

    @Service
    @Transactional
    open class MyService { 
        protected val internalVariable = ...
    
        fun doWork() {
            internalVariable.execute() // NullPointerException
        }
    }
    

    这个 internalVariable 作为其声明的一部分进行分配,没有任何注释(如 @Autowired 等),以及 这个 注释和Spring代理类的要求。

    当Spring代理/子类化我的服务类时,为什么这个变量为null?

    1 回复  |  直到 7 年前
        1
  •  24
  •   jay    7 年前

    我碰到了一个类似的问题,上面的评论是拉斐尔G&克雷格·奥蒂斯(Craig Otis)帮了我的忙,所以我建议接受以下评论作为答案(或者将上面的评论更改为答案,然后接受)。

    打开 方法/字段。

    (我遇到了一个类似的案例,它是一个封闭的 这导致了问题。但无论是场/方法,解决方案都是相同的,我认为一般原因都是相同的……)

    说明:

    为什么这是一个更复杂的解决方案,肯定与Spring AOP、最终字段/方法、CGLIB代理和

    Spring使用代理来表示某些对象,以处理由面向方面编程处理的某些问题。服务和;控制器(尤其是当 @Transactional

    因此,这些bean需要一个代理/包装器,Spring有两个选择——但当父类不是接口时,只有CGLIB可用。

    当使用CGLIB代理类时,Spring将创建一个子类,名为 比如myService$enhancerbyglib。此增强类将 对实际代码的交叉关注。

    真正的惊喜来了。这个额外的子类不调用super 基类的方法。相反,它创建了 您的真实对象和CGLIB增强对象指向(包装)它。

    发件人: spring singleton bean fields are not populated

    Spring AOP CGLIB proxy's field is null

    在科特林;除非明确打开,否则方法是最终的。

    Spring/CGLib的魔力何时&我不知道如何选择用目标委托将Bean包装在enhancerbyglib中(以便它可以使用最终确定的方法/字段)。然而,在我的例子中,调试器向我展示了两种不同的结构。当父方法为 ,它不创建委托(而是使用子类化),并且在没有NPE的情况下工作。但是,当特定方法关闭时 那么对于这个封闭方法 Spring/CGLIB使用包装对象,并将其委托给正确初始化的目标委托。出于某种原因,方法的实际调用是在上下文为

    Craig通过打开属性(而不是方法)解决了这个问题,我怀疑它具有类似的效果,即允许Spring/CGLib要么不使用委托,要么以某种方式正确使用委托。