Spring中@Component类注入@Autowired Service为空的原因咨询
嘿,我来帮你拆解下这个问题的核心原因,以及对应的解决方案:
核心问题分析
你遇到的exchangeService为空的情况,主要有两个关键原因:
1. Spring依赖注入的时机不对
Spring对@Autowired标注的字段,是在对象完成实例化之后才会执行注入操作的。而你在ProductDTO的带参构造器public ProductDTO(Product product)里直接访问exchangeService,这时候对象还在创建过程中,Spring还没来得及把依赖注入进去,所以这里的exchangeService自然是null。
2. 手动实例化导致Spring无法管理对象
如果你的ProductDTO是通过new ProductDTO(product)这种方式手动创建的,那这个实例根本不在Spring的应用上下文的管理范围内。哪怕你给类加了@Component注解,只要是手动new出来的对象,Spring都不会为它注入任何依赖——这也是为啥注入到@Controller里能正常工作的原因:Controller是Spring自己创建并管理的。
可行的解决方案
针对这两个问题,给你几个实用的解决办法:
方案一:改用构造器注入(推荐,符合Spring最佳实践)
把ExchangeService通过构造器注入,这样在对象实例化的时候就能拿到依赖,完美避开时机问题:
@Component public class ProductDTO implements Serializable { private final ExchangeService exchangeService; // 构造器注入,Spring会自动把ExchangeService传进来 @Autowired public ProductDTO(ExchangeService exchangeService) { this.exchangeService = exchangeService; } // 单独写一个初始化方法,处理从Product转换的逻辑 public void initFromProduct(Product product) { System.out.println("service****" + exchangeService); Currency EURCurrency = exchangeService.getEURCurrency(); // 这里写其他从Product到DTO的转换逻辑 } }
之后要创建DTO时,别手动new,而是从Spring容器中获取ProductDTO实例,再调用initFromProduct方法。
方案二:用@PostConstruct延迟初始化逻辑
如果你坚持要用字段注入,可以把构造器里的逻辑放到@PostConstruct标注的方法里——这个方法会在Spring完成所有依赖注入之后自动执行:
@Component public class ProductDTO implements Serializable { @Autowired private ExchangeService exchangeService; private Product product; public ProductDTO() { } // 先设置Product对象 public void setProduct(Product product) { this.product = product; } // 依赖注入完成后执行初始化 @PostConstruct public void init() { if (product != null) { System.out.println("service****" + exchangeService); Currency EURCurrency = exchangeService.getEURCurrency(); // 其他转换逻辑 } } }
同样,这个DTO实例必须由Spring创建,不能手动new。
方案三:创建DTO工厂类(适合频繁创建DTO的场景)
如果需要经常从Product生成ProductDTO,可以写一个由Spring管理的工厂类,在工厂里注入ExchangeService,专门负责DTO的创建和初始化:
@Service public class ProductDTOFactory { private final ExchangeService exchangeService; @Autowired public ProductDTOFactory(ExchangeService exchangeService) { this.exchangeService = exchangeService; } public ProductDTO createFromProduct(Product product) { ProductDTO dto = new ProductDTO(); // 这里可以直接使用exchangeService来完成DTO的初始化 Currency EURCurrency = exchangeService.getEURCurrency(); // 设置DTO的其他字段 return dto; } }
之后在需要创建DTO的地方,注入ProductDTOFactory来生成实例即可。
总结一下:Spring只负责管理它自己创建的对象的依赖注入,而且注入动作是在对象实例化之后才完成的。构造器里拿不到注入的依赖是时机问题,手动new的对象Spring根本不会处理依赖注入。
内容的提问来源于stack exchange,提问作者blue

