Saturday, December 7, 2013

Java Web App with Spring annotations, programmatic web.xml, programmatic application context and a scheduler

Create a new Maven Project with Eclipse

Make sure to flip the packaging to war



Add the following dependencies to your pom


<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.5.RELEASE</version>
</dependency>
</dependencies>
view raw gistfile1.txt hosted with ❤ by GitHub



Create the programmatic web.xml. I called mine WebInit.java(you can call it anything you want)
and stuck it in a package called "conf" under src/main/java

package conf;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
public class WebInit implements WebApplicationInitializer {
public void onStartup(ServletContext container) throws ServletException {
}
}
view raw gistfile1.java hosted with ❤ by GitHub
I also created a index.html file just to make sure I can deploy the app at this point and that WebInit kicks in.

Create the programmatic Spring Application Context. I did mine under the same "conf" package and called it SpringAppContext(you can call it anything you want)

package conf;
import java.util.Date;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringAppContext {
@Bean(name="testBean")
public Date testBean() {
return new Date();
}
}
view raw gistfile1.java hosted with ❤ by GitHub

Now we have to nudge Spring at app start-up and tell it to start wiring things up - creating beans, injecting and stuff (this is very technical language...thank you!)
So we add the following magic to the programmatic web.xml(WebInit.java in my case):

package conf;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
public class WebInit implements WebApplicationInitializer {
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(SpringAppConfig.class);
container.addListener(new ContextLoaderListener(rootContext));
}
}
view raw gistfile1.java hosted with ❤ by GitHub



At this point we redeploy to test:
Search for "testBean" in the console - should be on line indicating it was instantiated by Spring - if that is the case, life is good!

INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@7baa3dd: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,springAppContext,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor,testBean]; root of factory hierarchy
Dec 07, 2013 8:14:47 PM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization completed in 423 ms

Now we do some coding

We create a Service class that would be invoked to do some work from the scheduled job


package app.service;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.stereotype.Component;
@Component
public class SomeService {
public void doSomeServiceWork() {
System.out
.println("Hey, hey, Heeeey, you've got this thing working. The time is: "
+ new SimpleDateFormat("HH:mm:ss").format(new Date()));
}
}
view raw gistfile1.java hosted with ❤ by GitHub
Then we create the Scheduled Job and Autowire the Service into it:


package app.scheduled;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import app.service.SomeService;
@Component
public class SomeScheduledJob {
@Autowired SomeService someService;
@Scheduled(cron = "0/5 * * * * ?")
public void doSomeScheduledWork() {
someService.doSomeServiceWork();
}
}
view raw gistfile1.java hosted with ❤ by GitHub

Now we just have to tell Spring where to look for "@Component"s and also that we want to do scheduling stuff,
so we add these two to our SpringAppContext.java:

@EnableScheduling
@ComponentScan(basePackages= {"app"})

"app" is just the name of my base package. For you it would be whatever package you placed your "@Component"s at.

This what the final version of the SpringAppContext.java looks like:

package conf;
import java.util.Date;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
@Configuration
@EnableScheduling
@ComponentScan(basePackages= {"app"})
public class SpringAppContext {
@Bean(name="testBean")
public Date testBean() {
return new Date();
}
}
view raw gistfile1.java hosted with ❤ by GitHub

At this point we can deploy and test the complete web app.


And here is a zip of the project: webapp-scheduled

Hope this is useful!