webentwicklung-frage-antwort-db.com.de

Warum hat Spring Probleme mit zirkulären Abhängigkeiten auf einer Maschine und nicht auf einer anderen?

Ich habe ein Problem damit, eine Spring Data-basierte Anwendung in meiner Umgebung auszuführen. Ich verwende Debian, aber meine Mitarbeiter verwenden entweder Mac oder Ubuntu. Ich habe nichts Besonderes in meinen Umgebungsvariablen eingerichtet und verwende genau dieselbe Java-Version wie andere.

Ich habe dies in den Protokollen gesehen, was darauf hindeutet, dass es sich um ein Zirkelverweisproblem handelt, das zum Instanziierungsfehler führt:

nested exception is
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'flyway.CONFIGURATION_PROPERTIES':
Initialization of bean failed;
...
nested exception is
org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'flyway': Requested bean is currently in
creation: Is there an unresolvable circular reference?

Das Problem scheint also zu sein, dass die Flyway einige Abhängigkeiten braucht und sie Flyway braucht.

Die Frage ist, warum das nur in meiner Umgebung passiert, sonst niemand? Sogar bei den Tests mit H2 im Speicher sehe ich das Problem, es ist also nicht meine Datenbank, die Schuld ist.

Ist es möglich, dass Spring Autowiring irgendwie verwirrt ist und versucht, die Dinge in der falschen Reihenfolge zu tun, sodass das Repository null ist, wenn es versucht, es festzulegen?

Hat Spring eine schlecht implementierte topologische Sortierung zum Ordnen von Abhängigkeiten?

Warum sollte es sich in meiner Umgebung schlecht benehmen?

Könnte die Reihenfolge des Klassenpfades sein Verhalten beeinflussen?

=====================

Die Anwendung startet nicht mit diesem Fehler:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'contentItemRepository': FactoryBean threw exception on object creation; nested exception is Java.lang.IllegalArgumentException: Repository interface must not be null on initialization!
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.Java:175)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.Java:127)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.Java:1517)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.Java:251)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.Java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.Java:1127)

===========================

Die ContentItemRepository-Signatur lautet:

