Reputation: 3473
I trying to run async thread on button press in Java GUI application.
My code is:
Config class:
@Configuration
@ComponentScan({"khartn", "khartn.torrentsuploader.processor"})
public class AppConfig {
@Bean(initMethod = "init")
public NewJFrame mainForm() {
System.out.println("init mainForm");
return new NewJFrame();
}
@Bean
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
pool.setCorePoolSize(5);
pool.setMaxPoolSize(10);
pool.setWaitForTasksToCompleteOnShutdown(true);
pool.initialize();
return pool;
}
}
JFrame class:
public class NewJFrame extends javax.swing.JFrame {
@Autowired
FileProcessor fileProcessor;
@Autowired
ThreadPoolTaskExecutor taskExecutor;
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
taskExecutor.execute(new Runnable() {
@Autowired
MyDirectoryReader myDirectoryReader;
@Autowired
AuthThread authThread;
@Override
public void run() {
jLabel3.setText("Авторизация...");
Boolean authSuccessfull = false;
while (!authSuccessfull) {
authSuccessfull = authThread.auth();
}
jLabel3.setText("Загрузка файлов");
myDirectoryReader.readDir();
}
});
}
I got error on line
authSuccessfull = authThread.auth();
java.lang.NullPointerException
at khartn.torrentsuploader.form.NewJFrame$4.run(NewJFrame.java:162)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Why this exception occurs?
And how to fix this exception?
Why my components is not autowired?
Thank you.
Upvotes: 1
Views: 6280
Reputation: 267
Basically, you should not use
taskExecutor.execute(new Runnable(){
// do something here
});
Firstly you have to understand what is Managed Bean and Unmanaged Bean. When you are using Spring, all instances of your java classes will be instantiated and "pre-loaded" the moment you start your application. In another word, all classes will be instantiated and managed by the spring container. In practice, you use @Component (or @Bean if done at @Configuration class) and @Autowired annotations.
When you are using the "new" keyword for the class Runnable, what you are doing is breaking the rule of having spring to manage all your beans (or classes). Now the "new Runnable(){}"
is no longer managed by spring, yet you are expecting spring to inject all the @Autowired classes in your Runnable class. All @Autowired objects in the new Runnable(){}
is already out of reach from spring.
You may refer to this link to check out how mkyong uses ThreadPoolTaskExecutor. Do note on the part where he named the class PrintTask implements Runnable
. Hope this helps =)
Upvotes: 0
Reputation: 14855
Beans will not get autowired if your class is not initiated by the context. In other words,
If your class NewJFrame
is manually initiated by the new
keyword, spring framework will not be able to autowire
the property variables inside that class.
Do something thing like this.
@Component("mainForm")
public class NewJFrame extends javax.swing.JFrame {
And remove the bean method mainForm
from the configuration java file. And then redesign the NewJform as below. I didn't compile this program. So excuse me for any compilation errors.
Note: The key is to make sure all the @Autowired
properties inside the class where it's initiated by the DI
and NOT by the new
. Your Runnable is also initated by the new
keyword, thats why we need to take the myDirectoryReader
and authThread
out from the anonymous Runnable object.
@Component("mainForm")
public class NewJFrame extends javax.swing.JFrame {
@Autowired
FileProcessor fileProcessor;
@Autowired
ThreadPoolTaskExecutor taskExecutor;
@Autowired
MyDirectoryReader myDirectoryReader;
@Autowired
AuthThread authThread;
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
taskExecutor.execute(new Runnable() {
@Override
public void run() {
...
authSuccessfull = authThread.auth();
...
}
});
}
Upvotes: 2