Using Spring
#############################
This gives a rundown on how to efficiently use Spring inside JQM. This can of course be an inspiration for other big "container" frameworks.
There are multiple possibilities, and this page shows how to use two of them. They are presented here in order of increasing complexity, which is also the order of decreasing recommendation.
By doing nothing special
**************************
It has been said before, by default launching a new job instance in a JQM server is like launching a new JVM: if a Spring job already works from the command line, it will work in JQM without adaptation.
There are different ways to create Spring programs, but they all boil down to: create a Spring context, load configuration inside the context, create the job bean from the context and launch it.
A most common example is by using Spring Boot, which hides most boilerplate code. The main method is simply::
import org.springframework.boot.SpringApplication;
public class Application
{
public static void main(String[] args)
{
SpringApplication.run(MyJob.class, args);
}
}
And the job implements CommandLineRunner, which will automatically instantiate the bean and run it on context creation::
@Import(ContextConfig.class)
@SpringBootApplication
public class MyJobClass implements CommandLineRunner
{
@Autowired
private MyService myServiceToInject;
@Override
public void run(String... args) throws Exception
{
myServiceToInject.doSomething();
System.out.println("Job is done!");
}
}
In terms of job definition, the Application class is the JQM entry point. JQM knows nothing about Spring, it is just another main method to run.
Advantages:
* direct code reuse from CLI batch jobs
* just another job definition - nothing special to do
* free to initialize and configure Spring in any way: annotations, XML, packages to scan or ignore...
Cons:
* the Spring context is recreated on each launch, which is costly.
This is the recommended way of using Spring inside JQM, in the "keep it simple" philosophy.
.. note:: a full working sample is included inside the JQM integration tests. It is named "jqm-test-spring-1". (it also uses JPA with a JNDI resource handled by the JQM JNDI directory)
By having JQM set the context
******************************************
In this option, there is only one Spring context for all job definitions using Spring. The jobs themselves (payload code)
do no Spring context initialization - they just use Spring features (injection...) and do not care from where they do come from.
This option is the direct equivalent of what happens inside a servlet container (Tomcat...) when using Spring: the context
is actually initialized by a servlet initialization listener, and the application code just uses Spring, never creating a SpringContext itself.
JQM uses the same method, with an event handler. It also has a specialized runner which retrieves the job bean from the Spring context
and runs it (it must implement Runnable).
Note that the following configuration assumes that you want to share the Spring context between different executions and potentially between different
:def:`JobDef` to avoid initializing it on each run as it is often very costly. This means sharing the same class loader for all executions,
which is not the JQM default. If this does not suit your needs, change the execution context ``true`` to
false and the default JQM behaviour of having one different class loader per launch will be reinstated.
First of all, some dependencies are needed
com.enioka.jqm
jqm-handler-spring
${jqm.version}
com.enioka.jqm
jqm-api
${jqm.version}
provided
The payload can be defined like this::
package com.company.project;
@Component
public class MyJobClass implements Runnable
{
@Autowired
private MyService myServiceToInject;
@Resource(name = "runtimeParametersProvider")
private ObjectFactory