@Repository
@Transactional
public interface ContentItemRepository extends JpaRepository<ContentItem, String>, JpaSpecificationExecutor<ContentItem> {

===========================

Dies funktionierte früher für mich und ich konnte das Commit identifizieren, das den Build brach, indem ich alle Commits durchlief, eine mvn-Neuinstallation durchführte und versuchte, den Server zu starten, bis ich das Delta fand, das ihn brach.

Das 'contentItemRepository', das nicht null sein darf, ist das Folgende:

@Component
+public class UrlAliasRequestConverter implements Mapper<UrlAliasRequest, UrlAlias> {
+
+    /**
+     * The content item contentItemType repository.
+     */
+    @Autowired
+    private ContentItemRepository contentItemRepository;
19
user2800708

Ich verstehe nicht, warum das passiert ist, aber hier ist die einzige Lösung, die mir eingefallen ist:

Installieren Sie Debian 8 und es funktioniert.

Ich habe es in einer anderen sauberen Installation von Debian 7 versucht und dort weniger Fehler erhalten, hatte aber immer noch einige. Eine saubere Installation von Debian 8 schien zu funktionieren.

Ich kann nur den Schluss ziehen, dass Java eine Systembibliothek aufrufen muss, was sich auf die Reihenfolge auswirkt, in der Spring-Abhängigkeiten aufgelöst werden. Diese Bibliothek muss in Debian 8 aktualisiert werden, damit ich mit den Ubuntu-Installationen übereinstimme, die andere Entwickler und Produktionen verwenden.

Ich weiß nicht, was diese Bibliothek sein könnte ... Etwas, das die Dateien im Dateisystem durchsucht und sie in einer anderen Reihenfolge meldet? Etwas, das eine .jar-Datei entpackt und deren Inhalt in einer anderen Reihenfolge meldet?

Es scheint mir falsch, dass unser Code so empfindlich auf die genaue Reihenfolge der Abhängigkeitsauflösung und -injektion reagiert, aber das scheint der Fall zu sein. Es sieht auch nicht so aus, als ob es irgendetwas in unserem Code gibt, das es für die Bestellung empfindlich machen könnte. Wir machen nichts Verrücktes und folgen ziemlich normalen Verwendungsmustern.

Zu viel Frühlingszauber hält das Kartenhaus aufrecht, wenn du mich fragst. Meine anderen Projekte sind auf DropWizard und dort wird die Abhängigkeitsinjektion manuell codiert, also keine Überraschungen.

=== Update

Ich habe die Debian 7-Box auf 8 aktualisiert, und das Problem besteht weiterhin. Daher ist meine Hypothese, dass es sich um eine Bibliotheksversion handelt, falsch. Muss etwas mit meiner Umgebung zu tun haben.

Ich habe auf der Box einen neuen Benutzer angelegt. Das Problem ist immer noch für diesen Benutzer vorhanden. Es gibt etwas an dieser Box, das es wirklich nicht mag, aber ich kann nicht herausfinden, was es ist.

Ich würde gerne zur wahren Sache kommen und sie verstehen, aber ich glaube nicht, dass ich mehr Zeit darauf verwenden kann, sie herauszufinden.

Wie auch immer, eine saubere Installation von Debian 8 löst das Problem.

1
user2800708

Dies hängt sehr wahrscheinlich mit der Reihenfolge zusammen, in der die Klassendateien in einer Zeile gelesen werden

dir.listFiles() in PathMatchingResourcePatternResolver.doRetrieveMatchingFiles()

Da die Reihenfolge der Dateilisten (Klassendateien) von der Plattform abhängt und das Array nicht sortiert wird, hängt die Reihenfolge, in der die Klassen geladen werden, davon ab, wie die Plattform sie zurückgibt.

ref: http://forum.spring.io/forum/spring-projects/container/115998-circular-dependency-identification-inconsistent

4
xki

Ich habe das gleiche Problem mit Ubuntu 16.04.

Ich fand das das Problem mit

@ComponentScan(basePackages = "com.my.app")

Der Code läuft auf mindestens 5 verschiedenen Computern (Windows, Ubuntu 15.04 und Ubuntu 16.04 Desktop), aber unser CI-Server (Ubuntu 16.04 Server) wird nicht gestartet.

Nachdem ich mich verändert hatte

@ComponentScan(basePackages = "com.my.app")

zu

@ComponentScan(basePackages = {"com.my.app.service", "com.my.app.config", "com.my.app"})

der Code läuft auch auf dem CI-Server.

Ich denke, dies ist eine Frühlingsausgabe mit Bohnenlader ...

UPDATE:

https://github.com/spring-projects/spring-boot/issues/6045

https://jira.spring.io/browse/SPR-14307

4
István Pató

Ich habe gestern das gleiche Problem. Ich weiß nicht warum, aber ich habe einen Weg gefunden, um das Problem zu lösen: Markieren Sie alle Beans, die am zirkulären Abhängigkeitsbaum beteiligt sind, als lazy-init. Nicht nur die direkt kreisförmigen, die voneinander abhängen, sondern alle Bohnen, die auf sie verweisen!

Da es sich bei dem Projekt um ein altes Projekt handelt, wird nur Spring 3 verwendet. Ich bin nicht sicher, ob die späteren Versionen von Spring dieses Problem noch haben.

2
fifman

Welche Erweiterung Ihrer Repository-Schnittstelle gibt es? Sie können sich den Spring-Quellcode ansehen und sehen, warum die Ausnahme ausgelöst wird:

https://github.com/spring-projects/spring-data-commons/blob/master/src/main/Java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.Java

@SuppressWarnings("unchecked")
public Class<? extends T> getObjectType() {
    return (Class<? extends T>) (null == repositoryInterface ? Repository.class : repositoryInterface);
}

Hier ist ein Beispiel für mein Repository:

@Repository
public interface GameRepository extends JpaRepository<Game, Long> {
2
Brian Kates

Ich weiß nicht, warum dieses spezielle Problem auf einer Maschine und nicht auf einer anderen auftreten würde, aber ich denke, das Problem ist höchstwahrscheinlich, dass beide Beans Konstruktorinjektionen verwenden, um Verweise aufeinander zu übergeben, wodurch die unlösbare zirkuläre Abhängigkeit entsteht, für die A B benötigt seine Konstruktion, die wiederum A benötigt, kann weder erstellt werden, noch ist die andere bereits erstellt worden. Wenn die beiden Objekte eine Referenz auf das andere Objekt benötigen, müssen Sie diese stattdessen per Setter-Injection übergeben, nachdem die Objekte bereits erstellt wurden. Die Antworten auf diese Frage sind relevant für das Problem, das Sie haben.

1
JacksonWeekes

Wir sind heute in einer nahezu identischen Situation auf dieses Problem gestoßen: Die Anwendung konnte aufgrund eines Zirkelverweises nicht gestartet werden, anscheinend während der Erstellung von Spring Data @Repository -Instanzen und nur auf dem Computer eines Entwicklers.

In unserem Fall bestand die Lösung darin, unsere Konfiguration so umzugestalten, dass ein ApplicationListener<BeforeSaveEvent> von einer in einer @Configuration-Klasse definierten anonymen Klasse in einen @Component der obersten Ebene umgewandelt wurde.

Es scheint, dass Spring Data-Repositorys auf eine nicht offensichtliche Weise eine Art Handle für diese Anwendungs-Listener behalten, und da unser Repository eine anonyme innere Klasse ist, hat das Repository implizit einen Verweis auf seinen einschließenden @Configuration beibehalten (und somit wird eine Abhängigkeitsschleife erkannt) aufgrund von Beans, die über diesen @Configuration instanziiert wurden, der schließlich das Repository automatisch verkabelt hat).

Alle Antworten, die das Ändern von Lazy Init, das Ändern der Scanreihenfolge von Komponenten, das Neuinstallieren des Betriebssystems, das Aus- und Wiedereinschalten usw. beschreiben, verbergen sich nur, anstatt das Problem wirklich zu beheben, und ich würde vorschlagen, es an der Quelle zu beheben :) Der Grund, warum Dinge auf verschiedenen Maschinen funktionieren oder nicht funktionieren, ist, wie @xki andeutet, dass die Konstruktionsreihenfolge der Objektgraphen nicht deterministisch ist.

0
ryanp