GD_Java
GD_Java

Reputation: 1429

Not able to get spring service bean in Thread

I have a Spring web application in which I have multiple Service and DAO classes. In normal crud operations everything is working fine. But I am facing issue while injecting dependency in thread.

In my application I need to create a thread and execute it on demand. For this in a controller class I am creating thread like below.

TestThread testThread = new TestThread();
Thread thread = new Thread(testThread);
thread.start(); 

In my thread I am trying to get a dependency like below.

WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();        
TestService testService = (TestService) context.getBean("myService");

My service class looks below.

@Service("myService")
public class TestServiceImpl implements TestService {
    some methods...
}

But every time I am getting below exception.

Exception in thread "Thread-21" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'myService' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:685)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1199)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1081)

Upvotes: 1

Views: 2110

Answers (2)

araknoid
araknoid

Reputation: 3125

As the other stated, if you instantiate a new thread on your own, it will be out of Spring business.

There are 2 things that you can do within the Spring context. First of all is to declare a prototype component thread and demand it to spring whenever you need it:

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

    @Override
    public void run() {
        System.out.println(“Thread is running");
    }

}

As it is scoped prototype, each time you demand it to the spring context, it will be created a new instance each time.

If you don't like this approach, you can define a taskExecutor as a spring bean and then submit your custom CustomTask that implements the Runnable interface:

public class CustomTask implements Runnable {

    @Override
    public void run() {
        System.out.println("CustomTask is running");
    }

}

This can be the configuration for the task executor:

@Bean
public TaskExecutor taskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(5);
    executor.setMaxPoolSize(10);
    executor.setQueueCapacity(25);
    return executor;
}

If you want, you can give a look at the post Spring and Java Thread example that cover these cases.

Upvotes: 0

Oleg Kurbatov
Oleg Kurbatov

Reputation: 1386

Instead implementing your own Thread I'd suggest you to implement a Runnable interface.

class MyTask implements Runnable {
    @Override
    public void run() {
         //your logic is here
    }
}

This class you can even make a prototype bean (using @Scope("prototype") for example). In this case spring will create a new instance of MyTask every time asked for the bean injecting all the dependencies. Any additional intialization that varies from request to request you can do via setter methods.

Once the task instance is fully initialized, you can run it in many different ways.The most simple of them is instantiating dedicated Thread manually.

MyTask task = context.getBean("myTask");
//additional initialization
Thread taskRunner = new Thread(task);
taskRunner.start();

But it does not stand up to your requirement to

execute them one by one after success return of previous threads

For that you can use Executor service. You can inject it with spring or instantiate one inside of your controller:

Executor executor = Executors.newFixedThreadPool(1);

Then executing your task will look somewhat like following:

MyTask task = context.getBean("myTask");
//additional initialization
executor.execute(task); //enqueues the task for future execution

If you are running it on Java 8, you can use a lambda in order to avoid implementing MyTask:

executor.execute(() -> {
    // here you have access to all the injected beans of the controller
    // as well as to arguments of the handler method
});

Upvotes: 1

Related Questions