Spring Boot calling Spring Batch Job - spring

Below is my sequence
Spring Boot main class has run() method which in turn calls spring batch job.
when i execute above main class it executes the job first and then later executes my run() method.
If i disable the job , run() method executes first.
is there any way i can execute run()method first and then later call job.
Spring boot with run
MemberTaskletsApplication{
has some create statements
}
SpringApplication.run(MemberTaskletsApplication.class, args);
batch job class
public class ReadWriteBatchImpl {
has reader/writer methods
}
Thank you

Related

Spring web run after startup

I run a spring web application (not spring boot).
On startup the application requests a dataset from another server. This dataset takes about a minute to be processed. When I deploy this application to the tomcat, it takes a minute. The website itself will not be available until the dataset request has been processed completely. But actually I would like to see, that users are already able to login and the dataset is processed without stopping the rest of the application from working.
Currently I have a service class and use the #PostConstruct-Annotation.
#Service
public class StartupService {
#PostConstruct
public void load() {
//perform the dataset request
...
}
}
I found similar article here on stackoverflow, that suggested trying the ApplicationListener. But this has the same effect. HTTP Requests to the website are not answered unless the dataset request has finished.
#Service
public class StartupService implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(final ContextRefreshedEvent event) {
//perform the dataset request
...
}
}
Of course it would be possible, to start a new Thread, but I would like to know, what the best approach for this problem would be.
From the PostConstruct doc:
... This method MUST be invoked before the class is put into service...
So Spring cannot service a request until the #PostContruct method finishes.
As you suggested, start a new thread manually, or:
from the #PostConstruct method, call a public method in another bean annotated with #Async and Spring will asynchronously invoke the method which will allow the #PostConstruct method to finish immediately and start servicing requests
from the #PostConstruct method, #Schedule a one time task - for example 1 minute from now
See also: #EnableAsync and/or #EnableScheduling

#Async and #Transaction aspect order

Using Spring Boot 2.1.1.RELEASE / Spring Framework 5.1.4, I have an application with #Async and #Transactional annotations enabled through:
#EnableAsync(mode = AdviceMode.ASPECTJ)
#EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
When running a method that is annotated with both, first the transaction is created and then the asynchronous execution starts. So, the actual method body is not executed inside the transaction.
#Transactional
#Async
public void myAsyncMethod() {
// asynchronous database stuff
}
How can I configure spring / the aspects to actually execute in an order that makes sense, e.g. start the transaction on the new thread?
On a side note, with the older Spring Boot 1.5.17 / Spring Framework 4.3.20 it actually worked.
Demo: https://github.com/jaarts/spring-asynctransaction-demo
In Spring 5 Async advice is always execited first. See AsyncAnnotationBeanPostProcessor
public AsyncAnnotationBeanPostProcessor() {
setBeforeExistingAdvisors(true);
}
After that on superclass in postProcessAfterInitialization when advisors aplies code executes
if (this.beforeExistingAdvisors) {
advised.addAdvisor(0, this.advisor);
}
On #EnableTransactionManagement#order javadoc says
Indicate the ordering of the execution of the transaction advisor
but on #EnableAsync
Indicate the order in which the AsyncAnnotationBeanPostProcessor should be applied.

How to avoid loading all the beans of the other Batch job if not running it

