Spring Boot 如何让同一套Service同时支持REST API调用与本地执行
问题1:调用效果差异的原因
根本原因是Spring的依赖注入能力仅对Spring IoC容器管理的Bean生效:
- 当通过Controller接收HTTP请求调用时,
@RestController标记的Controller、@Service标记的Service、@Repository标记的Repository都会在Spring Boot启动时被实例化为容器托管的Bean,@Autowired标记的依赖会由容器自动完成注入,因此Repository可以正常初始化使用。 - 你本地自定义main方法中直接用
new PruebaService()生成的对象完全脱离了Spring容器的管理,Spring不会识别该对象内的@Autowired注解,也不会自动注入PruebaRepository依赖,所以调用时pruebaRepository为null,触发空指针异常。
额外提醒:你提供的Service代码存在属性名不匹配的笔误,注入的属性名为pruebadao,但save方法中调用的是pruebaRepository.save(prueba),这个问题也需要同步修正,否则即使依赖注入正常也会报错。
问题2:解决方案
根据使用场景可选择以下适配方案:
方案1:项目启动时执行逻辑
如果需要在项目启动阶段就运行目标业务代码,可以实现CommandLineRunner接口,此时所有Bean已经完成注入:
@SpringBootApplication public class Application implements CommandLineRunner { @Autowired private PruebaService pruebaService; public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Override public void run(String... args) throws Exception { Prueba prueba = new Prueba("prueba"); pruebaService.savePrueba(prueba); } }
方案2:主动从Spring上下文获取Bean
如果需要在自定义逻辑中调用,先启动Spring上下文,再从上下文中获取Service实例,不要手动new对象:
public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(Application.class, args); PruebaService pruebaService = context.getBean(PruebaService.class); Prueba prueba = new Prueba("prueba"); pruebaService.savePrueba(prueba); }
方案3:单元测试场景
如果是本地做功能测试,直接使用Spring Boot测试注解即可自动完成依赖注入:
@SpringBootTest class PruebaServiceTest { @Autowired private PruebaService pruebaService; @Test void testSavePrueba() { Prueba prueba = new Prueba("prueba"); pruebaService.savePrueba(prueba); } }
内容的提问来源于stack exchange,提问作者user9767587
相关产品推荐
相关产品推荐

