简介
说明
本文介绍SpringBoot注入实现类导致的启动失败的解决方案。
问题描述
- 注册bean时,返回值类型是接口,方法里创建了一个实现类。
- 通过@Autowired注入实现类,结果报错了,应用启动失败。
- 通过@Autowired注入接口,启动成功。
- 通过@Autowired注入接口,通过@Autowired注入实现类,启动成功。
问题复现
注入实现类启动失败
package com.knife.example; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @SpringBootApplication public class DemoApplication { @Autowired private DistributeLock distributeLock; public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } @Configuration class LockConfig{ @Bean public Lock lock() { return new DistributeLock(); } } interface Lock{} class DistributeLock implements Lock{}
报错信息(无法找到com.knife.DistributeLock这个bean)
2022-09-10 16:37:43.419 INFO 142692 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1013 ms 2022-09-10 16:41:28.518 WARN 142692 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'demoApplication': Unsatisfied dependency expressed through field 'distributeLock'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.knife.DistributeLock' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} 2022-09-10 16:41:28.521 INFO 142692 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat] 2022-09-10 16:41:28.533 INFO 142692 --- [ main] ConditionEvaluationReportLoggingListener : Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2022-09-10 16:41:28.601 ERROR 142692 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPLICATION FAILED TO START *************************** Description: Field distributeLock in com.knife.DemoApplication required a bean of type 'com.knife.DistributeLock' that could not be found. The injection point has the following annotations: - @org.springframework.beans.factory.annotation.Autowired(required=true) Action: Consider defining a bean of type 'com.knife.DistributeLock' in your configuration. 2022-09-10 16:41:28.607 WARN 142692 --- [ main] o.s.boot.SpringApplication : Unable to close ApplicationContext org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'springApplicationAdminRegistrar' defined in class path resource [org/springframework/boot/autoconfigure/admin/SpringApplicationAdminJmxAutoConfiguration.class]: Unsatisfied dependency expressed through method 'springApplicationAdminRegistrar' parameter 1; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.core.env.Environment' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:798) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE] at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:539) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE] at org.springframework.beans.
注入接口启动成功
package com.knife.example; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @SpringBootApplication public class DemoApplication { @Autowired private Lock lock; public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } @Configuration class LockConfig{ @Bean public Lock lock() { return new DistributeLock(); } } interface Lock{} class DistributeLock implements Lock{}
结果(启动成功)
注入接口和实现类启动成功
package com.knife.example; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @SpringBootApplication public class DemoApplication { @Autowired private Lock lock; @Autowired private DistributeLock distributeLock; public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } @Configuration class LockConfig{ @Bean public Lock lock() { return new DistributeLock(); } } interface Lock{} class DistributeLock implements Lock{}
原因分析
报错原因概述
Spring是通过类型来匹配bean的,DemoApplication需要的是DistributeLock类型的bean,但找不到(只有Lock类型的bean),于是报错。
源码追踪
待补充。
解决方案
在注册Bean时,返回值类型与实际创建的类型必须是同一个,不能返回一个接口!
package com.knife.example; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @SpringBootApplication public class DemoApplication { @Autowired private DistributeLock lock; public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } @Configuration class LockConfig{ @Bean public DistributeLock distributeLock() { return new DistributeLock(); } } interface Lock{} class DistributeLock implements Lock{}
请先
!