kotlin与Spring, 默认类,方法,property为final带来的问题--依赖注入失效,NullPointerException异常

问题的由来

在Spring中使用kotlin, 发现依赖注入似乎没有生效,导致NPE.
比如以下的代码,对于发送短信这个功能, 并不需要在主流程中同步发送, 所以就使用了Spring的@Async注解, 可以使这个方法在配置AsyncExecutor中执行.
但是实际调用时, 却发现contactDao为null, 程序报NullPointerException异常. 但是我用java写却没有问题.

@Service
open class MessageService {
    //根据用户id获取用户联系信息的Dao
    @Autowired
    lateinit var contactDao: ContactDao

    //将message发给一系列的用户ids
    @Async
    fun sendMessage(contactIds: List<String>, message: String) {
        //先根据id获取用户联系信息
        contactIds.map { contactDao.getContactById(it) }
                //对每个用户发送message
                .forEach { contact ->
                    sendPhoneMessage(contact.phone,message)
                }
    }

    fun sendPhoneMessage(phoneNumber:String, message:String){
        ...
    }
}

原理

解决这个问题, 就需要对Spring的源码有一定的了解.
简单的说就是kotlin的类, 方法, property默认都是final, 是不能够被子类更改的. 而Spring的cglib代理需要非final类, 方法.

  1. Spring的异步注解(@Async), 事务(@Transactional), 缓存(@Cacheable,@CachePut,@CacheEvict等),Configuration这些其实都要更改方法的执行流程, 也就是说要使用代理来更改.
  2. 对于不指定具体代理方法, 且没有实现接口的类, spring会选择使用cglib来进行代理
  3. cglib代理过程是先根据Bean实例的类,生成一个子类(配置了拦截器), 然后寻找构造器, 构造一个子类实例(并没有对该实例进行任何注入设置, 该实例的属性的都是null).
  4. 代理后生成的实例非final方法调用会转发给原bean, 就可以获得依赖注入的属性值. 但是final方法是不会被
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值