web-dev-qa-db-fra.com

Le nom du bean spécifié par l'annotation est en conflit avec la définition de bean existante non compatible

J'ai un problème avec certaines définitions de bean Spring. J'ai quelques fichiers XML de contexte qui sont chargés par ma méthode main (), et les deux contiennent presque exclusivement une balise. Lorsque ma méthode principale démarre, j'obtiens cette erreur de Spring:

Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'converterDAO' for bean class [my.package.InMemoryConverterDaoImpl] conflicts with existing, non-compatible bean definition of same name and class [my.other.package.StaticConverterDAOImpl]

Les deux classes DAO sont annotées de la manière suivante:

@Repository("converterDAO")
public class StaticConverterDAOImpl implements ConverterDAO {
...
}

Le DAO en mémoire possède également l'annotation @Repository ("converterDAO"). Le dao est référencé dans d'autres classes comme celle-ci:

...
private @Autowired @Qualifier("converterDAO") ConverterDAO converterDAO;
...

Je souhaite qu'un DAO prenne le pas sur la définition de l'autre, ce qui, comme je l'ai toujours compris, était l'une des principales raisons d'utiliser un cadre DI pour la première fois. Je fais cela avec des définitions XML depuis des années et je n’ai jamais eu de problèmes. Mais pas avec les analyses de composants et les définitions de beans annotées? Et qu'est-ce que Spring veut dire quand il est dit qu'ils ne sont pas "compatibles"? Ils implémentent la même interface et sont automatiquement connectés à des champs de ce type. Pourquoi diable ne sont-ils pas compatibles?

Quelqu'un peut-il me fournir un moyen pour qu'un bean annoté et analysé par composant en remplace un autre?

-Mike

40
user1283068

Dans un fichier XML, il existe une séquence de déclarations et vous pouvez remplacer une définition précédente par une nouvelle. Lorsque vous utilisez des annotations, il n'y a pas de notion de avant ou après . Tous les haricots sont au même niveau. Vous avez défini deux beans avec le même nom et Spring ne sait pas lequel choisir. 

Donnez-leur un nom différent ( staticConverterDAO , inMemoryConverterDAO par exemple), créez un alias dans le fichier XML Spring ( theConverterDAO par exemple) et utilisez cet alias lors de l'injection du convertisseur:

@Autowired @Qualifier("theConverterDAO")
30
JB Nizet

J'ai eu un problème similaire, avec deux bibliothèques de jar (app1 et app2) dans un projet. Le bean "BeanName" est défini dans app1 et est étendu dans app2 et le bean redéfini avec le même nom.

En app1:

package com.foo.app1.pkg1;

@Component("BeanName")
public class Class1 { ... }

Dans app2:

package com.foo.app2.pkg2;

@Component("BeanName")
public class Class2 extends Class1 { ... }

Cela provoque l'exception ConflictingBeanDefinitionException lors du chargement de l'applicationContext en raison du même nom de bean.

Pour résoudre ce problème, dans le fichier de configuration Spring applicationContext.xml:

<context:component-scan base-package="com.foo.app2.pkg2"/>
<context:component-scan base-package="com.foo.app1.pkg1">
    <context:exclude-filter type="assignable" expression="com.foo.app1.pkg1.Class1"/>
</context:component-scan>

Ainsi, la Classe1 est exclue pour être automatiquement analysée par composant et assignée à un bean, évitant ainsi le conflit de noms.

29
user1897261

J'ai eu un problème similaire avec Spring 4.x avec @RestController. Deux paquets différents avaient une classe du même nom ...

package com.x.catalog

@RestController
public class TextureController {
...

package com.x.cms
@RestController
public class TextureController {
...

La solution était facile ...

package com.x.catalog

@RestController("CatalogTextureController")
public class TextureController {
...

package com.x.cms
@RestController("CMSTextureController")
public class TextureController {
...

Le problème semble être que l'annotation est auto-câblée et prend le nom de la classe par défaut. Lui attribuer un nom explicite dans l'annotation @RestController vous permet de conserver les noms de classe.

18
Ian Newland

J'ai eu un problème similaire, et c'est parce qu'un de mes haricots a été déplacé vers un autre répertoire récemment. Je devais faire un "build clean" en supprimant le répertoire build/classes/Java et le problème est parti. (Le message d'erreur avait les deux chemins de fichiers différents en conflit, bien que je sache qu'il ne devrait plus en exister en réalité.)

5
Rock Lee

J'ai fait face à ce problème lorsque j'ai importé deux projets dans l'espace de travail. Il a en quelque sorte créé un fichier JAR différent afin que nous puissions supprimer les fichiers JAR et les fichiers de classe, puis reconstruire le projet pour obtenir les dépendances appropriées.

0
Roopal

J'ai aussi eu un problème similaire. J'ai construit le projet à nouveau et le problème a été résolu. 

La raison en est qu’il existe déjà dans un fichier des séquences définies pour les noms de beans spécifiés par Annotation. Lorsque nous modifions le nom du bean et que nous essayons d'exécuter l'application, Spring ne peut pas identifier lequel choisir. C'est pourquoi il montre cette erreur.

Dans mon cas, j'ai supprimé la classe de beans précédente du projet et ajouté le même nom de bean à une nouvelle classe de beans. Donc, Spring a la définition précédente de la classe de bean supprimée dans un fichier et en conflit avec la classe nouvellement ajoutée lors de la compilation. Donc, si vous faites un «build clean», les définitions précédentes des classes de beans seront supprimées et la compilation aboutira.

Scénario:

Je travaille sur un projet multi-module Gradle. 

Les modules sont:

- core, 
- service,
- geo,
- report,
- util and
- some other modules.

Nous avons donc principalement préparé un module [ locationRecommendHttpClientBuilder ] dans geo module. 

Code Java:

import org.springframework.stereotype.Component

@Component("locationRecommendHttpClientBuilder")
class LocationRecommendHttpClientBuilder extends PanaromaHttpClientBuilder {
    @Override
    PanaromaHttpClient buildFromConfiguration() {
        this.setURL(PanaromaConf.getInstance().getString("locationrecommend.url"))
        this.setMethod(PanaromaConf.getInstance().getString("locationrecommend.method"))
        this.setProxyHost(PanaromaConf.getInstance().getString("locationrecommend.proxy.Host"))
        this.setProxyPort(PanaromaConf.getInstance().getInt("locationrecommend.proxy.port", 0))
        return super.build()
    }
}

application-context.xml

<bean id="locationRecommendHttpClient"
      class="au.co.google.panaroma.platform.logic.impl.PanaromaHttpClient"
      scope="singleton" factory-bean="locationRecommendHttpClientBuilder"
      factory-method="buildFromConfiguration" />

Ensuite, il est décidé d’ajouter ce composant dans core module.

Un ingénieur a le code précédent pour le module geo puis il a pris le dernier module de core mais il a oublié de prendre le dernier module geo .

Donc, le composant [ locationRecommendHttpClientBuilder ] a été multiplié par deux dans son projet et il obtenait l'erreur suivante.

Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'LocationRecommendHttpClientBuilder' for bean class [au.co.google.app.locationrecommendation.builder.LocationRecommendHttpClientBuilder] conflicts with existing, non-compatible bean definition of same name and class [au.co.google.panaroma.platform.logic.impl.locationRecommendHttpClientBuilder]

Procédure de solution:

Après avoir retiré le composant du module geo , le composant [ locationRecommendHttpClientBuilder ] est uniquement disponible dans core module. Donc, il n'y a pas de situation conflictuelle. Le problème est résolu de cette façon.

0
SkyWalker