Spring @ComponentScan没有检测到REST控制器

时间:2019-06-29 19:39:15

标签: java spring spring-boot gradle

在StackOverflow上搜索了各种类似的问题之后,我确定大多数遭受此问题困扰的人都无法正确扫描其控制器所在的模块。一些解决方案要求将要扫描的文件与应用程序(有效)组合到同一模块中,但是我不想移动任何.java文件。相反,我想使@ComponentScan工作。

我具有以下项目结构

Project
      |
      settings.gradle
      build.gradle
      module1
            |
            src/main/java/com.test.application
            |                                |
            |                                Application.java
            |                                SwaggerConfig.java
            build.gradle
      module2
            |
            src/main/java/com.test.service
            |                            |
            |                            Service.java
            |                            Controller.java
            build.gradle

Application.java

@SpringBootApplication
@ComponentScan("com.test")
public class Application {

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

请注意,我正在组件扫描中扫描com.test。我在@ComponentScan documentation(或StackOverflow)上找不到任何暗示我在错误使用@ComponentScan的东西。

Controller.java

@RestController
@RequestMapping("/test")
public class GearParsingController {
  private SomeService someService;

  @Autowired
  public SomeController(SomeService someService) {
    this.someService = someService;
  }

  @GetMapping("/path")
  public ResponseEntity<String> getSomeService() {
    return new ResponseEntity<String>("Default message", HttpStatus.OK);
  }
}

项目build.gradle

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.6.RELEASE")
    }
}

subprojects {
    repositories {
        mavenCentral()
    }

    apply plugin: 'java'
    apply plugin: 'idea'
    apply plugin: 'org.springframework.boot'
    apply plugin: 'io.spring.dependency-management'
}

module1 build.gradle

dependencies {
    implementation project(':module2')

    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.1.6.RELEASE'
}

module2 build.gradle

dependencies {
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.1.6.RELEASE'

    testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0-RC2'
}

当我尝试访问位于localhost:8080/test/path的端点时,我遇到了:

{
    "timestamp": "2019-06-29T19:19:52.275+0000",
    "status": 404,
    "error": "Not Found",
    "message": "No message available",
    "path": "/test/path"
}

在调试模式下启动程序时,得到以下输出:

