This post discusses using Spring WebMVC for the client side, and also discusses some integration options for adding WebMVC to an existing application.
Spring WebMVC provides a class called
RestTemplate to simplify calling REST
APIs from Java. This follows a typical Spring design pattern where a complex
API is made more accessible through a template class (other examples include
Our example client uses Spring to instantiate the
RestTemplate, with this
XML configuration file:
Unlike the server side discussed in Part 2, the client side does not use annotation-driven configuration, so we register the Jackson JSON conversion library explicitly.
The associated Java code is as follows:
print(...) method and setter methods have been omitted for clarity.
The javadocs for
RestTemplate list other methods that are available;
here we display the two primary ones,
require a URL in string form as the first parameter. These URL strings support
path variables similar to what we saw on the server side in Part 2; however,
in this case the path variables are matched in order; the label in the curly brace
is not used.
postForObject method has an extra parameter inserted next, which is the
request body. Next is the expected type for the response body, followed by a
variable number of parameters that match to the path variables in the URL.
Obviously, each call to the
RestTemplate is making a network connection, so care
should be taken to make sure the call happens on a thread that can block without
slowing down the application, and to make sure that possible network or server
failures are handled.
This example shows adding a REST API to an existing Java SE application. For the application to be modular, it is necessary to separate the Spring WebMVC controller from other application classes, such as database access objects or server-side business logic. This raises issues with integration since the application may not be based on similar technology.
For WebMVC clients, this integration is simple. The example application uses
a Spring XML configuration file, but it is simple to replace this with a
direct instantiation of
RestTemplate wherever it will be used. The sample
Google Places client discussed in a previous post shows this.
For the server side, generally our goal will be to provide the Spring WebMVC controller class with a reference to application business logic. The business logic can get a reference to the controller class, but this is generally not necessary since as requests flow in from the client, the controller class is invoked automatically by Spring WebMVC.
For complete Spring applications, this integration can be done by combining
all beans into a single application context. Any existing application context
can be included from the WebMVC XML configuration file (since this file is read
automatically by Spring when the
DispatcherServlet is created). This approach
would break model-view-controller separation if we were writing a fully-fledged
web application, but since in this case we’re just adding a REST API on
existing business logic, it’s defensible from a design standpoint.
However, in many cases the application will not be Spring-based, or merging the application contexts may be undesirable. This makes integration more challenging. There are a few ways to proceed:
- A factory class can be used by Spring beans to instantiate or lookup objects
in the application. This can be done either directly in Java code or through
- The Spring beans can register themselves in a separate registry which is used by the application to lookup the WebMVC controllers and inject application references.
- A Spring bean can be added that implements
ApplicationContextAwareto get a direct reference to the Spring application context and store it in a registry. This context can then be used to look up any desired bean by name or type. Here is an example.
- While I have illustrated a
DispatcherServletand its ability to search for a Spring XML configuration file using a naming convention, it is also possible to use Spring’s
ContextLoaderListenerto load an application context in a servlet environment.
The last method deserves an expanded discussion. Unlike the
DispatcherServlet, when the
ContextLoaderListener creates its application
context, it registers it as the root context. This means it’s possible to use
retrieve it. (In the case of our embedded Jetty example, we can obtain the
servlet context easily from the
WebAppContext we instantiate.)
From a design standpoint, using a
ContextLoaderListener has the advantage
that it lets us use multiple instances of
DispatcherServlet to handle
separate web applications, each of which will have its own path and its own
Spring context, and all of which can access the ‘common’ beans in the root
context. The disadvantage is that we add some complexity to our configuration.
A good discussion of the difference can be found
Any of these four methods will work. The first two methods allow us to avoid spreading Spring-related dependencies further in our code. The last method provides the most flexibility.
Through these posts we’ve seen how Spring WebMVC and Jetty can be combined to add a REST API to an existing application with very few lines of code, and without requiring a servlet container to be added to the architecture.