J'ai deux modules Maven. La première, appelée "application", contient la classe d'application spring boot
Qui ne contient que ces lignes:
package org.example.application;
@SpringBootApplication
@ComponentScan({"org.example.model", "org.example"})
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
Dans le même module et package Maven, org.example.application
, J'ai un RestController
qui utilise un Component
qui à son tour utilise les composants de l'autre module Maven décrit ci-dessous.
L'autre module Maven, appelé "modèle", contient les composants spring boot
(Référentiels crud, entités, etc.). Toutes ces classes sont sous la même structure de package que le premier module Maven (org.example
) Mais dans des sous-packages de celui-ci, comme org.example.model.entities
, org.example.model.repositories
Etc.
Ainsi, le flux est comme ceci:
Module Maven application
dans le package org.example:SpringBootApplication -> RestController -> MyComponent
Et les composants qui doivent être câblés automatiquement dans MyComponent
sont ceux du module Maven model
sous le package org.example.model
.
Mais quand je démarre l'application, je reçois juste l'erreur:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field myRepository in org.example.MyComponent required a bean of type 'org.example.model.repositories.MyRepository' that could not be found.
Action:
Consider defining a bean of type 'org.example.model.repositories.MyRepository' in your configuration.
org.example.model.repositories.MyRepository
Existe dans le module Maven "modèle" mais ne peut pas être trouvé par la classe SpringBootApplication!
Comme vous pouvez le voir, j'ai essayé de définir explicitement les composants de numérisation pour: @ComponentScan({"org.example.model", "org.example"})
mais cela ne semble pas aider.
Alors qu'est-ce que j'ai fait de mal?
La première chose que vous devriez vous demander est: pourquoi déclarez-vous @ComponentScan
Alors que l'un des objectifs de @SpringBootApplication
Est (entre autres) de permettre l'analyse des composants?
De documentation Spring Boot :
L'annotation
@SpringBootApplication
Équivaut à utiliser@Configuration
,@EnableAutoConfiguration
Et@ComponentScan
Avec leurs attributs par défaut
Notez que lorsque dans la classe de votre application Spring Boot, vous déclarez @ComponentScan
Pour spécifier une valeur comme basePackages
, il remplace le basePackages
utilisé par défaut par @SpringBootApplication
qui est le package actuel où réside la classe. Donc, pour avoir comme package de base le package de la classe Spring Boot Application et les packages supplémentaires qui manquaient, vous devez les définir explicitement.
De plus, basePackages
est récursif. Donc, pour activer l'analyse à la fois pour les classes localisées dans les packages "org.example"
Et "org.example.model"
, Spécifier "org.example"
Suffit car "org.example.model"
En est un sous-package.
Essayez ça:
@SpringBootApplication(scanBasePackages={"org.example"})
Ou bien :
@SpringBootApplication
@ComponentScan("org.example")
Lorsque vous concevez la disposition de votre application Spring Boot, vous avez deux cas:
1) cas (à privilégier) où vous utilisez une disposition de package qui fournit la configuration automatique de Spring Boot avec une configuration nulle.
Pour résumer: si vos classes annotées avec des stéréotypes Spring Bean: @Component
, @Repositories
, @Repositories
, ... sont situées dans le même package ou un sous-package du Spring Boot Application class, déclarant seulement @SpringBootApplication
Est tout ce dont vous avez besoin.
2) cas (à éviter) où vous n'utilisez pas une disposition de package qui fournit la configuration automatique de Spring Boot avec une configuration nulle.
Cela signifie généralement que vous avez des classes candidates à analyser qui ne sont pas dans le package (ou sous-package) de votre classe annoté avec @SpringBootApplication
.
Dans ce cas, vous ajoutez l'attribut scanBasePackages
ou ajoutez @ComponentScan
Pour spécifier les packages à analyser.
Mais en plus, si vos référentiels ne se trouvent pas dans un package ou sous-package de votre classe annoté avec @SpringBootApplication
, Quelque chose d'autre doit être déclaré tel que: @EnableJpaRepositories(="packageWhereMyRepoAreLocated")
Voici la documentation sur cette partie (c'est moi qui souligne):
80.3 Utiliser les référentiels de données Spring
Spring Data peut créer des implémentations d'interfaces @Repository de différentes saveurs. Spring Boot gère tout cela pour vous, tant que ces @Repositories sont inclus dans le même package (ou un sous-package) de votre classe @EnableAutoConfiguration.
Pour de nombreuses applications, tout ce dont vous avez besoin est de placer les bonnes dépendances Spring Data sur votre chemin de classe (il existe un spring-boot-starter-data-jpa pour JPA et un spring-boot-starter-data-mongodb pour Mongodb) et en créer des interfaces de référentiel pour gérer vos objets @Entity. Des exemples sont dans l'exemple JPA et l'exemple Mongodb.
Spring Boot essaie de deviner l'emplacement de vos définitions @Repository, en fonction de la @EnableAutoConfiguration qu'il trouve. Pour obtenir plus de contrôle, utilisez l'annotation @EnableJpaRepositories (de Spring Data JPA).
1) cas (à privilégier) où vous utilisez une disposition de package qui fournit la configuration automatique de Spring Boot avec une configuration nulle.
Avec une application Spring Boot déclarée dans le package org.example
, Et toutes les classes de bean (référentiels inclus) déclarées dans le même package ou un sous-package de org.example
, La déclaration suivante suffit pour le Spring Application de démarrage:
package org.example;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
Les référentiels peuvent être situés dans le package org.example.repository
Tels que:
package org.example.repository;
@Repository
public interface FooRepository extends JpaRepository<Foo, Long>, { }
et
package org.example.repository;
@Repository
public interface BarRepository extends JpaRepository<Bar, Long>, { }
Les contrôleurs peuvent être situés dans le package org.example.controller
:
package org.example.controller;
@RestController
@RequestMapping("/api/foos")
public class FooController {...}
et donc pour ...
2) cas (à éviter) où vous n'utilisez pas une disposition de package qui fournit la configuration automatique de Spring Boot avec une configuration nulle.
Avec une application Spring Boot déclarée dans le package org.example.application
Et pas toutes les classes de bean (référentiels inclus) déclarées dans le même package ou un sous-package de org.example.application
, La déclaration suivante sera requise pour l'application Spring Boot:
package org.example.application;
@SpringBootApplication(scanBasePackages= {
"org.example",
"org.thirdparty.repository"})
@EnableJpaRepositories("org.thirdparty.repository")
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
Et les classes de haricots pourraient être comme ci-dessous.
Les référentiels qui peuvent provenir d'un JAR externe peuvent être situés dans le package org.thirdparty.repository
Tels que:
package org.thirdparty.repository;
@Repository
public interface FooRepository extends JpaRepository<Foo, Long>, { }
et
package org.thirdparty.repository;
@Repository
public interface BarRepository extends JpaRepository<Bar, Long>, { }
Les contrôleurs peuvent être situés dans le package org.example.controller
:
package org.example.controller
@RestController
@RequestMapping("/api/foos")
public class FooController {...}
et donc pour ...
Conclusion : la définition de l'application Spring Boot dans le package de base de votre espace de noms est vraiment encouragée pour rendre la configuration Spring Boot aussi simple que possible.