7
votes

Printemps: Comment instancier un haricot de printemps qui prend un paramètre d'exécution?

J'ai un haricot de printemps singleton qui crée quelques tâches ( java.util.concurrent.callable 's) au moment de l'exécution pour faire son travail en parallèle. En ce moment, le appelable est défini comme des classes intérieures dans le haricot Singleton et le Singleton Bean les crée simplement en les instanciant avec nouvelle tâche (dans) , où < code> dans est un paramètre connu uniquement au moment de l'exécution.

Maintenant, je veux extraire la classe de tâches interne à une classe de niveau supérieur régulière car je veux apporter la méthode de la tâche transactionnelle, donc j'en ai besoin pour être un haricot de printemps. < / p>

Je suppose que je dois donner mon singleton une sorte d'usine de la tâche S, mais les tâches doivent être prototypes de haricots de ressort qui prennent une valeur d'exécution en tant que paramètre constructeur. Comment puis-je accomplir cela?


3 commentaires

@Boristreukhov: Ce n'est pas une question sur le test des applications multi-threadées, c'est une question sur le printemps. En fait, je vais supprimer la raison n ° 2 de ma question car elle distrait du vrai problème.


Voir: Stackoverflow.com/questions/8772585/ ...


@Bossie ok j'ai enlevé mon commentaire, BTW Je pense que le moyen le plus simple est de créer des haricots de service distincts, de décorer leurs méthodes sous forme transactionnelle, de les injecter à votre singleton et de passer "dans" paramètre "dans" des méthodes de service.


3 Réponses :


4
votes

L'usine de haricots du printemps et les nouveaux sont mutuellement exclusives. Vous ne pouvez pas appeler nouveau et vous attendre à ce que cet objet soit sous contrôle de printemps.

Ma suggestion est d'injecter ces tâches dans le singleton. Faire-leur aussi des haricots de printemps.

Vous devez reconnaître que la tâche elle-même ne sera pas une transaction, mais ses dépendances peuvent être. Injectez-les dans les tâches et laissez le ressort gérer les transactions.


4 commentaires

+1 pour baiser. Aucune raison de rendre les choses plus difficiles qu'il ne faut être, il suffit de créer des services transactionnels et de les injecter dans les tâches.


"L'usine de haricots du printemps et les nouvelles sont mutuellement exclusives." Cela peut sembler évident pour la plupart, mais pour un nouveau-frère, cela était très important pour moi d'entendre. Cela m'a aidé à comprendre ce que le printemps fait réellement.


Mais que si je ne connais pas le nombre de tâches? C'est à dire. Quelqu'un soumet un emploi avec un numéro, par exemple, et j'instantiens 10 tâches? Pourriez-vous s'il vous plaît dire comment injecter des tâches à Singleton dans ce cas?


Vous devriez créer un pool de exécuteurs et les laisser gérer vos tâches. Oubliez le singleton et apprenez le printemps.



3
votes

Votre haricot Singleton peut mettre en œuvre des haricots de basefactoryaware et de recherche de l'usine de printemps contenant.

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;
    }   
}
///


0 commentaires

4
votes

Une autre approche peut être d'utiliser l'annotation @configury code> de Spring avec le tissage de charge de charge, de cette façon, vous pouvez utiliser nouveau code> (au lieu d'une usine de haricot) pour créer des appels câblés AU RUNTIME:

@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);


0 commentaires