Spring not injecting a bean into thread - spring

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

There are a couple of things wrong with your setup.
You shouldn't be creating and managing threads yourself, Java has nice features for that use those.
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.

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.

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 );}
}

Related

ThreadPoolExecutor and Spring Async

Initially I was using regular java Multithreading using the 'implements' method. However #Autowired does not work when a class is created with new in Spring, so I am trying to change it to using Spring'sAsync method. This is what I have so far. How would I go about adding the threads to the ThreadPoolExecutor?
The class that should create the threads
#Component
public class ScheduledCountyScraper {
#Autowired
StateScrapeQueueRepository stateScrapeQueueRepository;
#Autowired
CountyScrapeRepository countyScrapeRepository;
// #Scheduled(cron = "0 0 */3 * * *")
#EventListener(ApplicationReadyEvent.class)
public void scrapeCountyLinks() {
System.out.println("Scrape county links ran!");
try {
List<String> stateLinks = stateScrapeQueueRepository.getStatesLinks(website);
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
//what to do here?
executor.shutdown();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("---------------------");
}
}
}
The Async class
#Component
#EnableAsync
public class CountyScraper {
volatile private String stateLink;
#Autowired
StateScrapeQueueRepository stateScrapeQueueRepository;
#Autowired
CountyScrapeRepository countyScrapeRepository;
public CountyScraper() {
}
public CountyScraper(String stateLink) {
this.stateLink = stateLink;
}
#Async("countyScraper")
public void run() {
try {
// other code
stateScrapeQueueRepository.updateScrapeTimestamp(stateLink);
countyScrapeRepository.insertCountyLinks(countyLinks, website);
} catch (Exception e) {
e.printStackTrace();
}
}
}
By default Spring uses a SimpleAsyncTaskExecutor to execute async methods. This will by default spawn a new thread for every operation.
To define your own executor for use with async tasks, create a bean that implements the TaskExecutor interface or an Executor bean named "taskExecutor".
If you'd like to have your own custom executor just for this component, you can implement AsyncConfigurer and provide your own executor service:
#Override
public Executor getAsyncExecutor() {
return MY_EXECUTOR;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return MY_EXCEPTION_HANDLER;
}

Spring Autowired Shared Queue NullPointerException

