2012-02-24 20 views
7

Tengo un bean Singleton Spring que crea un par de tareas (java.util.concurrent.Callable) en tiempo de ejecución para hacer su trabajo en paralelo. En este momento, los Callable se definen como clases internas en el bean singleton, y el bean singleton los crea simplemente instanciandolos con new Task(in), donde in es un parámetro conocido solo en tiempo de ejecución.Spring: ¿cómo instanciar un bean Spring que toma un parámetro de tiempo de ejecución?

Ahora quiero extraer la clase Task interna a una clase de nivel superior porque quiero que el método call() de la Tarea sea transaccional, por lo que necesito que sea un Spring Bean.

Supongo que necesito darle a mi singleton algún tipo de fábrica de Task s, pero las tareas tienen que ser prototipos Spring beans que toman un valor de tiempo de ejecución como parámetro de constructor. ¿Cómo puedo lograr esto?

+0

@BorisTreukhov: esta no es una pregunta sobre la prueba de aplicaciones de subprocesos múltiples, esta es una pregunta acerca de Spring. De hecho, voy a eliminar la razón # 2 de mi pregunta porque distrae del problema real. –

+0

Ver: http://stackoverflow.com/questions/8772585/spring-bean-with-dynamic-constructor-value – quaylar

+0

@Bossie bien me quita mi comentario, por cierto creo que la forma más sencilla es crear un servicio separado beans, decore sus métodos como transaccionales, inyéctelos a su singleton y pase el parámetro "in" a los métodos de servicio. –

Respuesta

2

Fábrica de judías de primavera y nuevas son mutuamente exclusivas. No puede llamar a nuevo y esperar que ese objeto esté bajo el control de Spring.

Mi sugerencia es inyectar esas tareas en Singleton. Hágales también frijoles de primavera.

Debe reconocer que la tarea en sí misma no va a ser una transacción, pero sí sus dependencias. Inyecte esos en las Tareas y deje que Spring administre las transacciones.

+0

+1 para KISS. No hay razón para hacer las cosas más difíciles de lo que deben ser, simplemente cree servicios transaccionales e inyéctelos en las tareas. – pap

+0

"La fábrica de frijoles de primavera y las nuevas son mutuamente exclusivas". Puede parecer obvio para la mayoría, pero para un novato de primavera fue muy importante para mí escucharlo. Me ayudó a entender lo que realmente hace la primavera. –

+0

¿Pero qué sucede si no sé la cantidad de tareas? Es decir. alguien envía un trabajo con un número, digamos 10, y yo instauro 10 tareas? ¿Podría decirnos cómo inyectar tareas en Singleton en ese caso? –

3

Su bean singleton puede implementar BeanFactoryAware y buscar beans de la fábrica de muelles que lo contiene.

import org.springframework.beans.BeansException; 
import org.springframework.beans.factory.BeanFactory; 
import org.springframework.beans.factory.BeanFactoryAware; 

public class MyBeanFactory implements BeanFactoryAware { 

    private BeanFactory beanFactory; 

    public void setBeanFactory(BeanFactory beanFactory) 
      throws BeansException { 
     this.beanFactory = beanFactory;  
    } 

    public Task createTask(Task in) { 
     return beanFactory.getBean("task",in); 
    } 

} 
/////////////// 

import java.util.concurrent.Callable; 
import org.springframework.beans.factory.annotation.Configurable; 
import org.springframework.context.annotation.Scope; 
import org.springframework.transaction.annotation.Transactional; 

@Configurable // unless using xml based config 
@Scope(value="prototype") // tell bean factory to create new instance each time 
public class Task implements Callable<Object> { 

    private Object in; 

    public Task(Object in) { 
     super(); 
     this.in = in; 
    } 

    @Transactional 
    public Object call() throws Exception { 
     //do real work 
     return in; 
    } 
} 
/// 
4

Otro enfoque podría ser utilizar @Configurable anotación de la primavera con el tejido en tiempo de carga, de esta manera puede utilizar new (en lugar de una fábrica de beans) para crear cable rescatable de en tiempo de ejecución:

@Configurable 
public class WiredTask implements Callable<Result> { 

    @Autowired 
    private TaskExecutor executor; 

    public WiredTask(String in) { 
     this.in = in; 
    } 

    public Result call() { 
     return executor.run(in); 
    } 
} 

@Bean @Scope("prototype") 
public class TaskExecutor() { 

    @Transactional 
    public Result run(String in) { 
     ... 
    } 
} 

// Example of how you might then use it in your singleton... 
ExecutorService pool = Executors.newFixedThreadPool(3); 
WiredTask task = new WiredTask("payload"); 
Future<Result> result = pool.submit(task); 

Ver this article para más información. Tenga en cuenta que no puede usar @Configurable and @Transactional in the same bean, de ahí la necesidad de dos clases. Por esa razón, esta podría no ser la solución ideal si tiene muchas implementaciones diferentes de Callable (ya que necesitará 2 clases para cada una).

Cuestiones relacionadas