【问题标题】:Why Spring Boot is not finding a @Service bean trying to perform autowiring? the bean exist but it can't find it为什么 Spring Boot 没有找到尝试执行自动装配的 @Service bean? bean存在但找不到
【发布时间】:2020-07-03 21:23:32
【问题描述】:

我在处理使用 JUnitSpring Boot 2.2.5.RELEASE 项目时遇到了一个奇怪的问题。

我尝试详细解释我的问题:

1) 我定义了一个服务。首先,我定义了一个名为 OrderService 的接口,如下所示:

package com.dgs.soc.service;

import java.util.List;

import com.dgs.soc.excelapi.dto.Order;

public interface OrderService {

    public List<Order> getOrdersList();

}

然后我定义了它的实现,目前是一个非常简单的名字OrderServiceImpl

package com.dgs.soc.service;

import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
import com.dgs.soc.excelapi.dto.Order;
import com.dgs.soc.repository.OrderRepository;

@Service
public class OrderServiceImpl {

    public List<Order> getOrdersList() {
        List<Order> result = new ArrayList<Order>();

        return result;
    }

}

如您所见,该类由 @Service 注释进行注释。

问题在于使用JUnit,我有这个测试类:

package com.dgs.soc.excelapi.integration;

// IMPORTS LIST

@RunWith(SpringRunner.class)
@SpringBootTest(classes = { Application.class })
@WebAppConfiguration
@ActiveProfiles(profiles = { "no-liquibase" })
public class ExcelResourceIntegrationTest {

    @Autowired
    OrderServiceImpl orderService;

    @Test
    public void getOrdersListRepositoryTest() { 
        List<Order> ordersList = orderService.getOrdersList();
        assertThat(ordersList).isNotEmpty();
    }

}

在这里我遇到了一个奇怪的行为:执行 getOrdersListRepositoryTest() 测试方法我得到了这个异常

2020-03-23 04:42:24.783 ERROR 5281 --- [           main] o.s.test.context.TestContextManager      : Caught exception while allowing TestExecutionListener [org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@7fbdb894] to prepare test instance [com.dgs.soc.excelapi.integration.ExcelResourceIntegrationTest@2ad6895a]

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.dgs.soc.excelapi.integration.ExcelResourceIntegrationTest': Unsatisfied dependency expressed through field 'orderService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.dgs.soc.service.OrderServiceImpl' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:130) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1422) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:393) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:119) ~[spring-test-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83) ~[spring-test-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:43) ~[spring-boot-test-autoconfigure-2.2.5.RELEASE.jar:2.2.5.RELEASE]
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:244) ~[spring-test-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:227) ~[spring-test-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289) ~[spring-test-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) ~[junit-4.12.jar:4.12]
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291) ~[spring-test-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246) ~[spring-test-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97) ~[spring-test-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) ~[junit-4.12.jar:4.12]
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) ~[junit-4.12.jar:4.12]
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) ~[junit-4.12.jar:4.12]
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) ~[junit-4.12.jar:4.12]
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) ~[junit-4.12.jar:4.12]
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) ~[spring-test-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) ~[spring-test-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363) ~[junit-4.12.jar:4.12]
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190) ~[spring-test-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137) ~[junit-4.12.jar:4.12]
    at org.junit.runner.JUnitCore.run(JUnitCore.java:115) ~[junit-4.12.jar:4.12]
    at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:40) ~[junit-vintage-engine-5.5.2.jar:5.5.2]
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) ~[na:na]
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) ~[na:na]
    at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133) ~[na:na]
    at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[na:na]
    at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) ~[na:na]
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
    at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497) ~[na:na]
    at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:80) ~[junit-vintage-engine-5.5.2.jar:5.5.2]
    at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:71) ~[junit-vintage-engine-5.5.2.jar:5.5.2]
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229) ~[junit-platform-launcher-1.5.2.jar:1.5.2]
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197) ~[junit-platform-launcher-1.5.2.jar:1.5.2]
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211) ~[junit-platform-launcher-1.5.2.jar:1.5.2]
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191) ~[junit-platform-launcher-1.5.2.jar:1.5.2]
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:137) ~[junit-platform-launcher-1.5.2.jar:1.5.2]
    at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:89) ~[.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41) ~[.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542) ~[.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770) ~[.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464) ~[.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210) ~[.cp/:na]
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.dgs.soc.service.OrderServiceImpl' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1695) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1253) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    ... 49 common frames omitted

