suhas_n
suhas_n

Reputation: 147

Spring not injecting a bean into thread

1.How to inject a spring bean into thread

2.How to start a thread inside spring bean.

here is my code.

MyThread.java

@Component
public class MyThread implements Runnable {

    @Autowired
    ApplicationContext applicationContext;

    @Autowired
    SessionFactory sessionFactory;

    public void run() {

        while (true) {
            System.out.println("Inside run()");
            try {
                System.out.println("SessionFactory : " + sessionFactory);
            } catch (Exception e) {
                e.printStackTrace();
            }

            try {
                Thread.sleep(10000);

                System.out.println(Arrays.asList(applicationContext.getBeanDefinitionNames()));

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

}

i am calling run method from below class like (Please suggest if i am following wrong appraoch for calling a thread inside spring bean )

@Component
public class MyServiceCreationListener implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {

        if (event.getApplicationContext().getParent() == null) {
            System.out.println("\nThread Started");
            Thread t = new Thread(new MyThread());
            t.start();

        }
    }
}

spring is not performing dependency injection on MyThread class

Upvotes: 7

Views: 13468

Answers (3)

M. Deinum
M. Deinum

Reputation: 124441

There are a couple of things wrong with your setup.

  1. You shouldn't be creating and managing threads yourself, Java has nice features for that use those.
  2. You are creating new bean instances yourself and expect Spring to know about them and inject dependencies, that isn't going to work.

Spring provides an abstraction to execute tasks, the TaskExecutor. You should configure one and use that to execute your task not create a thread yourself.

Add this to your @Configuration class.

@Bean
public ThreadPoolTaskExecutor taskExecutor() {
    return new ThreadPoolTaskExecutor();
}

Your MyThread should be annotated with @Scope("prototype").

@Component
@Scope("prototype")
public class MyThread implements Runnable { ... }

Now you can inject these beans and an ApplicationContext into your MyServiceCreationListener

@Component
public class MyServiceCreationListener implements ApplicationListener<ContextRefreshedEvent> {

    @Autowired
    private ApplicationContext ctx;
    @Autowired
    private TaskExecutor taskExecutor;        

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {

        if (event.getApplicationContext().getParent() == null) {
            System.out.println("\nThread Started");
            taskExecutor.execute(ctx.getBean(MyThread.class));
        }
    }
}

This will give you a pre-configured, fresh instance of MyThread and execute it on a Thread selected by the TaskExecutor at hand.

Upvotes: 12

gati sahu
gati sahu

Reputation: 2626

You are creating Thread t = new Thread(new MyThread());.Spring container will not inject the dependency and also not maintain the life cycle of bean.

Example :

@Component
@Scope("prototype")
public class PrintThread extends Thread{

    @Override
    public void run() {

        System.out.println(getName() + " is running");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(getName() + " is running");
    }

}

to access the thread object from spring context.

public class ApplicationContextUtils implements ApplicationContextAware {
 private static ApplicationContext ctx;

 private static final String USER_THREAD = "printThread";

  @Override
  public void setApplicationContext(ApplicationContext appContext)
      throws BeansException {
    ctx = appContext;

  }

  public static ApplicationContext getApplicationContext() {
    return ctx;
  }

  public static UserService getUserService(){return ctx.getBean(USER_THREAD );}

}

Upvotes: 0

StanislavL
StanislavL

Reputation: 57381

Your MyThread is created manually rather than via spring context new Thread(new MyThread()); so no chance for spring to inject a bean.

Instead you can add a trick with static access to spring context where you can get a necessary bean from the context (see here or here).

Alternatively you can use ThreadLocal or InheritableThreadLocal to store necessary objects to be used in the thread.

Upvotes: 0

Related Questions