admin管理员组

文章数量:1299990

@Autowired is not working, and we don't know why. The service and controller are in different modules and packages, but we assume this does not matter. We can manually instantiate the service, so the controller module is able to "see" the common module.

Running the application results in the following error:

Parameter 0 of constructor in com.xx.campaign_api.controller.MyController required a bean of type 'com.xx.campaignmon.service.MyService' that could not be found.

We have multi-module Spring Boot 3.4.2 project with following pom:

<project xxx
    <groupId>.springframework</groupId>
    <artifactId>our-service</artifactId>
    <version>0.1.0</version>
    <packaging>pom</packaging>

    <modules>
        <module>campaign-common</module>
        <module>campaign-api</module>
        <module>campaign-schedule</module>
    </modules>
</project>

in the API module we have a REST controller like this:

package com.xx.campaign_api.controller;
import com.xx.campaignmon.service.MyService;
import .springframework.beans.factory.annotation.Autowired;
import .springframework.web.bind.annotation.GetMapping;
import .springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    private MyService testService;

    @Autowired
    public MyController(MyService testService) {  // THIS LINE IS FAILING
        this.testService = testService;
    }

    @GetMapping("/test")
    public String test() {
    return testService.test();
    }
}

The service looks like this:

package com.xxx.campaignmon.service;
import .springframework.stereotype.Service;

@Service
public class MyServiceImpl implements MyService {
    @Override
    public String test() {
        return "test3";
    }
}
package com.xxx.campaignmon.service;
public interface MyService {
    public String test();
}

The main class looks like this:

package com.xx.campaign_api;
@SpringBootApplication
public class CampaignApiApplication {
    public static void main(String[] args) {
        SpringApplication.run(CampaignApiApplication.class, args);
    }
}

in the pom of the controller module, we have:

    <dependency>
        <groupId>xx</groupId>
        <artifactId>campaign-common</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <scope>compile</scope>
    </dependency>

I also tried this:

package com.xx.campaign_api.controller
@SpringBootApplication(scanBasePackages = "com.xx")
@RestController
public class GaController {

    private MyService myService;

    @Autowired
    public GaController(MyService myService) {  // THIS LINE IS FAILING
        this.myService = myService;
    }

But this app won't start with this error:

Web application could not be started as there was no .springframework.boot.web.servlet.server.ServletWebServerFactory bean defined in the context.

@Autowired is not working, and we don't know why. The service and controller are in different modules and packages, but we assume this does not matter. We can manually instantiate the service, so the controller module is able to "see" the common module.

Running the application results in the following error:

Parameter 0 of constructor in com.xx.campaign_api.controller.MyController required a bean of type 'com.xx.campaignmon.service.MyService' that could not be found.

We have multi-module Spring Boot 3.4.2 project with following pom:

<project xxx
    <groupId>.springframework</groupId>
    <artifactId>our-service</artifactId>
    <version>0.1.0</version>
    <packaging>pom</packaging>

    <modules>
        <module>campaign-common</module>
        <module>campaign-api</module>
        <module>campaign-schedule</module>
    </modules>
</project>

in the API module we have a REST controller like this:

package com.xx.campaign_api.controller;
import com.xx.campaignmon.service.MyService;
import .springframework.beans.factory.annotation.Autowired;
import .springframework.web.bind.annotation.GetMapping;
import .springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    private MyService testService;

    @Autowired
    public MyController(MyService testService) {  // THIS LINE IS FAILING
        this.testService = testService;
    }

    @GetMapping("/test")
    public String test() {
    return testService.test();
    }
}

The service looks like this:

package com.xxx.campaignmon.service;
import .springframework.stereotype.Service;

@Service
public class MyServiceImpl implements MyService {
    @Override
    public String test() {
        return "test3";
    }
}
package com.xxx.campaignmon.service;
public interface MyService {
    public String test();
}

The main class looks like this:

package com.xx.campaign_api;
@SpringBootApplication
public class CampaignApiApplication {
    public static void main(String[] args) {
        SpringApplication.run(CampaignApiApplication.class, args);
    }
}