2020-03-23 04:42:24.816  INFO 5281 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
2020-03-23 04:42:24.819  INFO 5281 --- [extShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2020-03-23 04:42:24.846  INFO 5281 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2020-03-23 04:42:24.875  INFO 5281 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

它说 没有可用的 'com.dgs.soc.service.OrderServiceImpl' 类型的限定 bean 但是,正如您在前面的代码中看到的那样,该 bean 存在并且它由 @Service 允许自动装配的注解!!!

在这个项目中定义了一个由 @RestController 注释的类,它公开了 API。如果进入此类,我尝试自动装配相同的服务类,如下所示:

@Description(value = "Resource layer for handling REST requests.")
@RestController
@RequestMapping("api")
public class ExcelResource {

    @Autowired
    OrderServiceImpl orderService;

    .......................................................
    .......................................................
    .......................................................
}

现在我尝试将应用程序作为 Spring Boot Application 执行,我遇到了同样的问题:

***************************
APPLICATION FAILED TO START
***************************

Description:

Field orderService in com.dgs.soc.excelapi.resources.ExcelResource required a bean of type 'com.dgs.soc.service.OrderServiceImpl' 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.dgs.soc.service.OrderServiceImpl' in your configuration.

com.dgs.soc.service.OrderServiceImpl bean 仍然存在,并且由 @Service 注释。

为什么我会收到这个问题?我错过了什么?我该如何尝试解决这个问题?我在想我有一些参考问题或类似的问题,但我不知道

EDIT-1:@ComponentScan("com.dgs.soc.service") 放在我的 Application 类的顶部似乎可以工作,但我有一些疑问!!! p>

现在这是我的 Application 类:

package com.dgs.soc.excelapi;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan("com.dgs.soc.service")
public class Application extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(Application.class);
    }
}

它可以工作,但它应该在没有 ** @ComponentScan("com.dgs.soc.service")** 注释的情况下也可以工作,因为这个类是由 @SpringBootApplication 注释的,就像你可以在这里阅读:

https://docs.spring.io/spring-boot/docs/2.1.12.RELEASE/reference/html/using-boot-using-springbootapplication-annotation.html

自动启用@ComponentScan:对应用所在包进行@Component扫描(见最佳实践)

所以应用程序位于 com.dgs.soc.excelapi 中,理论上我希望组件扫描也必须在没有 @ComponentScan的明确定义的情况下正常工作>

为什么?有什么想法吗?

【问题讨论】:

  • 您的Application 课程在哪个包中?一般来说,spring 只会自动扫描Applicationclass 所在的包及其任何子包。尝试在 Application 类上添加要扫描的显式包列表。
  • 可能是你没有Spring loader扫描我们有你的serviceClass实现的那个包,可能你可以尝试使用@ComponentScan("")
  • @Setu 我的应用程序类在“com.dgs.soc.excelapi”包中
  • @AndreaNobili 在这种情况下,您肯定需要明确扫描软件包。您可以在 Spring Boot 应用程序类上使用 ComponentScan 注释或在 SpringBootApplication 注释上提供 scanBasePackages 属性。
  • @Setu 以这种方式工作,我在原始帖子的末尾添加了一些新信息,因为理论上它也应该在不使用 ComponentScan 的情况下工作,因为我正在使用SpringBootApplication 注释。我错过了什么?

标签: java spring spring-boot spring-annotations


【解决方案1】:

您的问题的答案是您没有正确的包结构供 spring-boot 自动扫描以获取您的服务类。

SpringBootApplication 注释只启用了扫描它所在的包及其子包。

如果您在com.acme.app 包中有SpringBootApplication 类,那么所有带有spring boot 注释的类都将在包com.acme.app 及其任何子包(即com.acme.app.servicescom.acme.app.controllers 等)中进行扫描。但是如果你有一个包com.acme.services,那么任何弹簧注释都不会从这个包中自动扫描。

你有两个选择;

  • 您可以修改包结构以允许 spring-boot 自动扫描所有注释。在您的情况下,将您的 Application 课程从 com.dgs.soc.excelapi 移动到 com.dgs.soc。或者您可以移动所有其他包,即com.dgs.soc.excelapi 下的服务。

  • 您可以使用SpringBootApplication 注释上的@ComponentScan 或scanBasePackages 属性显式列出要扫描的包。

【讨论】:

  • 啊,好吧,你有什么更简洁的解决方案?
  • 老兄,你节省了我的时间。谢谢。
【解决方案2】:

尝试将@ComponentScan注解放在主应用程序类的顶部

@ComponentScan("base.package.name")

【讨论】:

  • 以这种方式工作,但理论上它也必须在不使用 ComponentScan 注释的情况下工作,因为我在我的 Application 类上使用 SpringBootApplication 注释.我在原始帖子的末尾添加了一些附加信息。我错过了什么?
  • 如果你想让它在没有@ComponentScan 的情况下工作,那么所有其他包必须是 com.dgs.soc.excelapi ex 的子包。 com.dgs.soc.excelapi.service、com.dgs.soc.excelapi.dao 或所有类可以与主应用程序类在同一个包中
【解决方案3】:

问题如下:

您的应用程序类在包“com.dgs.soc.excelapi”中

@SpringBootApplication 扫描 该包及其所有子包 以查找 @Services/@Components/@Repositories。

您将所有服务放在完全不同的包中(“com.dgs.soc.service”),所以 Spring Boot 不会找到它们。因此@ComponentScan 注释有效。

修复:重新排序您的包结构。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-17
    • 2019-07-30
    • 2022-11-10
    • 2018-12-13
    • 2018-10-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-13
    相关资源
    最近更新 更多