I need to implement Multi Threaded background process. My project is spring , hibernate based I tried
with below code which uses org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor to
perform the below background operation in multi threaded manner.I need to know why my
thread count always 1 ?
public class UserUpdateProcessor implements InitializingBean {
private ThreadPoolTaskExecutor executor;
public void afterPropertiesSet() throws Exception {
for(int i = 0; i < 10) //added this like after the 1st reply
executor.execute(new UserBackgorundRunner ());
}
}
private class UserBackgorundRunner extends Thread {
public UserBackgorundRunner() {
this.setDaemon(true);
this.setPriority(MIN_PRIORITY);
}
public void run() {
List<User> users = getUserList();;
for (User user : users) {
try {
log.debug("Active count :::::::::::::::::::::::::::::"+executor.getActiveCount());
upgradeUserInBackground(user);
} catch (Exception e) {
LOGGER.warn("Fail to upgrade user");
}
}
}
My spring.xml looks like
<bean id="userThreadPool"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize"><value>10</value></property>
<property name="maxPoolSize"><value>15</value></property>
<property name="queueCapacity"><value>50</value></property>
</bean>
<bean id="userProcessor" class="com.user.UserUpdateProcessor"
autowire="byType">
<property name="executor" ref="userThreadPool" />
</bean>
It is always one because you only ever submit a single Thread to the ThreadPoolTaskExecutor.
Spring's InitializingBean (JavaDoc link) method afterPropertiesSet() is only invoked once in the Applications lifetime, and as far as I can tell from the example you have provided, that is the only thing submitting Thread's to your ThreadPoolTaskExecutor.
Related
I need to create a process that will query a webservice to extract information, and then save the data in my database. However, because this process is very time-intensive, I would like to make it run in the background.
Currently, I have a ProcessHandler which is invoked by a button in the UI. This handler creates a Thread which should run the process in the background. However, I am getting HibernateException with the message No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here.
I have defined ProcessHandler in one of the config xml files (there are several) as follows (this is a very generic definition):
<bean class="com.project.ProcessHandler" parent="parentHandler" />
Inside ProcessHandler, the code to invoke this process is also very generic:
Thread t = new Thread(new WorkerThread(alphaManager, bravoManager, charlieManager));
t.start();
This is the current implementation of WorkerThread:
public class WorkerThread implements Runnable {
private Manager alphaManager;
private Manager bravoManager;
private Manager charlieManager;
public WorkerThread() {
this.alphaManager = null;
this.bravoManager = null;
this.charlieManager= null;
}
public WorkerThread(Manager alphaManager, Manager bravoManager, Manager charlieManager) {
this.alphaManager = alphaManager;
this.bravoManager = bravoManager;
this.charlieManager= charlieManager;
}
#Override
public void run() {
// code to query webservice and extract data...
saveToDbMethod(data);
}
#Transactional(propagation = Propagation.REQUIRED)
private void saveToDbMethod(String data) {
// code to process data...
alphaManager.save(entityA);
bravoManager.save(entityB);
charlieManager.save(entityC);
}
}
The default constructor is a leftover from when I tried to define WorkerThread as a bean in (one of) my config xml files.
Can anyone help me by giving me some tips on how to troubleshoot this?
The problem is that you create the Thread manually and expecting it behave like a spring managed bean.
As the ProcessHandler is a legitimate bean, what i would do is following:
1) Create a seaparate service class which would have the managers as dependencies and that #Transactional method:
#Service
public class Service{
private Manager alphaManager;
private Manager bravoManager;
private Manager charlieManager;
public Service(Manager alphaManager, Manager bravoManager, Manager charlieManager) {
this.alphaManager = alphaManager;
this.bravoManager = bravoManager;
this.charlieManager= charlieManager;
}
#Transactional(propagation = Propagation.REQUIRED)
private void saveToDbMethod(String data) {
// code to process data...
alphaManager.save(entityA);
bravoManager.save(entityB);
charlieManager.save(entityC);
}
}
2) Inject the Service into the ProcessHandler:
<bean class="com.project.ProcessHandler" parent="parentHandler">
<property name="service" ref="service">
</bean>
3) Finally pass the Service to the WorkerThread:
public class WorkerThread implements Runnable {
private Service service;
public WorkerThread(Service service) {
this.service = service;
}
#Override
public void run() {
// code to query webservice and extract data...
service.saveToDbMethod(data);
}
}
and:
Thread t = new Thread(new WorkerThread(service));
t.start();
Now your operations should be transactional and within a session.
In my web services application, I implement asynchronous task executor to insert object in database. But at the first time of insertion it throws below exception.
org.springframework.orm.hibernate3.HibernateSystemException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance:
2nd time when I refresh the url the object is inserted to database successfully.
The problem is with first instance of new request where object is not inserted.
XML file
<bean id="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster">
<property name="taskExecutor">
<bean class="org.springframework.core.task.SimpleAsyncTaskExecutor"></bean>
</property>
</bean>
I used org.springframework.core.task.SimpleAsyncTaskExecutor / org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor and also child table list are clear(), addall(). But no luck.
If I comment the task executor tag, all new request objects are inserted properly.
In my scenario, I have to implement asynchronous task executor.
RptServiceImp.java
public class RptServiceImp{
#javax.annotation.Resource
private ApplicationEventPublisher applicationEventPublisher;
#Transactional
public void process(final RqstLoad rqstLoad ) {
try {
applicationEventPublisher.publishEvent(new LoggingEvt (this));
}catch(Exception e){
System.out.println("e:: "+e);
e.printStackTrace();
}
}
EventListoner.java
#Component
public class EventListener implements ApplicationListener<LoggingEvt > {
#Autowired
private EvntRptDAO evntRptDAO ;
#Override
public void onApplicationEvent(LoggingEvt evnt) {
final CustResource custRsrc = event.getCustResource();
try {
evntRpt er = new evntRpt (custRsrc);
evntRptDAO.saveAndFlush(er);
}
catch(Exception e){
System.out.println("e:: "+e);
e.printStackTrace();
}
}
}
I am trying to implement an event framework using spring events.I came to know that the default behavior of spring event framework is sync. But during spring context initialization if it finds a bean with id applicationEventMulticaster it behaves Async.
Now i want to have both sync and async event publishers in my application, because some of the events needs to be published sync. I tried to configure sync event multicaster using SysncTaskExecutor, but i cant find a way to inject it into my AsyncEventPublisher's applicationEventPublisher property.
My spring configuration file is as below
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor" destroy-method="shutdown">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="WaitForTasksToCompleteOnShutdown" value="true" />
</bean>
<bean id="syncTaskExecutor" class="org.springframework.core.task.SyncTaskExecutor" />
<bean id="customEventPublisher" class="x.spring.event.CustomEventPublisher" />
<bean id="customEventHandler" class="x.spring.event.CustomEventHandler" />
<bean id="eventSource" class="x.spring.event.EventSource" />
<bean id="responseHandler" class="x.spring.event.ResponseHandler" />
<bean id="syncEventSource" class="x.spring.event.syncEventSource" />
<bean id="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster">
<property name="taskExecutor" ref="taskExecutor" />
</bean>
<bean id="syncApplicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster">
<property name="taskExecutor" ref="syncTaskExecutor" />
</bean>
Can anyone help me out here ?
I just had to work this out for myself. By default events are sent asynchronously except if you implement a marker interface, in my case I called it SynchronousEvent. You'll need an 'executor' in your config too (I omitted mine as it's quite customised).
#EnableAsync
#SpringBootConfiguration
public class BigFishConfig {
#Autowired AsyncTaskExecutor executor;
#Bean
public ApplicationEventMulticaster applicationEventMulticaster() {
log.debug("creating multicaster");
return new SimpleApplicationEventMulticaster() {
#Override
public void multicastEvent(final ApplicationEvent event, #Nullable ResolvableType eventType) {
ResolvableType type = eventType != null ? eventType : ResolvableType.forInstance(event);
if (event instanceof PayloadApplicationEvent
&& ((PayloadApplicationEvent<?>) event).getPayload() instanceof SynchronousEvent)
getApplicationListeners(event, type).forEach(l -> invokeListener(l, event));
else
getApplicationListeners(event, type).forEach(l -> executor.execute(() -> invokeListener(l, event)));
}
};
}
...
no, you can't do that, the spring initApplicationEventMulticaster just init only one, and the BeanName must be applicationEventMulticaster. so you just can choose one of below Executor:
- org.springframework.core.task.SyncTaskExecutor
- org.springframework.core.task.SimpleAsyncTaskExecutor
- your own Executor: org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
any way, you can modify org.springframework.context.event.SimpleApplicationEventMulticaster
to add your logic, then you can control whether need to Sync/Async
/**
* Initialize the ApplicationEventMulticaster.
* Uses SimpleApplicationEventMulticaster if none defined in the context.
* #see org.springframework.context.event.SimpleApplicationEventMulticaster
*/
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isDebugEnabled()) {
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
"': using default [" + this.applicationEventMulticaster + "]");
}
}
}
i am not good for edit with stackoverflow. please forgive me.
SyncTaskExecutor
I don't need to add comment that you can know well. this is synchronized. this Executor run task in sequence, and blocked for every task.
public class SyncTaskExecutor implements TaskExecutor, Serializable {
/**
* Executes the given {#code task} synchronously, through direct
* invocation of it's {#link Runnable#run() run()} method.
* #throws IllegalArgumentException if the given {#code task} is {#code null}
*/
#Override
public void execute(Runnable task) {
Assert.notNull(task, "Runnable must not be null");
task.run();
}
}
SimpleAsyncTaskExecutor
This class is very large, so i just choose section of code. If you give threadFactory, will be retrieved Thread from this factory, or will be create new Thread.
protected void doExecute(Runnable task) {
Thread thread = (this.threadFactory != null ? this.threadFactory.newThread(task) : createThread(task));
thread.start();
}
ThreadPoolTaskExecutor
this class use jdk5's current pkg ThreadPoolTaskExecutor. but spring encapsulate functionality. Spring is good at this way, jdk6's current and jdk7'scurrent pkg have some difference.
this will be get Thread from ThreadPool and reuse it, execute every task Asynchronized. If you want to know more detail, see JKD source code.
I tried below tutorial :
https://www.keyup.eu/en/blog/101-synchronous-and-asynchronous-spring-events-in-one-application
It helps in making sync and async multicaster and creates a wrapper over these. Make sure the name of the wrapper class (DistributiveEventMulticaster) is applicationEventMulticaster
I have a simple JFrame as the main window of my Java desktop application and I would like to configure it as a Spring bean. I would like to set properties, inject dependencies and launch it. Here's my frame class:
public class MainFrame extends JFrame {
public MainFrame() {
setTitle("Static Title");
setVisible(true);
}
}
My Spring application context:
<bean class="com.example.MainFrame">
<property name="title" value="Injected Title" />
</bean>
Then I fire it all up...
public static void main(String ... args) {
new ClassPathXmlApplicationContext("applicationContext.xml");
}
...which is followed by this java.beans.IntrospectionException:
type mismatch between indexed and non-indexed methods: location
The frame is actually displayed but there's that exception and the title remains "Static Title". So I have a few questions...
I've seen this being done by IBM in a 2005 tutorial but with Spring 1.2, and I don't even know what JRE. So how do I approach this exception? Is it possible to configure a JFrame as a Spring bean or do I need to proxy it or something?
I'm also wary of not launching the application from the event dispatching thread. So if there's a cleaner way of doing this I'd like to know about it. I can easily dispatch everything except that I don't know how to dispatch the construction itself.
Finally feel free to criticise the overall concept. I haven't come across many examples of Spring managed Swing applications. I'm using Spring-3.1 with Java-1.6.
Thanks.
I'm having the same problem, and it seems that's actually a bug on Spring:
https://jira.springsource.org/browse/SPR-8491
I think I'll wrap a FactoryBean around the panel and see if it works. I'll edit this post later, in case it works (or not)
-- edit --
Okay, instantiating it through a FactoryBean does get around the problem. The declaration becomes a little awkward, but that will have to do, at least until the aforementioned bug is fixed.
package com.ats.jnfe.swing;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.FactoryBean;
/**
* Contorna, em caráter temporário, o bug apontado em:
* https://jira.springsource.org/browse/SPR-8491
* Quando o erro acima for resolvido, esta classe estará obsoleta.
*
* #author HaroldoOliveira
*/
public class SwingFactoryBean<T> implements FactoryBean<T> {
private Class<T> beanClass;
private Map<String, Object> injection;
private String initMethod;
private Map<String, PropertyDescriptor> properties;
private BeanInfo beanInfo;
private Method initMethodRef;
public T getObject() throws Exception {
T t = this.getBeanClass().newInstance();
if (this.getInjection() != null) {
for (Map.Entry<String, Object> en : this.getInjection().entrySet()) {
try {
this.properties.get(en.getKey()).getWriteMethod()
.invoke(t, en.getValue());
} catch (Exception e) {
throw new BeanInitializationException(MessageFormat.format(
"Error initializing property {0} of class {1}",
en.getKey(), this.getBeanClass().getName()), e);
}
}
}
if (this.initMethodRef != null) {
this.initMethodRef.invoke(t);
}
return t;
}
public Class<?> getObjectType() {
return this.getBeanClass();
}
public boolean isSingleton() {
return false;
}
public void initialize() {
try {
this.beanInfo = Introspector.getBeanInfo(this.getBeanClass());
this.properties = new HashMap<String, PropertyDescriptor>();
PropertyDescriptor[] descriptors = this.beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : descriptors) {
this.properties.put(pd.getName(), pd);
}
if (this.getInitMethod() != null) {
this.initMethodRef = this.getBeanClass()
.getMethod(this.getInitMethod());
}
} catch (Exception e) {
throw new BeanInitializationException(
"Error initializing SwingFactoryBean: " + e.getMessage(), e);
}
}
public Class<T> getBeanClass() {
if (this.beanClass == null) {
throw new BeanInitializationException("Class not informed.");
}
return this.beanClass;
}
public void setBeanClass(Class<T> beanClass) {
this.beanClass = beanClass;
}
public Map<String, Object> getInjection() {
return injection;
}
public void setInjection(Map<String, Object> injection) {
this.injection = injection;
}
public String getInitMethod() {
return initMethod;
}
public void setInitMethod(String initMethod) {
this.initMethod = initMethod;
}
}
Usage example:
<bean id="certificadoNFeConfiguracaoDialog" class="com.ats.jnfe.swing.SwingFactoryBean" init-method="initialize" scope="prototype" lazy-init="true">
<property name="beanClass" value="com.ats.ecf.view.swing.util.dialog.OKCancelDialog" />
<property name="initMethod" value="inicializa" />
<property name="injection">
<map>
<entry key="selector">
<bean class="com.ats.jnfe.swing.SwingFactoryBean" init-method="initialize">
<property name="beanClass" value="com.ats.jnfe.swing.CertificadoNFeConfigPanel" />
<property name="initMethod" value="inicializa" />
<property name="injection">
<map>
<entry key="fachada" value-ref="certificadoNFeConfiguracaoFacade" />
</map>
</property>
</bean>
</entry>
</map>
</property>
</bean>
Runs with Spring 3.0.7.RELEASE, 3.1.4.RELEASE und 3.2.3.RELEASE.
It seems it has been a bug as mentioned in another answer.
My thought would be to keep Swing out of Spring. Past anything trivial, wiring up a GUI using something else is going to be too tedious. Instead, I would change what you are doing and just use main() to create the Spring content and then create your GUI.
If all you are doing in Spring would be creating the MainFrame and starting it, maybe the easiest thing is to create a FactoryBean that creates the frame. The factory could also call setVisible() via a SwingUtilities.invokeLater() call.
Confirmed runs with Spring 4.0.2.RELEASE too.
Lest's consider that I have the following:
public class MyRunnable implements Runnable {
public void run() {
//do something expensive
}
}
public class ThreadExecutor {
private TaskExecutor taskExecutor;
public ThreadExecutor(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
public void fireThread(){
taskExecutor.execute(new MyRunnable());
}
}
my xml is the following:
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="25" />
</bean>
<bean id="threadExecutor" class="com.vanilla.threads.controllers.ThreadExecutor">
<constructor-arg ref="taskExecutor" />
</bean>
in my Spring MVC controller I start the task:
#RequestMapping(value="/startTask.html", method=RequestMethod.GET)
public ModelAndView indexView(){
ModelAndView mv = new ModelAndView("index");
threadExecutor.fireThread();
return mv;
}
Now let's consider that I would like to create another request(#RequestMapping(value="/checkStatus.html") which will tell if the the task started in my previous Request has been finished.
So my questions are simple:
1) Can I assign name to the task in TaskExecutor and if yes, how can I do it?
2) How can I check that the task with that specific name has been done?
1) No, but..
Instead of using taskExecutor.execute() use taskExecutor.submit() which returns a Future. Put the Future in the HttpSession, and when a checkStatus request comes in, pull the Future from the session and call isDone() on it. If you need to give it a name then instead of putting the Future in the session directly have a Map<String, Future> in the session where the key is the name of your task.