Reputation: 3848
I need to access Spring beans(featureService
and uxService
) in my Runnable Thread below but am getting null
value for applicationContext
hence I couldnt get Spring beans inside the Runnable. I am wondering if its possible to access spring beans inside a runnable or not? if not please suggest me an alternative approach.
I am using Spring 4.0.6
and 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;
}
}
I am calling the runnable as below
ExecutorService es = Executors.newCachedThreadPool();
es.execute(new UserMenuUpdateTask(activeUsers));
Upvotes: 10
Views: 12738
Reputation: 116
ApplicationContextAware interface works only when object is instantiated inside spring. When you do new UserMenuUpdateTask(activeUsers) spring doesn't know anything about this object hence it doesn't set applicationContext.
Write constructor without parameters, set scope to prototype and get this object from spring, at next line set activeUsers and it should work. Or set application by hands after object creation.
Also I would recommend you to change this lines
for (User user : userNamesList) {
featureService = (FeatureService) applicationContext.getBean("featureService");
uxService = (UxService) applicationContext.getBean("uxService");
//.........
}
to
featureService = (FeatureService) applicationContext.getBean("featureService");
uxService = (UxService) applicationContext.getBean("uxService");
for (User user : userNamesList) {
//.........
}
Upvotes: 1
Reputation: 12440
ApplicationContextAware
is an interface used by Spring to set its context into beans that Spring itself manages (knows about). Since you create the UserMenuUpdateTask
yourself, Spring does not even know about the instance and cannot set the field.
If you don't need a new instance of your runnable for every call / every thread (i.e. if the UserMenuUpdateTask
is stateless or thread-safe), you can let Spring manage it (through annotations or XML configuration) and use the Spring-instantiated instance in ExecutorService.execute()
.
If a new instance of UserMenuUpdateTask
is needed every time, you'll need to instead make the calling class ApplicationContextAware
(assuming instance of it is managed by Spring), and set the pointer to application context in the UserMenuUpdateTask
before giving it to the ExecutorService
.
Upvotes: 2
Reputation: 1974
Spring uses ThreadLocal to store the applicationContext
but ExecutorService creates a different Thread where no beans are managed and/or the beanContext does not find any beans.
Follow this instructions instead.
Upvotes: 1