I am new to the Spring Batch wanted to understand how we can avoid the below issue. In my project, we are using AppCommonConfig where we've listed all the batch files to be called and using Spring Boot. When I run the AAA batch job, it loads all the beans of other batch job as well which I think is not the correct approach.
How we can avoid or tweak the below code ?
I only wanted to load those beans which are part of my currently running batch job.
AppCommonConfig.java
#Configuration
#ComponentScan("com.test1.test2")
#EnableBatchProcessing
#EnableScheduling
#PropertySource("classpath:appconfig.properties")
#ImportResource({ "classpath:META-INF/Q.xml", "classpath:META-INF/R.xml",
"classpath:META-INF/ABC.xml",
"classpath:META-INF/XYZ.xml",
"classpath*:META-INF/AAA.xml", "classpath*:META-INF/YYY.xml",
"classpath*:META-INF/KKK.xml", "classpath:META-INF/BBB.xml",
"classpath:META-INF/CCC.xml",
"classpath:META-INF/DDD.xml",
"classpath:META-INF/EEE.xml" ,
............
...............
...............
...................
"classpath:META-INF/ZZZ.xml"})
public class AppCommonConfig {
#Bean
BatchConfigurer configurer(#Qualifier("batchDataSource") DataSource dataSource) {
return new DefaultBatchConfigurer(dataSource);
}
}
You can use Spring profiles: https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-definition-profiles.
In your case, you can have one profile per job. When you run your app with a specific profile, only the beans of that profile will be loaded.
As a side note, It seems not natural to me to have a AppCommonConfig class where you import all the batch job definitions. I would put only common beans in that class (data source, transaction manager, etc) and create a separate class for each job (in which case, you won't probably need to use profiles as beans are separated by design).

Spring, Run task once when application started

My application is based on spring boot.
I want to create a task which should be run only once after application has been started.
Currently, I am looking into two solutions:
Using #Scheduled and boolean property which should determine whether the logic shold be run or not.
#Scheduled
public void method(){
if(method_run_propery){
//do something;
}
}
Using Quartz. But I have not used before.
Please, tell me what is the best approach to use in this case.
Spring has a #PostConstruct annotation to do exactly that. Runs once the bean has been initialized and all dependencies added.
If it has to be run once immediately after application is initialized, I would simply start it from the init method of a singleton bean. Spring ensures that at be time it will be run all dependant beans will have been initialized.
For example, assuming a Java annotation Spring configuration you could use something like:
#Bean(init_method="init")
class TaskLauncher {
#Autowired DependantBeanClass dependant Bean;
...
public void init() {
// execute or start the task, eventually using the autowired dependant beans
...
}
}
When the context is refreshed, Spring autowire everything, initializes the dependant beans and then will call once the init method of the TaskLauncher bean.
No need for #Scheduler nor Quartz if you only need to start something at Spring initialization time
One of the ways is to implement ApplicationListener
Once spring context is initialized, Your class which implements ApplicationListener
which will then have onApplicationEvent method will be invoked, your logic can go in this method.

Using PersistenceContext in a Quartz Job

We're using Spring 3.1, JPA (via Hibernate) and Quartz. Typically we interact with the DB via #PersistenceContext annotation on Service beans, and either SpringMVC controllers, or GraniteDS-managed service invocation.
I'm working on writing a Quartz job that needs to interact with the database. I've tried everything I can find to get this working. I tried passing in a Spring-managed component (annotated with #PersistenceContext and #Transactional) via the jobMap, the call to entityManager.persist(o) executes, but nothing happens in the database. I also tried similar to this answer, creating a factory class to call autowireBean() on the job object. I set up the job class like so:
public class CreateAlertJob implements Job {
#PersistenceContext
EntityManager entityManager;
#Override
#Transactional
public void execute(JobExecutionContext context) throws JobExecutionException {
SomeEntity entity = new SomeEntity();
entityManager.persist(entity);
}
}
Same result, the method executes but the database is unaltered. I found this blog post which references a GitHub project. There he is using JpaInterceptor to establish a Hibernate session, but this uses the DAO pattern and I'd like to stick with using #PersistenceContext.
Clearly there is something about the Quartz thread that is preventing this from working properly? I'm about out of ideas and considering making a web service call to a SpringMVC controller just to get this working.
Since your CreateAlertJob is not created by Spring, #Transactional in it doesn't take effect.
You have the following options:
Delegate actual work to Spring bean and put #Transactional there
Use programmatic transaction management
Use AspectJ-based AOP implementation instead of Spring default implementation (but it would be overkill for such a simple problem)

Resources