J'ai un référence circulaire dans l'un de mes projets au travail en utilisant spring, que je ne peux pas résoudre et échoue avec l'erreur suivante au démarrage:
'org.springframework.security.authenticationManager': Requested bean is currently in creation: Is there an unresolvable circular reference?
J'ai essayé de recréer le même problème à un niveau plus petit dans un exemple de projet (sans tous les détails de mon projet de travail). Je n'ai cependant pas été en mesure de proposer un scénario plausible où le printemps échoue avec une erreur. Voici ce que j'ai:
public class ClassA {
@Autowired
ClassB classB;
}
public class ClassB {
@Autowired
ClassC classC;
}
@Component
public class ClassC {
@Autowired
ClassA classA;
}
@Configuration
public class Config {
@Bean
public ClassA classA() {
return new ClassA();
}
@Bean
public ClassB classB() {
return new ClassB();
}
}
J'ai un scénario similaire dans mon projet, qui échoue, et je m'attendais à ce que le printemps se plaigne également dans mon exemple de projet. Mais ça marche bien! Quelqu'un peut-il me donner un exemple simple de la façon de casser le ressort avec l'erreur de référence circulaire?
Edit: J'ai résolu le problème en utilisant javax.inject.Provider. La seule autre différence dans les 2 projets était que les annotations utilisées étaient javax.inject.Inject et javax.annotation.ManagedBean à la place de @Autowired et @Component.
Ceci est un vieux fil, donc je suppose que vous avez presque oublié le problème, mais je veux vous informer du mystère. J'ai rencontré le même problème et le mien ne s'est pas éteint comme par magie, j'ai donc dû résoudre le problème. Je vais résoudre vos questions étape par étape.
1. Pourquoi vous ne pouviez pas reproduire l'exception de référence circulaire?
Parce que Spring s'en occupe. Il crée des haricots et les injecte au besoin .
2. Alors pourquoi votre projet produit-il l'exception?
authenticationManager
avaient la référence circulaire3. Alors pourquoi l'exception a-t-elle disparu mystiquement?
L'exception peut ou non se produire dépend de l'ordre de création des beans. Je suppose que vous avez fait plusieurs *context.xml
fichiers ou plus, et chargez-les avec config quelque chose comme ci-dessous dans web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:*-context.xml</param-value>
</context-param>
Les fichiers xml seront chargés par la classe XmlWebApplicationContext
et l'ordre de chargement des fichiers n'est pas garanti. Il charge simplement les fichiers du système de fichiers. Le problème est là. Il n'y a pas de problème si la classe charge d'abord le fichier de contexte d'application, car vos beans sont déjà créés lorsqu'ils sont utilisés pour l'injection de construction de Spring Security. Mais, s'il charge d'abord le fichier de contexte Spring Security, le problème de référence circulaire se produit, car Spring essaie d'utiliser vos beans dans l'injection de constructeur avant qu'ils aient été créés.
4. Comment résoudre le problème?
Forcez l'ordre de chargement des fichiers xml. Dans mon cas, j'ai chargé le fichier xml de contexte de sécurité à la fin du fichier de contexte d'application en utilisant <import resource="">
. L'ordre de chargement peut être modifié en fonction des environnements, même avec le même code, je recommande donc de définir l'ordre pour supprimer les problèmes potentiels.
Vous pouvez utiliser @Lazy
pour indiquer que le haricot est créé paresseusement, rompant ainsi le vif cycle de câblage automatique.
L'idée est qu'un haricot sur le cycle pourrait être instancié en tant que proxy, et juste au moment où il est vraiment nécessaire, il sera initialisé. Cela signifie que tous les beans sont initialisés sauf celui qui est un proxy. L'utiliser pour la première fois déclenchera la configuration et comme les autres beans sont déjà configurés, ce ne sera pas un problème.
Extrait d'un numéro de Spring-Jira:
Annotation @Lazy qui peut être utilisée conjointement avec @Configuration pour indiquer que tous les beans de cette classe de configuration doivent être initialisés paresseusement. Bien sûr, @Lazy peut également être utilisé conjointement avec des méthodes @Bean individuelles pour indiquer une initialisation paresseuse sur une base un par un. https://jira.springsource.org/browse/SJC-26
Cela signifie que l'annotation de votre bean comme @Lazy
serait suffisant. Ou si vous préférez simplement annoter la classe de configuration comme @Lazy
comme suit:
@Configuration
@Lazy
public class Config {
@Bean
public ClassA classA() {
return new ClassA();
}
@Bean
public ClassB classB() {
return new ClassB();
}
}
Si vous implémentez une interface de vos beans, cela fonctionnera très bien.
Selon la documentation de Spring, il est possible d'obtenir un problème de dépendance circulaire ou BeanCurrentlyInCreationException
en utilisant injection de constructeur .
La solution pour résoudre le problème consiste à utiliser des setters au lieu de l'injection de constructeur.
Référence http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html .
Quelques lectures à ce sujet:
http://blog.jdevelop.eu/?p=382
Ces dépendances circulaires ne sont pas cool et doivent être évitées autant que possible