Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing Spring beans in Runnable thread

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));
like image 358
RanPaul Avatar asked Jul 14 '16 16:07

RanPaul


2 Answers

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.

like image 182
Jiri Tousek Avatar answered Sep 27 '22 16:09

Jiri Tousek


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.

like image 41
Grim Avatar answered Sep 27 '22 15:09

Grim