Spring中如何为静态类注入静态字段?注入后DAO为空问题排查
嘿,这个问题我碰到过好多次了——本质上是没搞清楚Spring依赖注入的核心逻辑:Spring是管理实例对象的依赖,而静态字段属于类本身,默认情况下Spring不会主动处理静态成员的注入。你之前的@Autowired setter注入之所以失败,是因为Spring只会对它所管理的bean实例调用@Autowired标注的方法,静态方法不属于任何实例,Spring根本不会去触发那个静态setter,所以你的dao字段自然一直是null。
下面给你几个可行的解决办法,还有更符合Spring设计理念的优化方向:
解决方案1:通过@PostConstruct在实例方法中赋值静态字段
把MyStaticService变成Spring管理的bean(加@Component注解),然后通过实例级别的依赖注入,再在初始化方法里把实例的dao赋值给静态字段:
@Component public class MyStaticService { // 静态字段 private static MyDao dao; // 实例级别的依赖,让Spring注入 private MyDao instanceDao; @Autowired public void setInstanceDao(MyDao instanceDao) { this.instanceDao = instanceDao; } // 实例初始化完成后执行,把实例的dao赋值给静态字段 @PostConstruct public void initStaticDao() { MyStaticService.dao = this.instanceDao; } public static int doCalculations(/* 你的参数 */) { return dao.doSmth(); // 现在不会再null了 } }
原理是:Spring会先创建MyStaticService的实例,完成instanceDao的注入,然后调用@PostConstruct标注的初始化方法,把实例的dao赋值给静态字段,这样静态方法就能正常调用了。
解决方案2:用@Configuration类手动注入
如果你不想把MyStaticService改成Spring管理的bean,可以写一个配置类,手动获取MyDao的bean并赋值给静态字段:
@Configuration public class StaticBeanConfig { @Autowired private MyDao myDao; @PostConstruct public void initStaticDao() { // 调用MyStaticService的静态setter赋值 MyStaticService.setDao(myDao); } } // 对应的MyStaticService需要添加静态setter public class MyStaticService { private static MyDao dao; // 提供静态setter供配置类调用 public static void setDao(MyDao dao) { MyStaticService.dao = dao; } public static int doCalculations(/* 你的参数 */) { return dao.doSmth(); } }
这个方法的好处是MyStaticService不需要被Spring管理,适合那些无法修改成Spring bean的遗留类。
更推荐的做法:避免静态依赖,使用实例bean
其实静态依赖注入并不是Spring推荐的最佳实践——静态字段会让代码耦合度更高,而且极难进行单元测试(没法轻易mock掉MyDao)。如果可以的话,最好把MyStaticService改成非静态的Spring bean:
@Component public class MyService { private final MyDao dao; // 构造器注入(Spring 4.3+可以省略@Autowired) public MyService(MyDao dao) { this.dao = dao; } public int doCalculations(/* 你的参数 */) { return dao.doSmth(); } } // 使用的时候,直接注入MyService实例 @Autowired private MyService myService; // 调用方法 int result = myService.doCalculations(...);
这种方式完全符合Spring的依赖注入设计理念,代码更易维护、易测试,是长远来看更好的选择。
内容的提问来源于stack exchange,提问作者CameronCoob

