2016-07-14 2 views
4

je besoin d'accéder à des grains de printemps (featureService et uxService) dans mon Runnable discussion ci-dessous, mais je reçois null valeur pour applicationContext donc je ne pourrais pas obtenir les haricots à l'intérieur du printemps Runnable. Je me demande s'il est possible d'accéder à des haricots de printemps à l'intérieur d'un runnable ou non? sinon, veuillez me suggérer une autre approche.Accès beans Spring en fil Runnable

J'utilise Spring 4.0.6 et Java 8

@Component 
public class UserMenuUpdateTask implements Runnable, Serializable, ApplicationContextAware { 


    private static final long serialVersionUID = 3336518785505658027L; 

    List<User>     userNamesList; 

    FeatureService    featureService; 

    UXService uxService; 

    private ApplicationContext applicationContext; 

    public UserMegaMenuUpdateTask() {} 

    public UserMegaMenuUpdateTask(List<User> userNamesList) { 
     this.userNamesList = userNamesList; 
    } 

    @Override 
    public void run() { 
     try { 
      for (User user : userNamesList) { 

        featureService = (FeatureService) applicationContext.getBean("featureService"); 
        uxService = (UxService) applicationContext.getBean("uxService");      
       //......... 
      } 
     } catch (BaseApplicationException ex) { 
      throw new BaseApplicationException(ex); 
     } 
    } 

    @Override 
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
     this.applicationContext = applicationContext; 

    } 
} 

J'appelle le runnable comme ci-dessous

ExecutorService es = Executors.newCachedThreadPool(); 
es.execute(new UserMenuUpdateTask(activeUsers)); 
+0

Appelez-vous 'setApplicationContext()' avant de l'exécuter? Vous devriez probablement aussi nous montrer comment vous utilisez le Runnable. –

+0

@JiriTousek 'setApplicationContext()' censé être appelé par le conteneur 'Spring' sur l'application démarrer à droite ..? J'ai mis à jour le code pour appeler le Runnable – RanPaul

+0

Seulement sur les haricots (objets) qu'il connaît. Vous créez une instance locale dans votre code que Spring n'a aucun moyen de connaître (Spring n'utilise en fait pas de magie, même si cela semble parfois :) –

Répondre

1

Spring utilise ThreadLocal pour stocker les applicationContext mais ExecutorService crée un autre fil où aucun haricots sont gérés et/ou le beanContext ne trouve aucun beans.

Suivez à la place .

1

ApplicationContextAware est une interface utilisée par Spring pour définir son contexte dans les beans que Spring lui-même gère (connaît). Puisque vous créez le UserMenuUpdateTask vous-même, Spring ne connaît même pas l'instance et ne peut pas définir le champ. Si vous n'avez pas besoin d'une nouvelle instance de votre runnable pour chaque appel/chaque thread (ie si le UserMenuUpdateTask est sans état ou thread-safe), vous pouvez laisser Spring le gérer (via des annotations ou la configuration XML) et l'utiliser l'instance instanciée par Spring dans ExecutorService.execute().

Si une nouvelle instance de UserMenuUpdateTask est nécessaire à chaque fois, vous devrez plutôt faire la classe d'appel ApplicationContextAware (en supposant par exemple de celui-ci est géré par Spring), et mettre le pointeur sur le contexte de l'application dans le UserMenuUpdateTask avant de le donner au ExecutorService.

0

L'interface ApplicationContextAware fonctionne uniquement lorsque l'objet est instancié au printemps. Lorsque vous faites new UserMenuUpdateTask (activeUsers) spring ne sait rien de cet objet, donc il ne définit pas applicationContext.

Ecrire le constructeur sans paramètres, définir la portée au prototype et obtenir cet objet à partir du printemps, à la ligne suivante définir activeUsers et cela devrait fonctionner. Ou définissez l'application à la main après la création de l'objet.

Aussi je vous recommande de changer ces lignes

for (User user : userNamesList) { 

     featureService = (FeatureService) applicationContext.getBean("featureService"); 
     uxService = (UxService) applicationContext.getBean("uxService");      
      //......... 
     } 

à

featureService = (FeatureService) applicationContext.getBean("featureService"); 
    uxService = (UxService) applicationContext.getBean("uxService");  

    for (User user : userNamesList) { 
     //......... 
    }