24

ho un riferimento circolarein uno dei miei progetti di lavoro con la primavera, che non sono in grado di risolvere, e non riesce con il seguente errore in fase di avvio:Primavera esempio di riferimento circolare

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

ho cercato di ricreare lo stesso problema a un livello più piccolo in un progetto di esempio (senza tutti i dettagli del mio progetto di lavoro). Tuttavia, non sono riuscito a trovare uno scenario plausibile in cui la primavera fallisse con un errore. Ecco quello che ho:

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

Ho uno scenario simile nel mio progetto, che non riesce, e mi aspettavo la primavera a lamentarsi nel mio progetto di esempio pure. Ma funziona bene! Qualcuno può darmi un semplice esempio di come rompere la molla con l'errore di riferimento circolare?

Modifica: Ho risolto il problema utilizzando javax.inject.Provider. L'unica altra differenza nei 2 progetti era che le annotazioni usate erano javax.inject.Inject e javax.annotation.ManagedBean al posto di @Autowired e @Component.

risposta

23

Questo è un thread vecchio, quindi credo che ti sia quasi dimenticato del problema, ma voglio farti conoscere il mistero. Ho incontrato lo stesso problema e il mio non è andato via magicamente, quindi ho dovuto risolvere il problema. Risolverò le tue domande passo dopo passo.

1. Perché non è stato possibile riprodurre l'eccezione di riferimento circolare?

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

2. Quindi perché il progetto produce un'eccezione?

  • Come @sperumal detto, Primavera può produrre eccezione circolare se si utilizza l'iniezione costruttore
  • Secondo il registro, si utilizza Primavera di sicurezza nel progetto
  • Nella configurazione di Primavera di sicurezza, lo fanno usare costruttore iniezione
  • vostri fagioli che inietta il authenticationManager avuto il riferimento circolare

3. Allora perché ha la ex l'idea è andata via misticamente?

L'eccezione può o non può verificarsi in base all'ordine di creazione dei bean. Credo che hai fatto diversi *context.xml file o giù di lì, e caricarli con qualcosa di configurazione come qui di seguito in web.xml

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

I file XML verranno caricati dal XmlWebApplicationContext di classe e l'ordine di caricamento dei file non sono garantiti. Carica solo file dal file system. Il problema è qui Non c'è alcun problema se la classe carica prima il file di contesto dell'applicazione, perché i bean sono già stati creati quando vengono utilizzati per l'iniezione di Spring Security. Tuttavia, se carica prima il file di contesto Spring Security, si verifica il problema di riferimento circolare, poiché Spring tenta di utilizzare i bean nell'iniezione del costruttore prima della creazione.

4. Come risolvere il problema?

Forza l'ordine di caricamento dei file xml. Nel mio caso, ho caricato il file xml del contesto di sicurezza alla fine del file di contesto dell'applicazione utilizzando <import resource="">. L'ordine di caricamento può essere modificato a seconda degli ambienti, anche con lo stesso codice, quindi consiglio di impostare l'ordine per rimuovere potenziali problemi.

2

qualche lettura sulla questione:

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

Tali dipendenze circolari non sono fresche e devono essere evitati quando possibile

26

Si potrebbe utilizzare @Lazy per indicare che il fagiolo è pigramente creato, rompendo il ciclo desideroso di autowiring.

L'idea è che alcuni bean sul ciclo possano essere istanziati come proxy e al momento è davvero necessario inizializzarlo. Ciò significa che tutti i bean sono inizializzati tranne quello che è un proxy. Usarlo per la prima volta attiverà la configurazione e, poiché gli altri bean sono già configurati, non sarà un problema.

Da un'edizione nella primavera-Jira:

@Lazy annotazione che può essere utilizzato in combinazione con @Configuration per indicare che tutti i fagioli all'interno di quella classe di configurazione dovrebbero essere pigramente inizializzato. Naturalmente, @Lazy può anche essere utilizzato in congiunzione con con i singoli metodi @Bean per indicare l'inizializzazione pigra su base uno alla volta. https://jira.springsource.org/browse/SJC-263

Il che significa che l'annotazione il bean come @Lazy sarebbe sufficiente. O se si preferisce semplicemente annotare la classe di configurazione come @Lazy come segue:

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

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

Se si implementa l'interfaccia dei vostri fagioli questo funzionerà abbastanza bene.

+1

Solo per aggiungere a questo, abbiamo riscontrato un problema simile (con l'iniezione di SpringTemplateEngine). La soluzione "setter injection" NON ha aiutato, ma l'annotazione '@ Lazy' ha funzionato. Sembra un cerotto su una ferita da proiettile, ma per ora prenderò la vittoria e andrò via. Grazie, signor Spaeth. – demaniak

9

In base alla documentazione Spring, è possibile ottenere il problema di dipendenza Circolare o BeanCurrentlyInCreationException utilizzando l'iniezione del costruttore.

La soluzione per risolvere il problema è utilizzare i setter invece dell'iniezione del costruttore.

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

+2

Penso che tu abbia frainteso ciò che è stato scritto lì: se usi prevalentemente l'iniezione del costruttore, ** è possibile ** creare uno scenario di dipendenza circolare irrisolvibile. –

+1

L'iniezione del costruttore è preferibile rispetto all'iniezione del setter: il bean non è presente fino al completamento della chiamata del costruttore, mentre con l'iniezione del setter è possibile omettere alcuni parametri necessari e il bean esiste per qualche tempo in uno stato non configurato correttamente –