2016-07-14 295 views
4

我需要在我的Runnable Thread下面訪問Spring beans(featureServiceuxService),但我得到的null值爲applicationContext因此我不能在Runnable中獲得Spring bean。我想知道是否可以訪問runnable內的spring bean?如果不是,請給我一個替代方法。在Runnable線程中訪問Spring Bean

我使用Spring 4.0.6Java 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; 

    } 
} 

我打電話可運行如下

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

你叫'setApplicationContext()'運行它之前?您應該也可以向我們展示您如何使用Runnable。 –

+0

@JiriTousek'setApplicationContext()'應該在應用程序啓動時被'Spring'容器調用。我已經更新了調用Runnable – RanPaul

+0

的代碼只能在它知道的bean(對象)上。你在你的代碼中創建了一個Spring無法知道的本地實例(Spring實際上並不使用魔法,即使它有時似乎:) –

回答

1

Spring使用ThreadLocal存儲applicationContext但ExecutorService的創建一個不同的線程在沒有豆的管理和/或beanContext沒有找到任何bean。

請按照此​​來代替。

1

ApplicationContextAware是Spring使用的一個接口,用於將其上下文設置爲Spring自身管理的bean(已知)。由於您自己創建了UserMenuUpdateTask,Spring甚至不知道該實例,也無法設置該字段。

如果你不需要爲每個調用/每個線程創建一個runnable的新實例(即如果UserMenuUpdateTask是無狀態或線程安全的),那麼可以讓Spring管理它(通過註釋或XML配置)並使用在ExecutorService.execute()中的Spring實例化實例。

如果UserMenuUpdateTask一個新的實例只需要每一次,你需要做,而不是調用的類ApplicationContextAware(它假設實例由Spring管理),並給予它之前設置指針,應用程序上下文中UserMenuUpdateTaskExecutorService

0

ApplicationContextAware接口僅在彈簧內部實例化對象時起作用。當你做新的UserMenuUpdateTask(activeUsers) spring不知道任何關於這個對象,因此它不設置applicationContext。

寫構造函數沒有參數,將範圍設置爲原型,並從春天獲取此對象,在下一行設置activeUsers,它應該工作。或者在對象創建後用手設置應用程序。

此外,我建議你到這個線

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) { 
     //......... 
    }