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.

25
demandé sur robbin 2012-07-05 20:40:12

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.

25
répondu Sanghyun Lee 2017-11-17 10:43:32

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.

26
répondu Francisco Spaeth 2012-07-05 17:05:22

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.

9
répondu sperumal 2012-07-14 03:24:42

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

2
répondu Konstantin Pribluda 2013-06-06 10:03:06