Spring引导在子包中找不到Service实现

问题描述 投票:0回答:1

我有一个带有REST控制器的Spring启动应用程序,一些服务和一些存储库。但是当我尝试启动时,Spring启动说:

java.lang.IllegalStateException: Failed to load ApplicationContext
at 

org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
    at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:44)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:283)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:173)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:128)
    at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:203)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:155)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'terminController': Unsatisfied dependency expressed through field 'terminService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'eu.wiegandt.toepferportal.services.TerminService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

我有以下包结构:

eu.wiegandt.toepferportal.ToepferportalApplication
eu.wiegandt.toepferportal.controllers.TerminController
eu.wiegandt.toepferportal.services.TerminService
eu.wiegandt.toepferportal.services.TerminServiceImpl

当我理解Spring Boot(1.5.10)之后,它应该搜索从我的应用程序传出的所有子包中的bean。那么为什么我会得到这个例外呢?

这是我的课程:

应用:

package eu.wiegandt.toepferportal;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

@SpringBootApplication
@EnableScheduling
public class ToepferportalApplication {

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

  @Bean
  public Module javaTimeModule() {
    return new JavaTimeModule();
  }

  @Bean
  public Module jdk8Module() {
    return new Jdk8Module();
  }
}

控制器:

package eu.wiegandt.toepferportal.controllers;

import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import eu.wiegandt.toepferportal.entities.Termin;
import eu.wiegandt.toepferportal.services.TerminService;

@RestController
@RequestMapping("/termine")
public class TerminController {
  @Autowired
  private TerminService terminService;

  @RequestMapping(method = RequestMethod.POST)
  public Termin createTermin(@RequestBody final Termin termin) {
    return terminService.saveOrUpdate(termin);
  }

  @RequestMapping(method = RequestMethod.GET)
  public List<Termin> getAll() {
    return terminService.listAll();
  }

  @ExceptionHandler
  void handleIllegalArgumentException(final IllegalArgumentException e,
      final HttpServletResponse response) throws IOException {

    response.sendError(HttpStatus.BAD_REQUEST.value());

  }
}

服务:

package eu.wiegandt.toepferportal.services;

import java.time.LocalDate;
import java.util.List;
import eu.wiegandt.toepferportal.entities.Termin;

public interface TerminService {

  public void delete(Long id);

  public List<Termin> findTerminForDay(LocalDate day);

  public Termin getById(Long id);

  public List<Termin> listAll();

  public Termin saveOrUpdate(Termin termin);

}

服务Impl。:

package eu.wiegandt.toepferportal.services;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import eu.wiegandt.toepferportal.entities.Termin;
import eu.wiegandt.toepferportal.repositories.TerminRepository;

@Service
public class TerminServiceImpl implements TerminService {
  @Autowired
  private TerminRepository terminRepository;

  @Override
  public void delete(final Long id) {
    terminRepository.delete(id);
  }

  @Override
  public List<Termin> findTerminForDay(final LocalDate aDay) {
    return terminRepository.findByBeginDate(aDay);
  }

  @Override
  public Termin getById(final Long id) {
    return terminRepository.findOne(id);
  }

  @Override
  public List<Termin> listAll() {
    final List<Termin> termine = new ArrayList<>();
    terminRepository.findAll().forEach(termine::add);
    return termine;
  }

  @Override
  public Termin saveOrUpdate(final Termin termin) {
    return terminRepository.save(termin);
  }

}

用我开始整个事情的测试:

package eu.wiegandt.toepferportal;

import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import com.fasterxml.jackson.databind.ObjectMapper;
import eu.wiegandt.toepferportal.controllers.TerminController;
import eu.wiegandt.toepferportal.entities.Termin;

@RunWith(SpringRunner.class)
@WebMvcTest(TerminController.class)
@AutoConfigureMockMvc(secure = false)
public class TerminControllerTest {
  @Autowired
  private MockMvc mvc;


  @Test
  public void testGetAll() throws Exception {
    final List<Termin> testTermine = new ArrayList<>();

    final ObjectMapper objectMapper = new ObjectMapper();
    mvc.perform(get("/termine").accept(MediaType.APPLICATION_JSON_UTF8)).andExpect(status().isOk())
        .andExpect(content().json(objectMapper.writeValueAsString(testTermine)));
  }
}

我的maven pom:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>eu.wiegandt</groupId>
    <artifactId>toepferportal</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>toepferportal</name>
    <description>A application to manag Termine for the TöWe.</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.10.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <test.db.root.pw>root</test.db.root.pw>
        <test.db.name>toepferplaner-test</test.db.name>
        <test.db.user.name>toepferplaner</test.db.user.name>
        <test.db.user.pw>toepferplaner</test.db.user.pw>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jersey</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.mariadb.jdbc</groupId>
            <artifactId>mariadb-java-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.restdocs</groupId>
            <artifactId>spring-restdocs-mockmvc</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>0.23.0</version>
                <configuration>
                    <imageName>${project.groupId}/${project.artifactId}</imageName>
                    <tag>${project.version}</tag>
                    <dockerDirectory>src/main/docker</dockerDirectory>
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                    </resources>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>integration-test</goal>
                            <goal>verify</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <environmentVariables>
                        <TOEPFERPLANER_DB_HOST>localhost</TOEPFERPLANER_DB_HOST>
                        <TOEPFERPLANER_DB_PORT>${it-database.port}</TOEPFERPLANER_DB_PORT>
                        <TOEPFERPLANER_DB_DATABASE>${test.db.name}</TOEPFERPLANER_DB_DATABASE>
                        <TOEPFERPLANER_DB_USER>${test.db.user.name}</TOEPFERPLANER_DB_USER>
                        <TOEPFERPLANER_DB_PASSWORD>${test.db.user.pw}</TOEPFERPLANER_DB_PASSWORD>
                    </environmentVariables>
                </configuration>
            </plugin>
            <plugin>
                <groupId>io.fabric8</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>0.20.1</version>
                <executions>
                    <execution>
                        <id>prepare-it-database</id>
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>start</goal>
                        </goals>
                        <configuration>
                            <images>
                                <image>
                                    <name>mariadb:latest</name>
                                    <alias>it-database</alias>
                                    <run>
                                        <ports>
                                            <port>it-database.port:3306</port>
                                        </ports>
                                        <env>
                                            <MYSQL_ROOT_PASSWORD>${test.db.root.pw}</MYSQL_ROOT_PASSWORD>
                                            <MYSQL_DATABASE>${test.db.name}</MYSQL_DATABASE>
                                            <MYSQL_USER>${test.db.user.name}</MYSQL_USER>
                                            <MYSQL_PASSWORD>${test.db.user.pw}</MYSQL_PASSWORD>
                                        </env>
                                        <wait>
                                            <log>mysqld: ready for connections</log>
                                            <time>20000</time>
                                        </wait>
                                    </run>
                                </image>
                            </images>
                        </configuration>
                    </execution>
                    <execution>
                        <id>remove-it-database</id>
                        <phase>post-integration-test</phase>
                        <goals>
                            <goal>stop</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/docker</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>


</project>
java spring rest spring-boot
1个回答
0
投票

我可以解决我的问题,在我的测试中用@WebMvcTest(TerminController.class)替换@SpringBootTest

© www.soinside.com 2019 - 2024. All rights reserved.