@Autowired não está funcionando, e não sabemos o porquê. O serviço e o controlador estão em módulos e pacotes diferentes, mas presumimos que isso não importa. Podemos instanciar manualmente o serviço, para que o módulo controlador consiga "ver" o módulo comum.
A execução do aplicativo resulta no seguinte erro:
Parameter 0 of constructor in com.xx.campaign_api.controller.MyController required a bean of type 'com.xx.campaign.common.service.MyService' that could not be found.
Temos um projeto multimódulo spring boot 3.4.2 com o seguinte pom:
<project xxx
<groupId>org.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>
no módulo api temos um controlador rest como este:
package com.xx.campaign_api.controller;
import com.xx.campaign.common.service.MyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.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();
}
}
O serviço se parece com isto:
package com.xxx.campaign.common.service;
import org.springframework.stereotype.Service;
@Service
public class MyServiceImpl implements MyService {
@Override
public String test() {
return "test3";
}
}
package com.xxx.campaign.common.service;
public interface MyService {
public String test();
}
A classe principal se parece com isso:
package com.xx.campaign_api;
@SpringBootApplication
public class CampaignApiApplication {
public static void main(String[] args) {
SpringApplication.run(CampaignApiApplication.class, args);
}
}
no pom do módulo controlador, temos:
<dependency>
<groupId>xx</groupId>
<artifactId>campaign-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
Eu também tentei isso:
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;
}
Mas este aplicativo não inicia com este erro:
Web application could not be started as there was no org.springframework.boot.web.servlet.server.ServletWebServerFactory bean defined in the context.
O problema é que seu serviço genérico e sua API têm pacotes diferentes e não compartilham um superpacote comum (bem, eles compartilham na forma de
com.xx
).Em seguida, não coloque múltiplas
@SpringBootApplication
anotações no seu código que só resultarão em erros. Então remova o@SpringBootApplication
da@RestController
classe.Você pode fazer três coisas para corrigir isso.
@SpringBootApplication
classe anotada (aquela commain
into)com.xx
e comece a partir daí.scanBasePackages
ao seu@SpringBootApplication
, embora isso funcione para detectar componentes, se você tiver coisas como entidades etc. lá, ele não os considerará.@SpringBootApplication
para um pacote compartilhado de nível superior.Mover a
@SpringBootApplication
classe anotadaEmbora isso provavelmente funcione, você pode correr o risco de escanear muito, dependendo do nome do arquivo
xx
.Adicionar
scanBasePackages
à@SpringBootApplication
anotaçãoEmbora isso funcione para detectar componentes como serviços, repositórios etc. Se você tiver coisas como entidades ou repositórios Spring Data nesses pacotes, isso não funcionará. Para fazer isso funcionar, você teria que adicionar anotações adicionais como
@EntityScan
e@EnableJpaRepositories
(ou qualquer tecnologia de persistência que você use). Adicionar todas essas anotações é trabalhoso e pode levar a surpresas, pois partes da configuração automática não são mais configuração automática.Reestruture pacotes e mova
@SpringBootApplication
classes.Agora eu sugeriria fazer isso e renomear seu
com.xx.campaign_api
pacote paracom.xx.campaign.api
. Isso o tornaria um subpacote decom.xx.campaign
. Agora, ao colocar oCampaignApiApplication
nocom.xx.campaign
pacote, ele detectará automaticamente tudo dentrocom.xx.campaign
e todos os seus subpacotes. Sem adicionar nenhuma anotação adicional.Este último também é o recomendado pelos desenvolvedores do Spring Boot e mencionado no guia de referência do Spring Boot.
A solução fornecida pela Geba foi a seguinte:
Agora tudo funciona!