Spring Module
Spring Module
Spring Module
prepared by:
Objectives
Upon completion of this module, you should be able to:
Describe the seven modules of Spring Framework
Additional Resources
The following references provide additional information on
the topics described in this module:
Naveen Balani, Introduction to the Spring framework A
first look at Spring AOP and the IOC container
[http://www-
128.ibm.com/developerworks/library/wa-spring1/]
2/56`
General Overview
Each of the modules (or components) that comprise the Spring framework
can stand on its own or be implemented jointly with one or more of the others.
The functionality of each component is as follows:
3/56`
Spring-based application. With Spring AOP you can incorporate
declarative transaction management into your applications without
relying on EJB components.
Spring DAO: The Spring JDBC DAO abstraction layer offers a
meaningful exception hierarchy for managing the exception handling
and error messages thrown by different database vendors. The
exception hierarchy simplifies error handling and greatly reduces the
amount of exception code you need to write, such as opening and
closing connections. Spring DAO's JDBC-oriented exceptions comply
to its generic DAO exception hierarchy.
Spring ORM: The Spring framework plugs into several ORM
frameworks to provide its Object Relational tool, including JDO,
Hibernate, and iBatis SQL Maps. All of these comply to Spring's
generic transaction and DAO exception hierarchies.
Spring Web module: The Web context module builds on top of the
application context module, providing contexts for Web-based
applications. As a result, the Spring framework supports integration
with Jakarta Struts. The Web module also eases the tasks of handling
multi-part requests and binding request parameters to domain objects.
Spring MVC framework: The Model-View-Controller (MVC) framework
is a full-featured MVC implementation for building Web applications.
The MVC framework is highly configurable via strategy interfaces and
accommodates numerous view technologies including JSP, Velocity,
Tiles, iText, and POI.
Spring framework functionality can be used in any J2EE server and most of it
also is adaptable to non-managed environments. A central focus of Spring is
to allow for reusable business and data-access objects that are not tied to
specific J2EE services. Such objects can be reused across J2EE
environments (Web or EJB), standalone applications, test environments, and
so on, without any hassle.
4/56`
Type 1 Services need to implement a dedicated interface through
which they are provided with an object from which they can
look up dependencies (for example, additional needed
services).
Type 2 Dependencies are assigned through JavaBeans properties
(for example, setter methods).
Type 3 Dependencies are provided as constructor parameters and
are not exposed as JavaBeans properties.
The Spring framework uses the Type 2 and Type 3 implementations for its
IOC container.
Aspect-oriented Programming
Aspect-oriented programming, or AOP, is a programming technique that allows
programmers to modularize crosscutting concerns, or behavior that cuts
across the typical divisions of responsibility, such as logging and transaction
management. The core construct of AOP is the aspect, which encapsulates
behaviors affecting multiple classes into reusable modules.
5/56`
Summary
In this first module, we introduced you to the basics of the Spring framework.
We started by discussing the seven modules that comprise Spring's layered
architecture. Soon, we will have a closer look at two of them: The IOC
container and Spring AOP. AOP and IOC are complementary technologies in
that both apply a modular approach to complex problems in enterprise
application development.
Spring does not try to duplicate existing solutions; it tries to integrate with
exiting solutions like JDO, AOP and Hibernate. Spring is portable across
application servers, as it does not include any application server or platform
specific requirements. This makes it compatible on major application servers
like Websphere, Weblogic, Tomcat, Jboss and others like them.
6/56`
Module 2
Spring Core
Objectives
Upon completion of this module, you should be able to:
Understand how Inversion of Control pattern operates
on Spring
Describe the purpose of Inversion of Control pattern
Additional Resources
The following references provide additional information on
the topics described in this module:
Download the Spring framework from the Spring
homepage.
[http://aopalliance.sourceforge.net/]
7/56`
Overview
Because org.springframework.beans.factory.BeanFactory is a
simple interface it can be implemented for a range of underlying storage
methods. The most commonly used BeanFactory definition is the
XmlBeanFactory, which loads beans based on definitions in an XML file, as
shown in Listing 2.1.
Beans defined in XML files are lazily loaded, which means that the beans
themselves will not be instantiated until they are needed. To retrieve a bean
from BeanFactory you can simply call the getBean() method passing in
the name of the bean you want to retrieve, as shown in Listing 2.2.
8/56`
Each bean definition can be a POJO (defined by class name and JavaBean
initialization properties) or a FactoryBean. The FactoryBean interface
adds a level of indirection to the applications built using the Spring framework.
An IOC example
Now we look at an example that demonstrates how you can inject application
dependencies (rather than build them in) through the Spring IOC container.
We will use the famous Hello World application. With respect to the simple
hello world, our hello world service requires a layout component that will
arrange how the hello world message should be displayed.
The interfaces
The implementations
9/56`
public void setMessage(String message) {
this.message = message;
}
The application
Our application does not know which implementation it got, it will just use the
interfaces and by the contract everything should work on any
implementations.
10/56`
Listing 2.8. HelloWorldApp
/**
* @param args
*/
public static void main(String[] args) {
try {
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {
"config/bean.xml"
});
HelloWorldService helloWorldService =
(HelloWorldService)
context.getBean("helloWorldService");
helloWorldService.execute();
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}
With all the interfaces and implementations in place, the next thing to consider
is how to integrate them in a loosely coupled manner. In Listing 2.8 you can
see how we configure this
<beans>
<bean id="helloWorldService"
class="examples.spring.HelloWorldServiceImpl">
<property name="message">
<value>Hello World</value>
</property>
<property name="layout">
<ref bean="standardLayout"/>
</property>
</bean>
<bean id="standardLayout"
class="examples.spring.StandardLayout">
</bean>
<bean id="uppercaseLayout"
class="examples.spring.UppercaseLayout">
</bean>
</beans>
11/56`
The Bean Configuration file tells Spring:
- Bean id is helloWorldService (The name of the Bean)
With Class HelloWorldServiceImpl (What class to load dynamically)
Property Message with Value=Hello World
Property Layout with value refers to bean with id StandardLayout
- Bean id is standardLayout (The name of the Bean)
With Class StandardLayout
- Bean id is uppercaseLayout (The name of the Bean)
With Class UppercaseLayout
Note that all the setter methods are implemented by Spring configuration
beans. All the dependencies (that is, the message and the layout interface)
can be injected by the Spring framework using these beans. The execute()
method will then use them to carry out the remainder of the implementation.
12/56`
Creating the projects
To run example above we will use Eclipse, Maven, and Maven plugin to
create our SpringHello project.
13/56`
Then add dependency to Spring Framework
14/56`
Now create the interfaces and classes from above listings into appropriate
packages (say, examples.spring)
15/56`
Create the bean.xml file in resources folder:
16/56`
Listing 2.9. log4j.properties
log4j.rootLogger=error, stdout
17/56`
Now, we can run the HelloWorldApp
18/56`
Summary
Since learning is best accomplished by doing, we used a working example to
show you how the IOC pattern (as implemented by the Spring IOC container)
works to integrate disparate systems in a loosely coupled manner. In this
example you saw how simple it was to inject dependencies, or services, than
having to build them in from the ground up.
19/56`
Module 3
Spring AOP
Objectives
Upon completion of this module, you should be able to:
Describe the concept of aspect, advice, joinpoint,
pointcut, and target
Describe the purpose of Aspect Oriented
Programming
Additional Resources
The following references provide additional information
on the topics described in this module:
R.J. Lorimer , Spring: A Quick Journey Through
Spring AOP
[http://www.javalobby.org/java/forums/t44746.ht
ml]
20/56`
Overview
One of the strengths of the Spring Framework is its robust and flexible aspect
oriented programming infrastructure. In Spring, AOP is a little different than
other AOP frameworks in that it brings with it a consistent AOP infrastructure
that can be applied for other AOP technical solutions.
Aspect - Think of this as the general feature you want to apply globally
to your application (logging, performance monitoring, exception
handling, transaction management, etc).
21/56`
Spring and Advice Objects
We start with the concept of advice objects, because they are the easiest to
bridge to from a non-AOP way of thinking. Advice implementations in Spring
are simply implementations of the
org.aopalliance.intercept.MethodInterceptor interface. That's not a
Spring class! So it turns out that Spring's AOP implementation uses a
*standard* AOP API from the AOP Alliance, which you can read more about it
on http://aopalliance.sourceforge.net/. The MethodInterceptor interface is
actually a child of the org.aopalliance.intercept.Interceptor interface,
which is a child of another interface, org.aopalliance.aop.Advice.
Remember that Spring AOP only supports method invocation, but that
conceptually, an advice could include field access, constructor invocation and
a bunch of other things. That is why Spring's advice starts at the
MethodInterceptor interface, even though there are other interfaces higher
up - because MethodInterceptor is the sub-interface that is designed for
method-invocation style advice and for which Spring has support. The
MethodInterceptor interface is really quite simple:
Basically, when you write an advice for intercepting a method, you have to
implement one method - the invoke method, and you are given a
MethodInvocation object to work with. The MethodInvocation object tells us
a bunch of stuff about the method that we're intercepting, and also gives a
hook to tell the method to go ahead and run.
Let's jump right in and look at a (very) basic method performance profiling
advice:
Not too complicated really - just capture the time before the method
invocation, tell the method to go ahead and run, then afterward capture the
time again, calculate the difference, and print it out. Incidentally, Spring
already has a better implementation of this type of interceptor - the
org.springframework.aop.interceptor.PerformanceMonitorInterceptor -
there are actually quite a few useful concrete interceptor implementations in
there - check it out.
org.springframework.aop.MethodBeforeAdvice - Implementations
of this interface have to implement this contract:
You'll notice in this case you aren't given the MethodInvocation object, just
the underlying Method object - this is because the call to proceed() will be
handled by Spring for you; all you need to do is do what you need *before* the
method is called (as the interface name implies).
You'll notice it looks a whole like the before advice, but simply adds the
Object's return value to the method arguments.
23/56`
contract, this is simply a 'marker' interface, and expects you to
implement any number of methods that look like this:
That's a primer on advice objects. Not too bad so far, right? If you've ever
worked with in reflection in Java, most of this is fairly similar in style.
Remember that the thing that an advice works with is called a JoinPoint. Our
join points in Spring are always methods, and at runtime resolve to
org.aopalliance.aop.Method objects which have made appearances as
method arguments to our advices above. To solidify the point,
org.aopalliance.aop.Method extends org.aopalliance.aop.JoinPoint .
The class filter is a special type of object that describes which classes have
potential joinpoints (read methods) on them. The method matcher simply
describes which methods for a given class are considered valid joinpoints for
this pointcut. We don't want to spend too much time on the pointcut interface,
however, because chances are - you won't be implementing it.
You may have noticed, neither of above pointcut examples made any
reference to any advice (e.g. MethodInterceptor implementation) - remember
that an advice knows the *what*, not the *where*? Well, a pointcut is the
inverse - it knows the *where*, not the *what*. Therefore, theoretically, these
two components can be intermingled in different configurations and reused.
Weve gone to great lengths above to clarify that pointcuts don't know about
advice objects, and advice objects don't know about pointcuts. Some object
somewhere, however, must know about both if we are going to have any hope
26/56`
of wrapping our beans in aspects. That is where implementations of
PointcutAdvisor come in. Conceptually speaking, a PointcutAdvisor is
nothing more than a pointcut and an advice object combined - hence the
name. The most basic variety of pointcut advisor is the
org.springframework.aop.support.DefaultPointcutAdvisor class. This is
for the most part just a bean that has two references - something akin to this:
Yes, yes, in reality it is more complicated than this - but really that is the bulk
of it right there. Now we are getting to a point where we can define the *what*
(the Advice) and the *where* (the Pointcut) in one discrete location. A basic
configuration of this advisor in a spring bean definition may look something
like this:
27/56`
<!--
An alternative pointcut advisor that combines the before advice with
the controller pointcut
Showing how reuse of pointcuts and advices is possible
-->
<bean name="pointcut.advisor2"
class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="beforeAdviceA"/>
<property name="pointcut" ref="controller.handle.pointcut"/>
</bean>
Hopefully this gives you some idea of the relationship of these three classes.
As you can see, advice objects and pointcuts can be intermixed freely into
varying pointcut advisors.
Ok, now, throw all of that example out of the window. Why? Well, because in
reality while the above example is much more flexible, it is quite verbose as
well. Most times that level of granularity is unnecessary, as we will soon see.
Earlier I glossed over the
org.springframework.aop.support.PointcutAdvisor class hierarchy, and
just mentioned the most basic DefaultPointcutAdvisor . Let's take a closer
look at the available class hierarchy now:
Did you notice how similar the names are to the pointcuts we just learned
about? Most of these classes take the separation of pointcut and advisor out
of the equation, which, while theoretically reducing some degree of flexibility,
typically makes configuration much easier. Here is the same example above,
using the NameMatchMethodPointcut Advisor object (which combines the
PointcutAdvisor API with the NameMatchMethodPointcut class):
<!--
Use the NameMatchMethod pointcut advisor to make things a little
simpler.
-->
<bean name="pointcut.advisor1"
class="org.springframework.aop.support.NameMatchMethodPointcutAdviso
r">
<property name="advice" ref="interceptorA"/>
<property name="mappedName" value="execute"/>
</bean>
<!--
Use the NameMatchMethod pointcut advisor to make things a little
simpler.
-->
<bean name="pointcut.advisor2"
class="org.springframework.aop.support.NameMatchMethodPointcutAdviso
r">
<property name="advice" ref="beforeAdviceA"/>
<property name="mappedName" value="execute"/>
</bean>
As you can see, we got rid of the configuration of one bean entirely.
Technically speaking we are no longer reusing the pointcut, but since pointcut
definitions are typically a configuration concern (as seen above), it doesn't
usually matter one way or another to us.
So, we've covered advice objects and pointcut objects - which when you get
down to it, are the core; the center of Spring AOP support. Then we covered
pointcut advisors which take advice objects and pointcut objects and glue
them together into one cohesive chunk - the peanut butter and jelly; the meat
and potatoes; the spaghetti and meatballs; the lamb and tunafish. There is a
very important piece of the puzzle missing however: how do we wrap these
pointcut-advisor combos around our objects? After all, that is the whole point
of all of this. Enter the ProxyFactoryBean .
Without getting into too much detail, Spring supports the concept of a
FactoryBean , which is a special type of bean, in that the bean returned is a
factory result, rather than just a plain 'newInstance()' call on the class you
provided. So, you could have a factory bean implementation that, based on
certain configuration details, factoried different implementations of a certain
class. So, just to solidify the point, in this example:
29/56`
If you ask for myBean from the bean factory, you're *not* going to get an
instance of MyFactoryBean - instead, Spring is going to consult with the
MyFactoryBean object, and ask it to provide the object you want.
Why is all of this important? Well, because this FactoryBean concept is how
Spring wraps your beans - via the some configuration details, and then using
some internal tool (dynamic proxies, CGLib, etc.) to create a proxy for your
bean that executes some advice on method calls when the pointcut says the
method is a joinpoint (assuming a pointcut is defined).
Expanding our example above, here is how Spring's proxy factory bean
works:
<!--
Use the NameMatchMethod pointcut advisor to make things a little
simpler.
-->
<bean name="pointcut.advisor1"
class="org.springframework.aop.support.NameMatchMethodPointcutAdviso
r">
<property name="advice" ref="interceptorA"/>
<property name="mappedName" value="execute"/>
</bean>
<!--
Use the NameMatchMethod pointcut advisor to make things a little
simpler.
-->
<bean name="pointcut.advisor2"
class="org.springframework.aop.support.NameMatchMethodPointcutAdviso
r">
<property name="advice" ref="beforeAdviceA"/>
<property name="mappedName" value="execute"/>
</bean>
<!-- Create the proxy bean that returns AOP'd varieties of our
controller -->
<bean name="myController"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value> aop.IController
</value></property>
<property name="interceptorNames">
30/56`
<list>
<value>pointcut.advisor2</value>
<value>pointcut.advisor1</value>
<value>myRawController</value>
</list>
</property>
</bean>
Notice the interceptorNames property? This is how we tell the proxy factory
bean what advisors or advice objects we want to apply to the proxied bean.
Order is important in this list - the order the advisors or advice objects are
entered in the list defines the order they will be invoked when entering and
exiting the bean. Note that in this case the *last* entry in the list is our bean
that we want to be proxied. This is just one possible way to define the bean to
be proxied as we'll see in a moment. Also, did you notice that we said
advisors or advice objects ? That is because the proxy factory bean allows
for another shortcut; not specifying a pointcut at all, just an advice. In those
cases, an 'every method is a joinpoint' style pointcut will automatically be
applied. So, if we didn't care which methods were advised, we could shorten
the example above like this:
<!-- Create the proxy bean that returns AOP'd varieties of our
controller -->
<bean name="myController"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>
aop.Icontroller</value></property>
<property name="interceptorNames">
<list>
<value>beforeAdviceA</value>
<value>interceptorA</value>
<value>myRawController</value>
</list>
</property>
</bean>
Now, I mentioned earlier that there is another way to specify the target bean.
This can be done through the targetName and/or target properties on the
factory bean:
31/56`
Listing 3.10. Alternative style for defining target
<!-- Create the proxy bean that returns AOP'd varieties of our
controller -->
<bean name="myController"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>
aop.Icontroller</value></property>
<property name="target" ref="myRawController"/>
<property name="interceptorNames">
<list>
<value>beforeAdviceA</value>
<value>interceptorA</value>
</list>
</property>
</bean>
If you don't need direct (non-AOP'd) access to your bean, then it may be
better for the simplicity of the file to just use an anonymous inner bean, rather
than declaring the bean separately to the proxy:
<!-- Create the proxy bean that returns AOP'd varieties of our
controller -->
<bean name="myController"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property
name="proxyInterfaces"><value>aop.Icontroller</value></property>
<property name="target"><bean class="
examples.spring.ExampleController"/></property>
<property name="interceptorNames">
<list>
<value>beforeAdviceA</value>
<value>interceptorA</value>
</list>
</property>
</bean>
32/56`
See AOP in action
<bean name="pointcut.advisor"
class="org.springframework.aop.support.NameMatchMethodPointcutAdvis
or">
<property name="advice" ref="performanceInterceptor"/>
<property name="mappedName" value="execute"/>
</bean>
<bean name="helloWorldProxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property
name="proxyInterfaces"><value>examples.spring.HelloWorldService</va
lue></property>
<property name="interceptorNames">
<list>
<value>pointcut.advisor</value>
<value>helloWorldService</value>
</list>
</property>
</bean>
33/56`
34/56`
Summary
There are more topics on Spring AOP that were not covered in this module,
such as:
Introductions/Mixins
Specialized Proxy Support (such as the TransactionProxyFactoryBean)
Other corner cases
35/56`
Module 4
Spring DAO
Objectives
Upon completion of this module, you should be able to:
Understand how Spring DAO works
Use Spring DAO library to simplify data access
Additional Resources
The following references provide additional information on
the topics described in this module:
Sebastian Hennebrueder, Spring DAO with JDBC
[http://www.laliluna.de/download/eclipse-spring-
jdbctutorial-en.pdf]
36/56`
Overview
In this module we will explains how to implement the design pattern Data
Access Objects (DAO) to access a Database with JDBC in Spring.
Spring allows to integrate any of above solutions to access our database. The
interface is well designed and lets us easily replace a JDBC database access
with a Hibernate based database access.
Hibernate, JDO and EJB are solutions to map database data to classes, e.g.
Reading a line of the table book and writing it to a object of class type book.
This allows you to use classes instead of result sets in your application and is
considered as good design, because your application keeps being object
oriented.
If you use JDBC access, Spring provides an abstract exception layer. If you
change your database from Sybase to Oracle you do not have to change the
exception handling from SybaseDataAcception to OracleDataException.
Spring catches the application server specific Exception and throws a Spring
dataexception.
37/56`
The domain classes
The domain classes is class book which is a normal Java bean with private
attributes and public getter/setter and constructor method.
38/56`
Listing 4.2. Book
public class Book {
// unique number to indentify the book
private Integer id;
// the title
private String title;
public Book() {
}
41/56`
public void setBookIncrementer(DataFieldMaxValueIncrementer
bookIncrementer) {
this.bookIncrementer = bookIncrementer;
}
..........................
We also define the SQL statements as constants, and some query attributes
that are instances of these private Class.
42/56`
rs.getString("author"),
rs.getInt("borrowed_by"));
return book;
}
}
Each query is defined as private class. It will needs the sql and declarations of
parameters types, showing which kind of parameters we are passing.
You need not to pass the types but may have Spring to find out which types
are passed. But this can be a problem when passing null values. So just don't
do it. We will use book objects anywhere so when we read data from the
database we will have to map the resultset of a query to the class.
Notice that for insert, update and delete query, we extend our private class
from SqlUpdate class and for select query, we extend it from
MappingSqlQuery.
We also need to override the initDao method and instantiate our private query
attributes from our private classes appropriately. We will configure the
datasource later.
@Override
protected void initDao() throws Exception {
super.initDao();
this.queryInsert = new QueryInsert( getDataSource() );
this.queryUpdate = new QueryUpdate( getDataSource() );
this.queryDelete = new QueryDelete( getDataSource() );
this.querySelect = new QuerySelect( getDataSource() );
}
And now, for insert, update and delete method, we need no further
preparation, so have a look at the source code below:
43/56`
public int updateBook(Book book) {
Object values[] = new Object[] {
book.getTitle(),
book.getAuthor(),
book.getBorrowedBy(),
book.getId()
};
return queryUpdate.update(values);
}
It is really simple isn't it. Imagine if you would have to create a connection for
each access of the database, close it and handle all the possible exceptions.
testClient.testInsertUpdateDelete(libraryDao);
}
44/56`
libraryDao.updateBook(book);
System.out.println("List books:");
famousBooks = libraryDao.getBooks();
for (Iterator iter = famousBooks.iterator(); iter.hasNext();)
{
Book element = (Book) iter.next();
System.out.println("Book: " + element.getTitle() +
" written by "
+ element.getAuthor());
}
// delete the book
libraryDao.deleteBook(book);
System.out.println("List books:");
famousBooks = libraryDao.getBooks();
for (Iterator iter = famousBooks.iterator(); iter.hasNext();)
{
Book element = (Book) iter.next();
System.out.println("Book: " + element.getTitle() +
" written by "
+ element.getAuthor());
}
}
45/56`
Listing 4.9. bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="libraryDao" class="examples.spring.LibraryDaoImpl"
singleton="true">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="bookIncrementer">
<ref bean="bookIncrementer" />
</property>
</bean>
<bean id="bookIncrementer"
class="org.springframework.jdbc.support.incrementer.OracleSequenceM
axValueIncrementer">
<constructor-arg>
<ref bean="dataSource" />
</constructor-arg>
<constructor-arg>
<value>book_id_seq</value>
</constructor-arg>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
>
<property name="driverClassName"
value="oracle.jdbc.driver.OracleDriver" />
<property name="url"
value="jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTO
COL=TCP)(HOST=10.8.9.101)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=x
e)(SERVER=DEDICATED)))" />
<property name="username" value="bvk" />
<property name="password" value="bvk" />
</bean>
</beans>
46/56`
Summary
We have brief you step by step on how to use Spring DAO, the following
topics can be found out by yourself:
47/56`
Module 5
Using OpenSymphony Quartz Scheduler in Spring
Objectives
Upon completion of this module, you should be able to:
Describe the seven modules of Spring Framework
Additional Resources
The following references provide additional information on
the topics described in this module:
Christophe Verr, Using OpenSymphony Quartz
Scheduler in Spring
[http://www.javaranch.com/journal/
200711/combining_spring_and_quartz.html]
48/56`
Overview
Often our application need to run task regularly, Spring offers a few helper
classes to do some scheduling in our application. In Spring 2.0, both the
JDK's Timer objects and the OpenSymphony Quartz Scheduler are
supported. Quartz is an open source job scheduling system that can be easily
used with Spring.
About Quartz
Quartz offers five main structures to realize scheduling:
The Job interface
The JobDetail class
The Trigger abstract class
The Scheduler interface
The SchedulerFactory interface
The Job interface represents a job. A job does something, only one thing. Its
API is very straightforward. Only one execute() method, which will be called
by Quartz when a Job has to be executed. Some useful information can be
retrieved from the JobExecutionContext that is passed to the execute()
method.
Some data can be passed to jobs via the JobDataMap class. If a JobDataMap
is registered in a JobDetail, it can be accessed from the Job, via the
JobExecutionContext which is passed to the execute() method of the Job
interface. The JobDetail class is used to give some information about a
particular Job. Jobs are started (or "fired") by triggers, which are represented
by the Trigger class. Quartz has some convenient implementation class of
Trigger, such as SimpleTrigger and CronTrigger. A SimpleTrigger acts like a
basic timer, where you can define a starting time, an ending time, a repeat
count and a repeat interval. A CronTrigger uses more advanced settings,
using the "cron" Unix utility notation. The settings for a CronTrigger can be
very specific, like "fire the job at 10:15am on every last Friday of every month
during the years 2008, 2009, 2010". One notion is that jobs and triggers are
given names, and may be assigned to a group. A name must be unique within
the same group. So you can create a trigger for one group, and all jobs within
that group will be executed.
49/56`
Finally, the SchedulerFactory is used to get a Scheduler instance, which can
be used to register jobs and triggers.
Let's illustrate this with a basic example : a simple job printing a welcome
message, and a trigger firing the job every ten seconds.
First, the Job, only printing a welcome message:
scheduler.scheduleJob(jobDetail, ranchTrigger);
} catch (SchedulerException ex) {
ex.printStackTrace();
}
}
}
50/56`
Spring's Quartz API resides in the org.springframework.scheduling.quartz
package. There's quite a few classes there, but we'll only see those needed to
fire up jobs.
The QuartzJobBean abstract class
The JobDetailBean class
The SimpleTriggerBean class
The CronTriggerBean class
The SchedulerFactoryBean class
The MethodInvokingJobDetailFactoryBean class
The wrapping of Quartz API is obvious. QuartzJobBean implements Job,
JobDetailBean extends JobDetail. No need to say which class
SimpleTriggerBean and CronTriggerBean extend.
Declaring Jobs
The JobDetailBean is used to declare jobs. We set the name of the job class,
and if needed, some data the job may use. The job class extends
QuartzJobBean. Here is the declaration:
51/56`
Listing 5.4. ranchJob Bean Declaration
<bean name="ranchJob"
class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="examples.spring.quartz.RanchJob"
/>
<property name="jobDataAsMap">
<map>
<entry key="message" value="Welcome at JavaRanch" />
</map>
</property>
</bean>
Note how we retrieve the message from the context. This message was set in
the bean declaration, using the jobDataAsMap property. Spring actually calls
setter methods for each object set in this map. Here is the Spring way to use
the message in the job class :
@Override
protected void executeInternal (JobExecutionContext ctx) throws
JobExecutionException {
System.out.println("[JOB] " + message);
}
}
Declaring Triggers
Declaring triggers is as simple as declaring a job. We'll only use a
SimpleTriggerBean, which will start immediately, and repeat every ten
seconds. You can refer to the CronTriggerBean API to check how to set a
cronExpression for your trigger.
52/56`
Listing 5.7. ranchTrigger Bean Declaration
<bean id="ranchTrigger"
class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail" ref="ranchJob" />
<property name="startDelay" value="0" />
<property name="repeatInterval" value="10000" />
</bean>
Everything has been set up, all we need now is to load the context. The
scheduler will be started automatically on initialization.
We've seen so far how to fire Quartz jobs, but what if you want to call your
own method of your own bean? With Spring, you are not tied to Quartz job
instances, you can also use your own pojos to act as jobs. For example, you
may wish to use the CronTrigger's advanced settings to fire up your own task.
Nothing special here. Just a good old bean, declared the good old way.
53/56`
Listing 5.10. A Plain Bean
<bean name="welcomeBean" class="examples.spring.quartz.RanchBean">
<property name="message" value="Welcome at JavaRanch" />
</bean>
<bean id="ranchTrigger"
class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail" ref="methodInvokingJob" />
<property name="startDelay" value="0" />
<property name="repeatInterval" value="10000" />
</bean>
Voil! Executing the RanchQuartz application again will produce the same
result, with "[JOBBEAN]" being printed out instead of "[JOB]".
A word of caution
A trigger can fire only one job, but a job may be fired by many triggers. This
can bring a concurrency issue. In Quartz, if you don't want the same job to be
executed simultaneously, you can make it implement StatefulJob instead of
Job. In Spring, if you are using the MethodInvokingJobDetailFactoryBean, you
can set its "concurrent" property to false.
54/56`
Summary
As stated at the beginning of this module Spring also supports JDK's Timer
objects. If you want to use a simple timer for a simple task as above, you may
consider using a TimerTask and Spring's ScheduledTimerTask and
TimerFactoryBean instead. If you decide to use Quartz in Spring, there are
many more properties that can be set for the scheduler, jobs and triggers.
Refer to Spring's API to discover them all.
55/56`
Finally
You should now have a pretty good idea of what Spring brings to the table.
Spring aims to make J2EE development easier, and central to this is its
inversion of control. This enables you to develop enterprise applications using
simple Java objects that collaborate with each other through interfaces. These
beans will be wired together at runtime by the Spring container. It lets you
maintain loosely coupled code with minimal cost.
On top of Springs inversion control, Springs container also offers AOP. This
allows you place code that would otherwise be scattered throughout you
application in one placean aspect. When your beans are wired together,
these aspects can be woven in at runtime, giving these beans new behavior.
There are many topics that are not covered in this introduction, such as:
Resources
PropertyEditors, data binding, validation and the BeanWrapper
Transaction Management
Web MVC Framework
Remoting (exposing Spring services outside container)
Other Integration Subject, etc
But by this time you should be able to catch those topics up yourself, by
reading Spring Reference and lot of articles on the net.
-)|(-
56/56`