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?
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
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
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