2013-04-18 12 views
13

Come si può avere una classe che implementa Runnable e inoltrata a Springs TaskExecutor autowired?Attività di autowiring inviate a Spring TaskExecutor

Per esempio, ho un compito:

public class MyTask implements Runnable { 

    @Autowired private MyRepository myRepository; 

    @Override 
    public void run() { 
     myRepository.doSomething(); 
    } 
} 

E un servizio che invia un compito al TaskExecutor primavera:

@Service 
public class MyService { 

    @Autowired private TaskExecutor taskExecutor; 

    public void someMethod() { 

     MyTask myTask = new MyTask(); 
     taskExecutor.execute(myTask); 

    } 

} 

So che i campi non vengono autowired perché MyTask è essere istanziato usando il nuovo MyTask(). Tuttavia, come faccio a evitare questo? Dovrei avere accesso a Spring ApplicationContext e creare il bean attraverso di esso? Come faresti in un ambiente applicativo web?

Grazie!

risposta

4

Ci sono almeno due buoni modi per farlo usando primavera. Innanzitutto, l'annotazione @Configurable. Usare questo significa una dipendenza da AspectJ, ma ti permetterà di iniettare fagioli che non sono gestiti da Spring (cioè stai usando il nuovo operatore). Ciò comporterebbe l'annotazione di MyTask con @Configurable e l'aggiunta di un paio di linee alla configurazione Spring come menzionato nel collegamento.

@Configurable 
public class MyTask implements Runnable { ... } 

@Service 
public class MyService { 
    @Autowired private TaskExecutor taskExecutor; 

    public void someMethod() { 

    // AspectJ would jump in here and inject MyTask transparently 
    MyTask myTask = new MyTask(); 
    taskExecutor.execute(myTask); 

} 

}

Il secondo approccio comporterebbe utilizzando la funzione ServiceLocatorFactoryBean di primavera per creare fagioli prototipo. Questo è meglio spiegato nel JavaDoc, ma in questa circostanza si sarebbe iniettare un TaskFactory nella tua classe @Service annotato, proprio come qualsiasi altro di fagioli e poi fare qualcosa in questo modo:

@Service 
public class MyService { 
    @Autowired private TaskExecutor taskExecutor; 
    @Autowired private MyRepository myRepository; 
    @Autowired private TaskFactory taskFactory; 


public void someMethod() { 
    MyTask myTask = taskFactory.getTask("myTask") 
    taskExecutor.execute(myTask); 
} 

}

MyTask sarebbe già inserito nel repository, poiché è possibile configurarlo nella mappatura XML. Uso entrambi questi approcci su base giornaliera, ma tendo a preferire il secondo perché è più facile da leggere e aiuta a mantenere gli sviluppatori onesti, assicurando che non facciano cose che non sono facilmente testabili, e francamente, è più chiaro per l'osservatore casuale.

11

provare

public class MyTask implements Runnable { 
    private MyRepository myRepository; 

    public MyTask(MyRepository myRepository) { 
     this.myRepository = myRepository; 
    } 

    @Override 
    public void run() { 
     myRepository.doSomething(); 
    } 
} 

@Service 
public class MyService { 
    @Autowired private TaskExecutor taskExecutor; 
    @Autowired private MyRepository myRepository; 


    public void someMethod() { 
     MyTask myTask = new MyTask(myRepository); 
     taskExecutor.execute(myTask); 
    } 
} 

oppure è possibile dichiarare la portata del MyTask = "prototipo" e cambiare MyService come

@Service 
public class MyService { 
    @Autowired private ApplicationContext ctx; 

    public void someMethod() { 
     MyTask myTask = ctx.getBean(MyTask.class); 
     taskExecutor.execute(myTask); 
    } 
} 
+0

Sì, questo funzionerebbe. Speravo di ottenere l'Autowiring lavorando nell'attività perché ho numerose dipendenze e preferisco non passarle tutte - tuttavia, sembra che non ci sia un modo per aggirarlo. –

+1

C'è un altro modo, vedi aggiornamento –

+0

@EvgeniyDorofeev come posso definire MyTask come prototipo? – Dejell

Problemi correlati