Spring注入SakilaDao触发NotWritablePropertyException报错排查
根因定位
报错触发的核心逻辑是Spring的属性匹配规则与配置/代码定义不匹配:
- Spring在通过XML配置完成Setter注入时,完全不直接读取类的私有字段,而是严格遵循JavaBeans规范,通过类中公共setter方法的命名推导可注入的属性名
- 推导规则:如果类中存在方法签名为
void setXxx(对应类型 参数)的公共方法,则该类存在可写属性xxx(注意首字母自动小写) - 当前不匹配点:
- 你的
SakilaManagerImpl类中定义的setter方法是public void setDao(SakilaDaoImpl dao),按照规则推导,类的可写属性名是dao - 你在
applicationContext.xml中配置的property名称是SakilaDao,Spring会按这个名称查找对应的setSakilaDao()方法,类中不存在该方法,因此抛出NotWritablePropertyException
- 你的
- 你之前把字段类型从实现类换成接口类型不生效,是因为问题根源从来不是参数类型,而是property名称和setter方法名完全对不上
修复方案(二选一)
方案1:匹配现有类方法,修改XML配置(改动最小)
直接修改applicationContext.xml中manager bean的property名称,和类中现有setter对应:
<bean id="manager" class="com.java.Training.managerImpl.SakilaManagerImpl"> <!-- 原name="SakilaDao" 改为name="dao" --> <property name="dao" ref="dao"></property> </bean>
该方案不受dao字段的声明类型影响,不管你用SakilaDaoImpl还是接口SakilaDao声明属性,只要setter是setDao(),这个配置就生效
方案2:匹配现有XML配置,修改类方法
如果你希望保留XML中SakilaDao的property配置,就需要在SakilaManagerImpl中重命名对应的setter/getter方法:
// 替换原有的getDao()、setDao()方法 public SakilaDao getSakilaDao() { return dao; } public void setSakilaDao(SakilaDao dao) { this.dao = dao; }
推荐该方案的写法,因为属性类型用接口声明符合依赖倒置原则,更易维护。
注意事项
- 不要混淆Java字段名和Spring可识别的属性名:哪怕你把类中的私有字段直接命名为
SakilaDao,只要没有对应的公共setSakilaDao()方法,Spring依然无法识别该属性,会抛出完全相同的报错 - XML中的property名称尽量遵循Java编码规范用小写开头,减少大小写拼写不一致导致的匹配错误
内容的提问来源于stack exchange,提问作者Saptarshi
相关产品推荐
相关产品推荐

