24

Ich habe eine zirkuläre Referenz in einem meine Projekte bei der Arbeit Feder verwendet, die ich nicht in der Lage bin zu beheben, und schlägt mit dem folgenden Fehler beim Start:Frühling Kreisreferenzbeispiel

'org.springframework.security.authenticationManager': Requested bean is currently in creation: Is there an unresolvable circular reference? 

Ich habe versucht, Erstellen Sie das gleiche Problem auf einer kleineren Ebene in einem Beispielprojekt (ohne alle Details meines Arbeitsprojekts). Ich habe jedoch kein plausibles Szenario gefunden, in dem der Frühling mit einem Fehler versagt. Hier ist, was ich habe:

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(); 
    } 
} 

ich ein ähnliches Szenario in meinem Projekt haben, das ausfällt, und ich erwartete Frühling als auch in meinem Beispielprojekt zu beklagen. Aber es funktioniert gut! Kann mir jemand ein einfaches Beispiel dafür geben, wie man den Federbruch mit dem kreisförmigen Referenzfehler unterbricht?

Bearbeiten: Ich habe das Problem mit javax.inject.Provider behoben. Der einzige andere Unterschied in den 2 Projekten waren die verwendeten Annotationen javax.inject.Inject und javax.annotation.ManagedBean anstelle von @Autowired und @Component.

Antwort

23

Dies ist ein alter Thread, also glaube ich, du hast das Problem fast vergessen, aber ich möchte dich über das Geheimnis informieren. Ich stieß auf das gleiche Problem, und meins ging nicht magisch weg, also musste ich das Problem lösen. Ich werde deine Fragen Schritt für Schritt lösen.

1. Warum konnten Sie die zirkuläre Referenzausnahme nicht reproduzieren?

Weil Spring takes care of it. It creates beans and injects them as required.

2. Warum produziert Ihr Projekt die Ausnahme?

  • Wie @sperumal sagte, kann Frühling Kreis Ausnahme erzeugen, wenn Sie Konstruktor Injektion
  • Gemäß dem Protokoll verwenden Sie Spring Security in Ihrem Projekt
  • Im Spring Security Config, tun sie Konstruktor Injektion
  • Ihre Bohnen, die die authenticationManager injiziert hatte die zirkuläre Referenz

3. warum die ex hat Die Idee ist mystisch weggegangen?

Die Ausnahme kann oder kann nicht auftreten hängt von der Erstellungsreihenfolge der Beans ab. Ich denke, man mehrere *context.xml Dateien gemacht oder so, und laden sie mit Config so etwas wie unten in web.xml

<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value>classpath:*-context.xml</param-value> 
</context-param> 

Die XML-Dateien von XmlWebApplicationContext Klasse und der Ladereihenfolge der Dateien garantiert nicht geladen werden. Es lädt nur Dateien aus dem Dateisystem. Das Problem ist hier. Es gibt kein Problem, wenn die Klasse zuerst die Anwendungskontextdatei lädt, da Ihre Beans bereits erstellt werden, wenn sie für die Konstruktionsinjektion von Spring Security verwendet werden. Wenn jedoch zuerst die Spring Security-Kontextdatei geladen wird, tritt das zirkuläre Referenzproblem auf, da Spring versucht, Ihre Beans in der Konstruktorinjektion zu verwenden, bevor sie erstellt wurden.

4. Wie das Problem zu lösen?

Erzwinge die Ladereihenfolge der XML-Dateien. In meinem Fall habe ich die Sicherheitskontext-XML-Datei am Ende der Anwendungskontextdatei mithilfe von <import resource=""> geladen. Die Ladereihenfolge kann je nach Umgebung auch mit dem gleichen Code geändert werden. Daher empfehle ich, die Reihenfolge festzulegen, um mögliche Probleme zu beheben.

2

Einige Lektüre zu diesem Thema:

http://blog.jdevelop.eu/?p=382

Solche zirkuläre Abhängigkeiten nicht cool sind und muss deshalb vermieden werden, wenn möglich

26

Sie @Lazy nutzen könnten, um anzuzeigen, dass die Bohne lazily erstellt wird, brechen die eifriger Zyklus des Autofahrens.

Die Idee ist, dass einige Bohne auf dem Zyklus als Proxy instanziiert werden könnte, und genau in dem Moment, in dem sie wirklich benötigt wird, wird sie initialisiert. Dies bedeutet, dass alle Beans initialisiert werden, mit Ausnahme desjenigen, der ein Proxy ist. Wenn Sie es zum ersten Mal verwenden, wird die Konfiguration ausgelöst und da die anderen Beans bereits konfiguriert sind, wird dies kein Problem darstellen.

Von einer Ausgabe im Frühjahr-Jira:

@Lazy Anmerkung, die mit @Configuration in Verbindung verwendet werden kann, um anzuzeigen, dass alle Bohnen innerhalb dieser Konfigurationsklasse initialisiert träge sein sollten. Natürlich kann @Lazy auch in Verbindung mit einzelnen @Bean-Methoden verwendet werden, um die faule Initialisierung auf einer Basis eins zu eins anzuzeigen. https://jira.springsource.org/browse/SJC-263

Was bedeutet, dass Ihr Bean als @Lazy Kommentierung genug sein würde. Oder wenn Sie nur die Konfigurationsklasse wie @Lazy mit Anmerkungen versehen, wie folgt:

@Configuration 
@Lazy 
public class Config { 
    @Bean 
    public ClassA classA() { 
     return new ClassA(); 
    } 

    @Bean 
    public ClassB classB() { 
     return new ClassB(); 
    } 
} 

Wenn Sie eine Schnittstelle Ihrer Bohnen implementieren wird dies ganz gut funktionieren.

+1

Nur um das hinzuzufügen, haben wir ein ähnliches Problem (mit der Injektion von SpringTemplateEngine). Die "Setter-Injektion" -Lösung hat NICHT geholfen, aber die '@ Lazy'-Annotation hat es geschafft. Es fühlt sich an wie ein Pflaster vor einer Schusswunde, aber jetzt werde ich den Sieg davontragen und weggehen. Danke Herr Späth. – demaniak

9

Gemäß der Spring-Dokumentation ist es möglich, das Problem der zirkulären Abhängigkeit oder BeanCurrentlyInCreationException mithilfe von Konstruktorinjektion zu erhalten.

Die Lösung zur Behebung des Problems besteht darin, anstelle von Constructor-Injektion Setter zu verwenden.

Referenz http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html.

+2

Ich glaube, Sie haben falsch verstanden, was dort geschrieben wurde: Wenn Sie überwiegend die Konstruktorinjektion verwenden, ** ist es möglich ** ein nicht auflösbares zirkuläres Abhängigkeitsszenario zu erstellen. –

+1

Konstruktorinjektion ist gegenüber Setterinjektion vorzuziehen - Ihre Bean ist nicht vorhanden, bis der Konstruktoraufruf abgeschlossen wurde, während Sie bei der Setterinjektion möglicherweise einige notwendige Parameter weglassen und Bean für einige Zeit im nicht ordnungsgemäß konfigurierten Zustand existiert –