in the pom of the controller module, we have:

    <dependency>
        <groupId>xx</groupId>
        <artifactId>campaign-common</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <scope>compile</scope>
    </dependency>

I also tried this:

package com.xx.campaign_api.controller
@SpringBootApplication(scanBasePackages = "com.xx")
@RestController
public class GaController {

    private MyService myService;

    @Autowired
    public GaController(MyService myService) {  // THIS LINE IS FAILING
        this.myService = myService;
    }

But this app won't start with this error:

Web application could not be started as there was no .springframework.boot.web.servlet.server.ServletWebServerFactory bean defined in the context.

Share Improve this question edited Mar 2 at 21:58 halfer 20.5k19 gold badges109 silver badges202 bronze badges asked Feb 11 at 15:16 John LittleJohn Little 12.4k26 gold badges111 silver badges184 bronze badges 5
  • Add the package of your CampaignApiApplication. Judging from the controller they are in different packages then the service, leading to the component scanning setup by Spring Boot doesn't see your services. – M. Deinum Commented Feb 11 at 15:21
  • hmm, if the controller and the services have to be in the same package, this is somewhat limiting. I see examples in our anization where they lump all modules into the same package, presumably due to this limitation, which creates a confusing namespace. – John Little Commented Feb 11 at 15:31
  • I nowhere said they need to be in the same package but ideally the share the same main package. If you then place your CampaignApiApplication in that main package it will detect everything. A simple rename of the com.xx.campaign_api.controller package to com.xx.campaign.api and placeing the CampaignApiApplication in the com.xxaign package will resolve it. – M. Deinum Commented Feb 11 at 15:46
  • 1 add this @SpringBootApplication(scanBasePackages = { "com.xx.campaign_api", "com.xxx.campaign"}). If it helps, i could formulate as answer – Geba Commented Feb 11 at 15:53
  • why not let me add it as answer? just curious. maybe i do not get idea of comments/answers. But anyway happy to help) – Geba Commented Feb 11 at 16:02
Add a comment  | 

2 Answers 2

Reset to default 1

The problem is your generic service and your API have different packages and don't really share a common super package (well they do in the form of com.xx).

Next don't put multiple @SpringBootApplication annotations in your code that only will result in errors. So remove the @SpringBootApplication from the @RestController class.

You can do 3 things to fix this.

  1. Move your @SpringBootApplication annotated class (the one with the main into com.xx and start it from there.
  2. Add a scanBasePackages to your @SpringBootApplication, while this work for detecting components if you have things like entities etc. in there it won't consider those.
  3. Restructure your application a little and move your @SpringBootApplication to a top-level shared package.

Move the @SpringBootApplication annotated class

package com.xx;

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

While this will probably work, you might run the risk of scanning too much, depending of the name of the xx.

Add scanBasePackages to the @SpringBootApplication annotation

package com.xx.campaign_api;

@SpringBootApplication(scanBasePackages={
 "com.xx.campaign", "com.xx.campaign_api"
})
public class CampaignApiApplication {
    public static void main(String[] args) {
        SpringApplication.run(CampaignApiApplication.class, args);
    }
}

While this will work for detecting components like services, repositories etc. If you have things like entities or Spring Data repositories in those packages that won't work. To make that work you would have to add additional annotations like @EntityScan and @EnableJpaRepositories (or whatever persistence technology you use). Adding all those annotations is cumbersome and can lead to surprises as parts of auto configuration not being auto config anymore.

Restructure packages and move @SpringBootApplication class.

package com.xx.campaign;

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

Now I would suggest to do this and rename your com.xx.campaign_api package to com.xx.campaign.api. This would make it a sub package of com.xx.campaign. Now when placing the CampaignApiApplication in the com.xx.campaign package it will automatically detect everything in com.xx.campaign and all of its sub-packages. Without adding any additional annotations.

This last one is also the recommended one from the Spring Boot developers and mentioned in the Spring Boot reference guide.

The solution provided by Geba was the following:

package com.campaign_api;

@SpringBootApplication(scanBasePackages = { "com.xx"})
public class CampaignApiApplication {
    public static void main(String[] args) {
        SpringApplication.run(CampaignApiApplication.class, args);
    }
}

Now it all works!

本文标签: