2011-10-14 8 views
41

Quando ho iniziato a studiare Spring, le cose sono state configurate nel file applicationContext.xml. Poi, quando ho iniziato a leggere libri in particolare sulle versioni più recenti di Spring, hanno tutti eseguito la configurazione in file XML separati come myapp-servlet-xml, myapp-security.xml, myapp-service.xml, ecc., Di configurazione di contextConfigLocation nel file web.xml. Così, per esempio, il codice ho seguito insieme a avuto questo come è contextConfigLocation:Guida/spiegazione gerarchia di file XML di Spring

<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value> 
     /WEB-INF/myapp-servlet.xml 
     /WEB-INF/myapp-data.xml 
    </param-value> 
</context-param> 

In ogni caso, di recente mi sono imbattuto in un problema di configurazione (che la gente utile qui a StackOverflow mi ha aiutato a capire) che era dovuto a questa separazione. Non c'era alcun file applicationContext.xml per gli esempi da questi libri e più tardi quando ho provato ad aggiungere la scansione e le annotazioni automatiche all'app causando problemi. Ho provato a spostare tutto in applicationContext.xml e ad eliminare gli altri file e ho risolto il problema. Nient'altro è cambiato, ho solo messo tutto in applicationContext.xml.

Quindi, questo, insieme ai commenti degli altri, mi ha portato a capire che, anche se non si crea un'applicazioneContext.xml, è ancora in uso ed è il livello più alto di una sorta di gerarchia di configurazione . Spero che qualcun altro possa spiegarmi come funziona tutto questo perché non ho trovato alcuna spiegazione su di esso da nessuna parte.

Ad esempio, se inserisco un determinato contesto: i tag di scansione dei componenti nei file di configurazione che si trovano sotto applicationContext.xml, è possibile che alcune classi non vengano scansionate. Cose di questa natura. Non capisco la precedenza e cosa deve andare dove per essere sicuri che sia visto in tutta l'applicazione e così via. Se qualcuno può spiegarlo chiaramente o indicarmi una risorsa che lo spiega, lo apprezzerei molto, grazie. Spero che ciò che sto chiedendo abbia senso.

risposta

83

Non c'è niente di speciale nel file "applicationContext.xml", tranne che è il nome che Spring tende ad aspettarsi come file di configurazione predefinito. Utilizzando un file chiamato così o più file denominati "dog.xml", "cat.xml" e "alien.xml" funzioneranno esattamente allo stesso modo. Il problema derivante dall'avere più ApplicationContexts in uso allo stesso tempo, non dall'avere più file XML. Di recente ho risposto a un paio di domande da persone che hanno avuto problemi a causa della mancata comprensione di questi concetti. Scopri quelle risposte, e vedere quali domande avete ancora:

Declaring Spring Bean in Parent Context vs Child Context

Spring-MVC: What are a "context" and "namespace"?

Edit: In risposta alla tua nuova domanda:

ho avuto un tag <context:component-scan base-package="com.myapp"/> in il mio servlet.xml.

Sto indovinando questo file "servlet.xml" si chiama come foo-servlet.xml, dove la DispatcherServlet configurato nel web.xml si chiama "pippo", come

<servlet> 
    <servlet-name>foo</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
</servlet> 

Per convenzione, quando questo DispatcherServlet si avvia, creerà un nuovo ApplicationContext configurato dal file foo-servlet.xml, derivato dallo servlet-name. Ora, dal momento che si inserisce uno context:component-scan, si analizzerà in modo ricorsivo il pacchetto specificato e creerà i bean per tutte le classi annotate.Il pacchetto che hai fornito, com.myapp, sembra che sia il pacchetto base per l'intera app, quindi Spring creerà i bean da all delle classi annotate nella tua app, compresi quelli di accesso ai dati, in questo ApplicationContext associato al DispatcherServlet. In genere, questo contesto dovrebbe avere solo roba e bean di livello di visualizzazione che supportano direttamente DispatcherServlet, quindi si trattava di una configurazione errata.

Nel mio file data.xml avevo i bean di origine dati e basta. Nessun altro bean, tutto il resto è stato creato e annotato.

Presumibilmente, questo file "data.xml" è quello che è elencato nel parametro di contesto contextConfigLocation. Supponendo che ci si aggiunge anche il ContextLoaderListener al web.xml, come

<listener> 
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
</listener> 

allora che il file verrà utilizzato per creare un secondo ApplicationContext - il contesto radice. Questo è ciò che fa questo ascoltatore. Nota che in realtà crea il contesto da tutti i i file elencati in contextConfigLocation, e se hai incluso anche il tuo "servlet.xml" in quell'elenco, allora hai caricato quella configurazione due volte: qui nel contesto radice e in il contesto associato a DipatcherServlet. Si spera che ora si veda la differenza tra i file di configurazione XML e ApplicationContexts che configurano. Lo stesso file XML può essere facilmente utilizzato per configurare due diversi contesti. Se farlo è corretto o meno è un'altra domanda. In questo caso particolare, non lo è.

L'ordine in cui ho descritto questi due contesti è in realtà indietro. Stavo solo seguendo la tua descrizione di quello che hai fatto. ContextLoaderListener, essendo un ServletContextListener, verrà sempre eseguito prima dell'avvio di qualsiasi servlet. Ciò significa che il contesto di root viene creato per primo e l'altro secondo per secondo. Questo è progettato in modo tale che quando DispatcherServlet crea il suo contesto, può aggiungere quel contesto come figlio del contesto di root. Ho descritto questa relazione in quegli altri post. L'effetto più importante di questo è che i bean nel contesto di root sono disponibili per e tramite il contesto di DispatcherServlet. Questo vale anche per le relazioni autowired. Questo è importante perché DispatcherServlet solo cerca nel suo contesto associato i bean di cui ha bisogno, come le istanze del controller. I controller, tuttavia, devono ovviamente essere cablati con bean di supporto. Pertanto, tradizionalmente, i controllori vivono nel contesto di DispatcherServlet e i bean di supporto vivono nel contesto di root.

Ho quindi provato ad aggiungere @Transacational al mio bean di servizio e non sarebbe persistito.

Affinché @Transactional al lavoro, è necessario includere il tag <tx:annotation-driven/> nella configurazione del ApplicationContext dove la vita di fagioli annotato. Il trucco sta nel capire la parte "dove vive". I bean di un bambino possono sovrascrivere i bean in un contesto padre. Quindi - sto solo indovinando qui - se avessi caricato tutti i tuoi bean nel contesto DispatcherServlet come descritto sopra ma inserissi lo <tx:annotation-driven/> nel contesto root, potresti avere un bean nel contesto root che è transazionale correttamente, ma non lo è quello utilizzato perché il duplicato è "più vicino" al servlet nella gerarchia padre/figlio e il contesto in cui si trova non ha ricevuto una configurazione <tx:annotation-driven/>.

Quando ho cambiato il contesto servlet: il tag component-scan punta invece su com.myapp.web e poi ha aggiunto un contesto: tag component-scan nel file data.xml, tutto ha funzionato.

Dipende ancora un po 'sulla esattamente quali file di configurazione si erano compresi in cui ApplicationContexts, ma per lo meno posso dire che in questo modo, è stato rimosso un sacco di fagioli dal contesto del DispatcherServlet che stavano causando problemi. In particolare, i bean @Transactional correttamente configurati nel contesto radice non sarebbero più ombreggiati dai bean nel contesto figlio e verrebbero iniettati nei controller, quindi la roba di persistenza funzionerebbe in quel momento.

Quindi ... la cosa principale da togliere è che si hanno due ApplicationContex correlati. Devi rimanere consapevole di questo fatto e mantenere il controllo su quali fagioli andare in quale contesto.

Questo copre tutto?

+0

Grazie mille per l'aiuto e i collegamenti. I link fornivano alcuni dei chiarimenti che stavo cercando. Ho una domanda però. Ho avuto un tag nel mio servlet.xml. Nel mio file data.xml avevo i bean di origine dati e basta. Nessun altro bean, tutto il resto è stato creato e annotato. Ho quindi provato ad aggiungere @Transacational al mio bean di servizio e non sarebbe persistito. Quando ho cambiato il contesto servlet: il tag component-scan invece punta a com.myapp.web e poi ha aggiunto un contesto: tag component-scan al file data.xml, tutto ha funzionato. – cardician

+0

Quindi la mia domanda sarebbe, puoi chiarire perché è così? Ho un servlet di dispatcher che controlla servlet.xml in modo che non sia il contesto di root. Hmmm ... Immagino di non capire ancora completamente come stanno le cose insieme. Grazie mille però. – cardician

+0

Un grandissimo grazie a te! Penso che tu abbia davvero aiutato a chiarire ciò che non riuscivo a vedere dai libri e dagli Spring Doc che ho letto. Stavo davvero inserendo il mio file serlvet.xml nella lista contextConfigLocation che, come hai detto, stava causando 2 contesti. Probabilmente non era il mio unico problema, ma sicuramente uno di loro. Ora con la tua spiegazione dovrei essere in grado di verificare e verificare che tutto sia configurato correttamente. Apprezzo anche che tu stia elencando come Spring carica anche i file. Penso che tutto sia molto più chiaro. Grazie ancora. – cardician

Problemi correlati