2015-04-22 13 views
5

So che ci sono così tante domande simili su questo. Ho esaminato molti di loro ma il problema rimane ancora.Spring bean creato ma non avviato automaticamente

Ho un servizio che viene creato ma non avviato automaticamente. Non c'è (!) Avvio manuale, né nel progetto né nei test (come in this question)

Entrambi i bean vengono trovati e creati, dice l'output di Tomcat. Almeno il primo servizio non viene iniettato dove dovrebbe essere. Non so del secondo.

servizi (Interface):

public interface SchoolService { 
    public School getSchool(String id); 
} 

servizio (Attuazione):

@Service 
@Transactional 
public class SchoolServiceImpl implements SchoolService { 

    @Autowired 
    private SchoolDAO schoolDAO; 

    public School getSchool(String id) { 
    //database things 
    return school; 
    } 

} 

dove ottiene "chiama"

public class SchoolMenu implements Serializable { 

    @Autowired 
    private SchoolService schoolService; 

    public SchoolMenu() { 
    //here schoolService is null 
    School school = schoolService.getSchool("id"); 
    } 

} 

application-context.xml

<?xml version='1.0' encoding='UTF-8' ?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:p="http://www.springframework.org/schema/p" 
     xmlns:aop="http://www.springframework.org/schema/aop" 
     xmlns:tx="http://www.springframework.org/schema/tx" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd 
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> 


    <bean id="SchoolServiceImpl" class="content_management.School.service.SchoolServiceImpl"/> 
    <bean id="SchoolDAOImpl" class="content_management.School.dao.SchoolDAOImpl"/> 
</beans> 

Tomcat uscita:

org.springframework.beans.factory.support.DefaultListableBeanFactory: Pre-instantiating singletons in org.s[email protected]57003970: defining beans [SchoolServiceImpl,SchoolDAOImpl]; root of factory hierarchy 
org.springframework.beans.factory.support.DefaultListableBeanFactory: Creating shared instance of singleton bean 'SchoolServiceImpl' 
org.springframework.beans.factory.support.DefaultListableBeanFactory: Creating instance of bean 'SchoolServiceImpl' 
org.springframework.beans.factory.support.DefaultListableBeanFactory: Eagerly caching bean 'SchoolServiceImpl' to allow for resolving potential circular references 
org.springframework.beans.factory.support.DefaultListableBeanFactory: Finished creating instance of bean 'SchoolServiceImpl' 
org.springframework.beans.factory.support.DefaultListableBeanFactory: Creating shared instance of singleton bean 'SchoolDAOImpl' 
org.springframework.beans.factory.support.DefaultListableBeanFactory: Creating instance of bean 'SchoolDAOImpl' 
org.springframework.beans.factory.support.DefaultListableBeanFactory: Eagerly caching bean 'SchoolDAOImpl' to allow for resolving potential circular references 
org.springframework.beans.factory.support.DefaultListableBeanFactory: Finished creating instance of bean 'SchoolDAOImpl' 

Dov'è il mio errore?

+0

Si sta tentando di utilizzare il campo dal costruttore, prima che Spring abbia avuto la possibilità di fare qualsiasi cosa. – chrylis

risposta

2

Per il funzionamento di @Autowired, SchoolMenu deve essere un bean Spring. In caso contrario, è possibile ottenere schoolService dal contesto dell'applicazione. Qualcosa di simile

ApplicationContext appContext = new ClassPathXmlApplicationContext("application-context.xml"); 
SchoolService schoolService = (SchoolService) appContext.getBean(SchoolService.class); 
1

Stai accedendo schoolService nel costruttore di SchoolMenu:

public SchoolMenu() { 
    //here schoolService is null 
    School school = schoolService.getSchool("id"); 
} 

A quel punto, schoolService non è ancora iniettato. Non potrebbe essere - non può accadere nulla prima del il costruttore è stato richiamato.

È possibile dichiarare un metodo da richiamare dopo l'inizializzazione del bean, annotandolo con l'annotazione javax.annotation.PostConstruct. Esegui azioni che richiedono le dipendenze iniettate in quel metodo, non nel costruttore.

(Ci sono alcuni altri modi per ottenere lo stesso, come implementazione dell'interfaccia InitializingBean, ma questi sono un po 'obsolete)

Esempio:

public SchoolMenu() { 
} 

@PostConstruct 
public void init() { 
    // schoolService is NOT null here 
    School school = schoolService.getSchool("id"); 
} 
+1

Ancor più preferibile è utilizzare l'iniezione del costruttore in primo luogo. – chrylis

+0

L'iniezione del costruttore ha molti vantaggi, ma un grosso svantaggio: non può risolvere i cicli nelle dipendenze (non è possibile inizializzare due servizi che si riferiscono l'un l'altro usando l'iniezione del costruttore - almeno uno di essi ha bisogno di setter o iniezione di campo) –

+1

Sì, ma (1) non è il caso qui per quanto posso dire e (2) le dipendenze cicliche sono quasi sempre un segno di un problema di progettazione. – chrylis

0

Invece di definire fagioli in XML, è possibile utilizzare la scansione dei componenti aggiungendo questa configurazione al contesto dell'applicazione e Spring eseguirà la scansione e il rilevamento automatico del bean automaticamente.

<context:component-scan base-package="content_management.School" /> 

Inoltre, è necessario aggiungere nello spazio dei nomi di contesto il contesto dell'applicazione.xml sarà simile a questo:

<?xml version='1.0' encoding='UTF-8' ?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:p="http://www.springframework.org/schema/p" 
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:tx="http://www.springframework.org/schema/tx" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd 
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd 
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> 

<context:component-scan base-package="content_management.School" /> 

</beans> 
+0

Ho aggiunto sia lo spazio dei nomi che lo snippet di scansione, ma ottengo 'XmlBeanDefinitionStoreException: la riga 26 nel documento XML dalla risorsa ServletContext [/WEB-INF/applicationContext.xml] non è valida; l'eccezione nidificata è org.xml.sax.SAXParseException; numero riga: 26; columnNumber: 78; cvc-complex-type.2.4.c: ' – sebastian

+0

Puoi mostrare la riga 26 del tuo applicationContext.xml o anche meglio l'intero file? Sembra l'errore di sintassi –

+0

la riga 26 è la riga ' sebastian

Problemi correlati