Exemple de référence circulaire à ressort
J'ai une référence circulaire dans l'un de mes projets au travail en utilisant spring, que je ne peux pas corriger, 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). J'ai cependant été incapable de trouver 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 plaint également dans mon exemple de projet. Mais cela fonctionne très bien! Quelqu'un peut-il me donner un exemple simple de la façon de briser le printemps avec l'erreur de référence circulaire?
Edit: j'ai résolu le problème en utilisant javax.injecter.Fournisseur. La seule autre différence dans les 2 projets était les annotations utilisées étaient javax.injecter.Injecter et javax.annotation.ManagedBean à la place de @ Autowired et @ Component.
4 réponses
C'est un vieux fil, donc je suppose que vous avez presque oublié le problème, mais je veux vous faire connaître le mystère. J'ai rencontré le même problème, et le mien ne s'est pas envolé comme par magie, alors j'ai dû résoudre le problème. Je vais résoudre vos questions, étape par étape.
1. Pourquoi vous n'avez pas pu 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 est-ce que votre projet produire l'exception?
- comme l'a dit @sperumal, Spring peut produire une exception circulaire si vous utilisez l'injection constructeur
- selon le journal, vous utilisez Spring Security dans votre projet
- dans la configuration de sécurité Spring, ils utilisent l'injection constructeur
- vos haricots qui injectent le
authenticationManager
avaient la référence circulaire
3. Alors pourquoi l'exception a-t-elle disparu mystiquement?
L'exception peut ou peut ne pas se produire dépend l'ordre de création des haricots. Je suppose que vous avez fait plusieurs fichiers *context.xml
ou plus, et les charger avec config quelque chose comme ci-dessous dans le 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 XmlWebApplicationContext
classe et l'ordre de chargement des fichiers ne sont pas garantis. Il charge simplement les fichiers du système de fichiers. Le problème est ici. Il n'y a pas de problème si la classe charge d'abord le fichier de contexte de l'application, car vos beans sont déjà créés lorsqu'ils sont utilisés pour l'injection de construction de Spring Security. Mais, si il charge d'abord le fichier de contexte de sécurité Spring, le problème de référence circulaire se produit, car Spring essaie d'utiliser vos beans dans l'injection du constructeur avant leur création.
4. Comment résoudre le problème?
Force 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é dépend des environnements même avec le même code, donc je recommande réglage de l'ordre pour éliminer les problèmes potentiels.
Vous pouvez utiliser @Lazy
pour indiquer que le haricot est créé paresseusement, brisant le cycle avide d'autowiring.
L'idée est qu'un bean 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.
D'un numéro dans Printemps-Jira:
@Lazy annotation qui peut être utilisée conjointement avec @Configuration pour indiquer que tous les beans de cette classe de configuration doivent être paresseusement initialisé. Bien sûr, @Lazy peut également être utilisé en conjonction avec des méthodes @Bean individuelles pour indiquer une initialisation paresseuse sur un une par une. https://jira.springsource.org/browse/SJC-263
Ce qui signifie que l'annotation de votre bean comme @Lazy
serait suffisante. Ou si vous préférez juste 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 assez bien.
Selon la documentation Spring, il est possible d'obtenir un problème de dépendance circulaire ou BeanCurrentlyInCreationException
en utilisant constructor injection.
La solution pour résoudre le problème consiste à utiliser des setters au lieu de L'injection du constructeur.
Référence http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html.
Quelques lectures sur la question:
Http://blog.jdevelop.eu/?p=382
De telles dépendances circulaires ne sont pas cool et doivent être évitées lorsque cela est possible