I'm using Spring for the first time and am trying to implement a shared queue wherein a Kafka listener puts messages on the shared queue, and a ThreadManager that will eventually do something multithreaded with the items it takes off the shared queue. Here is my current implementation:
The Listener:
#Component
public class Listener {
#Autowired
private QueueConfig queueConfig;
private ExecutorService executorService;
private List<Future> futuresThread1 = new ArrayList<>();
public Listener() {
Properties appProps = new AppProperties().get();
this.executorService = Executors.newFixedThreadPool(Integer.parseInt(appProps.getProperty("listenerThreads")));
}
//TODO: how can I pass an approp into this annotation?
#KafkaListener(id = "id0", topics = "bose.cdp.ingest.marge.boseaccount.normalized")
public void listener(ConsumerRecord<?, ?> record) throws InterruptedException, ExecutionException
{
futuresThread1.add(executorService.submit(new Runnable() {
#Override public void run() {
try{
queueConfig.blockingQueue().put(record);
// System.out.println(queueConfig.blockingQueue().take());
} catch (Exception e){
System.out.print(e.toString());
}
}
}));
}
}
The Queue:
#Configuration
public class QueueConfig {
private Properties appProps = new AppProperties().get();
#Bean
public BlockingQueue<ConsumerRecord> blockingQueue() {
return new ArrayBlockingQueue<>(
Integer.parseInt(appProps.getProperty("blockingQueueSize"))
);
}
}
The ThreadManager:
#Component
public class ThreadManager {
#Autowired
private QueueConfig queueConfig;
private int threads;
public ThreadManager() {
Properties appProps = new AppProperties().get();
this.threads = Integer.parseInt(appProps.getProperty("threadManagerThreads"));
}
public void run() throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(threads);
try {
while (true){
queueConfig.blockingQueue().take();
}
} catch (Exception e){
System.out.print(e.toString());
executorService.shutdownNow();
executorService.awaitTermination(1, TimeUnit.SECONDS);
}
}
}
Lastly, the main thread where everything is started from:
#SpringBootApplication
public class SourceAccountListenerApp {
public static void main(String[] args) {
SpringApplication.run(SourceAccountListenerApp.class, args);
ThreadManager threadManager = new ThreadManager();
try{
threadManager.run();
} catch (Exception e) {
System.out.println(e.toString());
}
}
}
The problem
I can tell when running this in the debugger that the Listener is adding things to the queue. When the ThreadManager takes off the shared queue, it tells me the queue is null and I get an NPE. It seems like autowiring isn't working to connect the queue the listener is using to the ThreadManager. Any help appreciated.
This is the problem:
ThreadManager threadManager = new ThreadManager();
Since you are creating the instance manually, you cannot use the DI provided by Spring.
One simple solution is implement a CommandLineRunner, that will be executed after the complete SourceAccountListenerApp initialization:
#SpringBootApplication
public class SourceAccountListenerApp {
public static void main(String[] args) {
SpringApplication.run(SourceAccountListenerApp.class, args);
}
// Create the CommandLineRunner Bean and inject ThreadManager
#Bean
CommandLineRunner runner(ThreadManager manager){
return args -> {
manager.run();
};
}
}
You use SpringĀ“s programatic, so called 'JavaConfig', way of setting up Spring beans (classes annotated with #Configuration with methods annotated with #Bean). Usually at application startup Spring will call those #Bean methods under the hood and register them in it's application context (if scope is singleton - the default - this will happen only once!). No need to call those #Bean methods anywhere in your code directly... you must not, otherwise you will get a separate, fresh instance that possibly is not fully configured!
Instead, you need to inject the BlockingQueue<ConsumerRecord> that you 'configured' in your QueueConfig.blockingQueue() method into your ThreadManager. Since the queue seems to be a mandatory dependency for the ThreadManager to work, I'd let Spring inject it via constructor:
#Component
public class ThreadManager {
private int threads;
// add instance var for queue...
private BlockingQueue<ConsumerRecord> blockingQueue;
// you could add #Autowired annotation to BlockingQueue param,
// but I believe it's not mandatory...
public ThreadManager(BlockingQueue<ConsumerRecord> blockingQueue) {
Properties appProps = new AppProperties().get();
this.threads = Integer.parseInt(appProps.getProperty("threadManagerThreads"));
this.blockingQueue = blockingQueue;
}
public void run() throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(threads);
try {
while (true){
this.blockingQueue.take();
}
} catch (Exception e){
System.out.print(e.toString());
executorService.shutdownNow();
executorService.awaitTermination(1, TimeUnit.SECONDS);
}
}
}
Just to clarify one more thing: by default the method name of a #Bean method is used by Spring to assign this bean a unique ID (method name == bean id). So your method is called blockingQueue, means your BlockingQueue<ConsumerRecord> instance will also be registered with id blockingQueue in application context. The new constructor parameter is also named blockingQueue and it's type matches BlockingQueue<ConsumerRecord>. Simplified, that's one way Spring looks up and injects/wires dependencies.

Autowiring not working in springboot application

