2010-05-18 3 views
6

Ho un Singleton che ha una molla iniettato Dao (semplificato sotto):Dependency Injection nel vostro Singleton

public class MyService<T> implements Service<T> { 
    private final Map<String, T> objects; 
    private static MyService instance; 

    MyDao myDao; 

    public void set MyDao(MyDao myDao) { 
     this. myDao = myDao; 
    } 

    private MyService() { 
     this.objects = Collections.synchronizedMap(new HashMap<String, T>()); 
     // start a background thread that runs for ever 
    } 

    public static synchronized MyService getInstance() { 
     if(instance == null) { 
      instance = new MyService(); 
     } 
     return instance; 
    } 

    public void doSomething() { 
     myDao.persist(objects); 
    } 
} 

mio config primavera sarà probabilmente simile a questa:

<bean id="service" class="MyService" factory-method="getInstance"/> 

Ma questo sarà istanziare il MyService durante l'avvio.

Esiste un modo programmatico per eseguire un inserimento di dipendenza di MyDao in MyService, ma non è necessario gestire Spring MyService?

Fondamentalmente voglio essere in grado di fare questo dal mio codice:

MyService.getInstance().doSomething(); 

pur avendo primavera iniettare il MyDao per me.

risposta

2

Se si desidera un singleton, perché non solo definire quella classe nelle configurazioni Spring, ed è automaticamente un singleton (per impostazione predefinita).

Per evitare l'inizializzazione all'avvio, hai guardato Spring lazy initialisation? Fondamentalmente è necessario:

lazy-init="true" 

nella definizione del bean.

+0

E devi ottenere il bean usando ApplicationContext dove ti serve? – Langali

+0

Vorrei * normalmente * ottenere il mio primo bean di livello superiore all'inizializzazione e quindi fare riferimento a ulteriori bean come richiesto da quel bean di livello superiore. Ma potresti fare ciò che stai suggerendo. –

0

Come detto da altri, si dovrebbe lasciare primavera gestire i single, ma se si desidera gestire da soli e lasciare che la primavera iniettare le dipendenze, fare questo:

applicationContext.getAutowireCapableBeanFactory().autowireBean(yourService); 
0

credo che l'interfaccia FactoryBean è una buona alternativa per te. È un'ottima scelta quando è necessario eseguire una logica di inizializzazione. Ad esempio, per avviare un database in memoria o alcuni processi in background in thread separati.

Ulteriori informazioni a riguardo sono disponibili nello reference documentation.

Un esempio che dimostra come istanzio un database e restituisco un'origine dati ogni volta che qualcuno vuole un bean dall'implementazione FactoryBean.

@PostConstruct 
void init() { 
    embeddedDatabase = new EmbeddedDatabaseBuilder().addScript(schemaPath) 
     .addScript(dataPath).setType(embeddedDatabaseType).build(); 
} 


public DataSource getObject() throws Exception { 
    return embeddedDatabase; 
} 

Ciò consente l'accoppiamento lento tra la logica di fabbrica e l'oggetto restituito. È pesantemente utilizzato internamente dal framework Spring.

Se si desidera inizializzarlo la prima volta che lo si utilizza, impostare lazy-initialization su true.

Un'altra alternativa se si desidera che il codice interagisca con il contenitore Spring è quello di creare uno stabilimento che implementa l'interfaccia ApplicationContextAware.Poi si può fare qualcosa di simile:

myDao = context.getBean(MyDao.class); 
4

Ecco una soluzione, creare una classe con un metodo factory statica:

public class MyService { 
    private static MyService instance; 

    private MyDao myDao; 

    public static MyService createInstance(final MyDao myDao) { 
     instance = new MyService(myDao); 
     return instance; 
    } 

    private MyService(final MyDao myDao) { 
     this.myDao = myDao; 
    } 

    public static synchronized MyService getInstance() { 
     return instance; 
    } 

    public void doSomething() { 
     // just do it! 
     myDao.justDoIt(); 
    } 
} 

e utilizzare primavera initilize esso:

<bean class="my.path.MyService" factory-method="createInstance" scope="singleton"> 
    <constructor-arg ref="reference.to.myDao" /> 
    </bean> 

e ora dovresti essere in grado di fare:

MyService.getInstance().doSomething(); 

senza problemi.