Reputation: 147
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
Reputation: 124441
There are a couple of things wrong with your setup.
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
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
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