I am trying to create a Spring boot application with JFrame. I can see my beans in applicationContext but they are not getting autowired. I am unable to find the reason for this issue. Can someone help me with this?
Here is the code:
JavauiApplication - it is showing both userManager and userNameRepository is beans
#SpringBootApplication
public class JavauiApplication implements CommandLineRunner {
#Autowired
private ApplicationContext appContext;
public static void main(String[] args) {
new SpringApplicationBuilder(JavauiApplication.class).headless(false).run(args);
java.awt.EventQueue.invokeLater(() -> new InputNameForm().setVisible(true));
}
#Override
public void run(String... args) throws Exception {
String[] beans = appContext.getBeanDefinitionNames();
Arrays.sort(beans);
for (String bean : beans) {
System.out.println(bean);
}
}
}
InputNameForm.java -> userManager coming null
#Component
public class InputNameForm extends javax.swing.JFrame {
/**
* Creates new form InputNameForm
*/
public InputNameForm() {
initComponents();
}
#Autowired
UserManager userManager;
private void submitButtonActionPerformed(java.awt.event.ActionEvent evt) {
userManager.setName(firstName.getText(), lastName.getText());
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(InputNameForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new InputNameForm().setVisible(true);
}
});
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JTextField firstName;
private javax.swing.JLabel firstNameLabel;
private javax.swing.JTextField lastName;
private javax.swing.JLabel lastNameLabel;
private javax.swing.JButton submitButton;
// End of variables declaration//GEN-END:variables
}
UserManager.java -> userNameRepository is coming null
#Component
public class UserManager {
#Autowired
UserNameRepository userNameRepository;
public void setName(String firstName, String lastName) {
userNameRepository.save(new UserName(firstName, lastName));
System.out.println(userNameRepository.findAllByFirstName(firstName));
}
}
It's a very common problem and it occurs because newcomers don't understand how the IoC container works.
Firstly, BeanDefinitionReader reads metadata about your beans from XML, Annotations(#Component, #Service etc), JavaConfig or Groovy script.
There are several BeanPostProcessor's which is responsible for reading all of these Spring annotation you're writing(#Autowired etc).
BeanFactory creates all BeanPostProcessor's then it creates all of your beans.
What happen if you create your bean with #Autowired dependencies via new operator? Nothing, because it isn't actually a bean. The object you created isn't related to IoC container. You may have the bean already in your ApplicationContext if you marked it with #Component(for example) but the object which was created via new operator wont be processed by Spring(annotations won't work).
Hope this helps.
PS: The lifecycle is simplified.
I had the same problem few days ago. What I undertood was that GUI builders like the one that comes with netbeans will automatically create components using new keyword. This means that those components won't be manage by spring. The code usually loks like this:
private void initComponents() {
jPanel1 = new javax.swing.JPanel(); //This component will not be managed by spring.
//...
}
You could use the following class provided here, to make it work.
#Component
public class BeanProvider {
private static ApplicationContext applicationContext;
// Autowires the specified object in the spring context
public static void autowire(Object object) {
applicationContext.getAutowireCapableBeanFactory().autowireBean(object);
}
#Autowired
private void setApplicationContext(ApplicationContext applicationContext) {
BeanProvider.applicationContext = applicationContext;
}
}
The top level SwingApp class:
#SpringBootApplication
public class SwingApp implements CommandLineRunner {
public static void main(String[] args) {
new SpringApplicationBuilder(SwingApp.class)
.headless(false).bannerMode(Banner.Mode.OFF).run(args);
}
#Override
public void run(String... args) throws Exception {
SwingUtilities.invokeLater(() -> {
MainFrame frame = new MainFrame();
frame.setVisible(true);
});
}
}
The MainFrame class:
public class MainFrame extends javax.swing.JFrame {
public MainFrame() {
initComponents();
}
private void initComponents() {
//Gui Builder generated code. Bean not managed by spring.
//Thus, autowired inside CustomPanel won't work if you rely on ComponentScan.
jPanel1 = new CustomJPanel();
//...
}
private CustomJPanel jPanel1;
}
The panel class where you want to autowire things:
//#Component //not needed since it wont work with gui generated code.
public class CustomJPanel extends javax.swing.JPanel{
#Autowired
private SomeRepository someRepository
public CustomJPanel(){
BeanProvider.autowire(this); //use someRepository somewhere after this line.
}
}
I have the same problem in a JavaFx project. Service and Component annotated classes were null in UI controllers even if it was shown in context that it was created. Below code worked for me
#Component
public class FxmlLoaderWithContext {
private final ApplicationContext context;
#Autowired
public FxmlLoaderWithContext(ApplicationContext context) {
this.context = context;
FXMLLoader fxmlloader = new FXMLLoader();
fxmlloader.setControllerFactory(context::getBean); //this row ensure services and components to be autowired
}
}
I think it returns null because you using command new to create object, such as new InputNameForm(). When creating object like that, the object isn't managed by Spring. That's why autowired not working.
The solution is registering your class as a bean.
You can use a class like in here.
#Component
public class BeanProvider {
private static ApplicationContext applicationContext;
public static void autowire(Object object) {
applicationContext.getAutowireCapableBeanFactory().autowireBean(object);
}
#Autowired
private void setApplicationContext(ApplicationContext applicationContext) {
BeanProvider.applicationContext = applicationContext;
}
}
And then, in your class InputNameForm constructor, call this:
class InputNameForm() {
BeanProvider.autowire(this);
...
}
And that's it. Spring will take care the rest.

Injecting externalized value from properties file by annotation into Spring

This method doesn't work
How can I read my properties file and inject my variable in my Scheduled like:
#Scheduled(fixedRateString ="${frequence.move}")
#Configuration
#PropertySource( "resources.properties")
public class Scheduler {
private static ApplicationContext applicationContext=new AnnotationConfigApplicationContext(
Scheduler.class);
#Autowired
public Environment envi;
public static final String time=applicationContext.getBean(Environment.class).getProperty("frequence.move";
#Scheduled(fixedRateString ="${frequence.move}")
public void doTask() {
AnnotationConfigApplicationContext applicationContext
= new AnnotationConfigApplicationContext(BatchConfigEMS.class);
JobLauncher launcher = (JobLauncher) applicationContext.getBean(JobLauncher.class);
Job job = (Job) applicationContext.getBean(Job.class);
try {
test();
launcher.run(job, new JobParameters());
} catch (JobExecutionAlreadyRunningException e) {
e.printStackTrace();
} catch (JobRestartException e) {
e.printStackTrace();
} catch (JobInstanceAlreadyCompleteException e) {
e.printStackTrace();
} catch (JobParametersInvalidException e) {
e.printStackTrace();
}
}
Your code is flawed in a couple of ways. Basically as soon as you feel the need to create an instance of an ApplicationContext you should stop, think and act. As generally that is a sign you are doing things wrong.
To get beans use auto wiring, wire the beans into the classes as they need.
First make your Scheduler a #Component instead of a #Configuration and auto wire the needed beans.
#Component
public class Scheduler {
#Autowired
private JobLauncher launcher;
#Autowired
private Job job;
#Scheduled(fixedRateString ="${frequence.move}")
public void doTask() throws JobExecutionException {
test();
launcher.run(job, new JobParameters());
}
}
In your BatchConfigEMS add the #PropertySource and make sure you have a public static bean of the type PropertySourcesPlaceholderConfigurer.
#Configuration
#PropertySource( "resources.properties")
public class BatchConfigEMS {
#Bean
public static PropertySourcesPlaceholderConfigurer configurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Assuming you have a web application load the configuration ones and everything else should be auto wired. The placeholders should get replaced because of the added configurer.
this is my file (resource.properties)
fournisseur.key =false
produit.key = true
frequence.move = 5000
frequence.delete = 5000
i want just take this key[frequence.move] from my file properties
and use it here :
#Scheduled(fixedRateString = "${frequence.move}")
public void doTask() {
all the code here it work
}
I write what you advice me and that doesn't work

Class Cast Exception in while mocking bean

I am trying to create test cases in my application using powermock and TestNG. This is a web application and spring context xml is loaded through web.xml. I want to mock the spring context xml with my own test xml and access beans from there.
ContextLoader Code
public class AppContextLoader implements ApplicationContextAware {
private static ApplicationContext context;
public void setApplicationContext(ApplicationContext context) {
this.context = context;
}
public static Object getBean(String beanName) {
return context.getBean(beanName);
}
}
I am trying to access a bean later in my code like below
XMLConverter converter = (XMLConverter) AppContextLoader.getBean("XMLConverter");
Below is my Test Code
#PrepareForTest(AppContextLoader.class)
#PowerMockIgnore({"javax.management.*", "javax.xml.*","org.xml.*","org.w3c.dom.*"})
public class ImplTest {
Impl impl;
ApplicationContext context;
#ObjectFactory
/**
* Configure TestNG to use the PowerMock object factory.
*/
public IObjectFactory getObjectFactory() {
return new org.powermock.modules.testng.PowerMockObjectFactory();
}
#BeforeClass
public void setUp() throws Exception {
impl = new Impl();
context = new ClassPathXmlApplicationContext("Test_config.xml");
}
#Test
public void execute() {
try {
PowerMock.mockStatic(AppContextLoader.class);
expect(AppContextLoader.getBean("XMLConverter")).andReturn(context.getBean("XMLConverter"));
PowerMock.replay(AppContextLoader.class);
actualResponse = impl.execute(request, "");
//PowerMock.verify(AppContextLoader.class);
Assert.assertEquals("", actualResponse);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
When I am executing this code I am getting below error:
java.lang.ClassCastException: com.xxx.xxx.xxx.xxx.bean.XMLConverter cannot be cast to com.xxx.xxx.xxx.xxx.bean.XMLConverter
I am new to unit testing, and not sure what is causing this issue where same class are not able to cast each other. Any help will be appreciated

Resources