2019-06-29 13:58:58.345  INFO 8272 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2019-06-29 13:58:58.387  INFO 8272 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2019-06-29 13:58:58.387  INFO 8272 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.21]
2019-06-29 13:58:58.522  INFO 8272 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2019-06-29 13:58:58.522 DEBUG 8272 --- [           main] o.s.web.context.ContextLoader            : Published root WebApplicationContext as ServletContext attribute with name [org.springframework.web.context.WebApplicationContext.ROOT]
2019-06-29 13:58:58.522  INFO 8272 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1786 ms
2019-06-29 13:58:58.544 DEBUG 8272 --- [           main] o.s.b.w.s.ServletContextInitializerBeans : Mapping filters: characterEncodingFilter urls=[/*], hiddenHttpMethodFilter urls=[/*], formContentFilter urls=[/*], requestContextFilter urls=[/*]
2019-06-29 13:58:58.545 DEBUG 8272 --- [           main] o.s.b.w.s.ServletContextInitializerBeans : Mapping servlets: dispatcherServlet urls=[/]
2019-06-29 13:58:58.583 DEBUG 8272 --- [           main] o.s.b.w.s.f.OrderedRequestContextFilter  : Filter 'requestContextFilter' configured for use
2019-06-29 13:58:58.583 DEBUG 8272 --- [           main] .s.b.w.s.f.OrderedHiddenHttpMethodFilter : Filter 'hiddenHttpMethodFilter' configured for use
2019-06-29 13:58:58.583 DEBUG 8272 --- [           main] s.b.w.s.f.OrderedCharacterEncodingFilter : Filter 'characterEncodingFilter' configured for use
2019-06-29 13:58:58.584 DEBUG 8272 --- [           main] o.s.b.w.s.f.OrderedFormContentFilter     : Filter 'formContentFilter' configured for use
2019-06-29 13:58:58.896 DEBUG 8272 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : 5 mappings in 'requestMappingHandlerMapping'
2019-06-29 13:58:58.990  INFO 8272 --- [           main] pertySourcedRequestMappingHandlerMapping : Mapped URL path [/v2/api-docs] onto method [public org.springframework.http.ResponseEntity<springfox.documentation.spring.web.json.Json> springfox.documentation.swagger2.web.Swagger2Controller.getDocumentation(java.lang.String,javax.servlet.http.HttpServletRequest)]
2019-06-29 13:58:59.045 DEBUG 8272 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Patterns [/**/favicon.ico] in 'faviconHandlerMapping'
2019-06-29 13:58:59.128  INFO 8272 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2019-06-29 13:58:59.146 DEBUG 8272 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : ControllerAdvice beans: 0 @ModelAttribute, 0 @InitBinder, 1 RequestBodyAdvice, 1 ResponseBodyAdvice
2019-06-29 13:58:59.257 DEBUG 8272 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Patterns [/webjars/**, /**] in 'resourceHandlerMapping'
2019-06-29 13:58:59.263 DEBUG 8272 --- [           main] .m.m.a.ExceptionHandlerExceptionResolver : ControllerAdvice beans: 0 @ExceptionHandler, 1 ResponseBodyAdvice
2019-06-29 13:58:59.442  INFO 8272 --- [           main] d.s.w.p.DocumentationPluginsBootstrapper : Context refreshed
2019-06-29 13:58:59.481  INFO 8272 --- [           main] d.s.w.p.DocumentationPluginsBootstrapper : Found 1 custom documentation plugin(s)
2019-06-29 13:58:59.519  INFO 8272 --- [           main] s.d.s.w.s.ApiListingReferenceScanner     : Scanning for api listing references

所以,我的问题是:为什么ComponentScan无法检测到我的REST控制器?

4 个答案:

答案 0 :(得分:1)

以这种方式制作文件:

项目build.gradle (已将spring插件应用程序删除到所有模块项目中)

@app.route('/hook/reservation', methods=['POST'])
def fn_th_reservation():

    task_attributes = json.loads(request.form['TaskAttributes'])
    channel_sid = task_attributes["channelSid"]
    worker_sid = request.form['WorkerSid']
    reservation_sid = request.form["ReservationSid"]
    workspace_sid = request.form["WorkspaceSid"]
    task_sid = request.form["TaskSid"]

    # implement app specific logic here. you can use channel_sid and
    # worker_sid to compare them to a mapping from you database for instance
    is_right_worker = ...

    reservation_status = 'accepted' if is_right_worker else 'rejected'

    client = Client(account_sid, auth_token)
    # accept or reject reservation
    reservation = client.taskrouter.workspaces(workspace_sid) \
        .tasks(task_sid).reservations(reservation_sid) \
        .update(reservation_status=reservation_status)

    print(reservation.worker_name)
    print(reservation.reservation_status)

    return('200')

module1 build.gradle (应用spring插件和bootJar目标)

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.6.RELEASE")
    }
}

subprojects {
    repositories {
        mavenCentral()
    }

    apply plugin: 'java'
    apply plugin: 'idea'
}

module2 build.gradle (添加了jar目标)

dependencies {
    implementation project(':module2')

    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.1.6.RELEASE'
}

apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

bootJar {
    baseName = 'module1'
    version = '0.0.1-SNAPSHOT'
}

settings.gradle

dependencies {
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.1.6.RELEASE'
}

jar {
    baseName = 'module2'
    version = '0.0.1-SNAPSHOT'
}

要点是,我们希望将第二个模块构建为普通jar,而将主模块构建为spring boot runnable。通过该设置,只需include 'module1' include 'module2',然后从主项目文件夹中gradle build

答案 1 :(得分:0)

我认为,如果您想从“ com.test”包中提取控制器,请使用@ComponentScan的basePackages选项:

@ComponentScan(basePackages = "com.test")

答案 2 :(得分:0)

您的主应用程序Application.java位于目录com.test.application下,这意味着默认情况下,当springboot应用程序启动时,@SpringBootApplication注释将在packgae {{下查找bean和配置。 1}}。在springboot documentation中,我们指定应将Main应用程序放在根软件包下,以便spring扫描其下的所有内容。

  

@SpringBootApplication是一个方便注释,它添加了所有   以下:

     
      
  • @Configuration将类标记为应用程序上下文的bean定义的源。
  •   
  • @EnableAutoConfiguration告诉Spring Boot根据类路径设置,其他bean和各种属性开始添加bean
      设置。
  •   
  • 通常,您会为Spring MVC应用添加@EnableWebMvc,但是当Spring Boot在服务器上看到spring-webmvc时,它会自动添加它。   类路径。这会将应用程序标记为Web应用程序,
      激活关键行为,例如设置DispatcherServlet。
  •   
  • @ComponentScan告诉Spring在hello包中查找其他组件,配置和服务,以使其
      找到控制器。
  •   

因此,要解决您的问题,请尝试将主应用程序移至软件包的根目录 com.test.application,也可以使用注释com.test来指定需要扫描哪些所有软件包,如:

@ComponentScan

答案 3 :(得分:0)

根据Spring Boot约定,控制器必须位于com.test.controller包中。