Java Spring MVC Application Architecture Tutorial
A Spring MVC is a Java framework used to build web applications. It follows the Model-View-Controller design pattern and implements all of the basic features of a core spring framework like Inve. This tutorial explains the benefits of using Spring MVC in your application and walks through the entire process of creating a simple Spring MVC application.
Introduction to Java Spring MVC Application Architecture Tutorial. In this tutorial, we will learn about the basics of Java Spring MVC application architecture and how to build a simple web application using Spring MVC. We will also cover some of the more advanced features of Spring MVC including reactive programming and views.
What is Spring MVC?
If you’re new to Java development, or if you’ve been using Java for a while but haven’t had much experience with frameworks, Spring MVC might be the perfect fit for your next project. Spring MVC is an open-source framework that helps developers create web applications in Java.
Spring MVC provides a set of servlet-based modules that can be used to build and configure Web applications. For example, Spring MVC supports forms based on HTML, using JSPs for templating and XML for configuration.
What is Spring Data?
Spring Data is a core component of the Spring framework that includes various repository implementations and query language support. This library facilitates the development of REST web services and RESTful client-server applications.
What is Apache Camel?
Camel is an open-source Java framework that simplifies the integration of enterprise applications with web services by providing abstractions for message-, transport-, routing-, and security management as well as reliable message delivery across multiple levels of technology abstraction in the client and the service layer. The core concepts of Apache Camel are:
Message Exchange Patterns (MEP) – define a message format to be exchanged between components in an enterprise application.
Routing – define how messages are routed from one component to another.
Transport-level security – protect messages with security credentials at the transport level before being passed to the consumer components.
What is Spring Boot?
Spring Boot is a lightweight, production-grade multi-tier framework for building, releasing, and running applications on the JVM. It offers a number of useful features, including auto-configuration, tooling support, image and extension management, bean validation and dependency injection, and packaged dependencies for external libraries and OSGi bundles. Spring Boot is designed to deliver production-grade applications quickly, with less ceremony and a smaller footprint.
What is Spring Security?
Spring Security is an open-source framework that provides enterprise-level security for web applications. It includes support for OAuth 2.0 and OpenID Connect, as well as basic identity management like password hashing and access control lists (ACLs). It also offers to scan, alerting/notification, cryptography, and more. What are the benefits of using Spring Boot? The following benefits are offered by the Spring Boot platform:
- Injectable dependencies – eliminate vendor lock-in
- Configuration without XML configuration files
- Build powerful REST APIs in minutes
- Flexible Web Services that connect to backend databases
- Run unit tests on a local environmentDev and Pro versions available for enterprise environmentsTesting service and container-based applications Service Discovery by automatically discovering the hostnames and ports of other services.
Layers of Abstractions
Spring MVC applications are broken down into a series of layers. We consider a layer to be a discrete, orthogonal area of concern within an application. For instance, all of the persistence code is considered a separate layer from the view rendering code. Layers are abstractions within an application, and interfaces provide the contract by which layers interact. Some layers might be well hidden, used only by the layer immediately above it. In contrast, the most important layer (the domain model itself) spans nearly all the other layers in the system.
Layers are conceptual boundaries and are not necessarily physically isolated. More often than not, all of the layers will be located within the same virtual machine for a web application. For a good discussion on application distribution, consult Rod Johnson’s Expert One-on-One J2EE Design and Development (Wrox, 2002).
Note Are layers the same thing as tiers? Many people use the two terms interchangeably, but separating the two helps when discussing the application and its deployment. A layer is a logical abstraction within an application. A tier is best thought of as a physical deployment of the layers. Thinking in layers can help the software developer, while thinking in tiers can assist the system administrator. Layers are mapped onto tiers.
Thinking in layers can help conceptualize the flow through an application. Visualizing the application’s layers as a cake (layers of cake stacked one on another) is a common and convenient way to illustrate how the application is organized. Typical metaphors such as“ down into persistence” and “back up to the user interface” refer to a cake, and denote a sense of vertical direction, reinforcing the metaphor.
Typically, any persistence functionality is at the bottom of the cake, while the user interface is at the top. What is found in the middle, and how it is organized, is the subject of this chapter. We will use this metaphor when explaining our architecture.
Breaking it down further, typical Spring MVC applications have at least five layers of abstraction that you as a developer will code to. The layers are:
- user interface
- domain object model
You might notice that common application elements, such as transaction management or security, are not in the preceding list. If you are familiar with the Spring Framework and its extensive use of aspect-oriented programming (AOP), this won’t come as a surprise. Transaction management, for instance, is considered a transparent aspect of a system, not a full layer.
You will notice that the domain model vertically spans all the other layers. This is because all the other layers have a dependency on the domain model. It is the only layer that crosscuts all the rest.
Isolating problem domains, such as persistence, web navigation, and user interface, into separate layers, creates a flexible and testable application. Implementations of each layer will vary independently, increasing the flexibility of the application. Decreasing the coupling between areas of the application will increase the testability, making it easier to test each part of the application in isolation.
This isolation is accomplished by minimizing the amount of dependencies between the layers. The fewer dependencies a layer has upon itself, the less costly it is to change that layer. It is a best practice to ensure that a layer is required only by one or two other layers. Avoid having one single layer required by many different parts of the application.
You can avoid dependency explosion in at least two ways. If a layer begins to employ too many layers, consider creating a new layer of abstraction wrapping all the previous interactions. On the other hand, if you find that a layer has permeated throughout many layers, consider if that layer is itself an aspect of the system. If the functionality can be applied across great swaths of the system transparently, use Spring’s AOP functionality to remove the explicit dependency from your code.
The important point to remember is that one of the great benefits of layering an application is it creates a decoupled design. When you discover a layer or facet of the application that is too intrusive, refactor it to another abstraction or through AOP. This will keep your application flexible and testable.
Java Interface As Layer Contract
The Java interface is the key enabler to building an application with layers. An interface is a contract for a layer, making it easy to keep implementations and their details hidden while enforcing correct layer usage.
The benefits of low coupling provided by interfaces have been well known for some time. Their full benefits have been hindered because the instantiation of concrete types was still required. The promise of implementation abstraction wasn’t quite realized—this is, before Spring and other Dependency Injection frameworks. Spring helps interfaces truly shine because it handles the creation of the objects instead of your application code.
Treating an interface as a contract between layers is very helpful in large team settings. Coordinating the many resources often required by large projects is difficult, and it is rare that integration between layers happens precisely. Interfaces help to speed development between teams because of their lightweight nature. Developers program against the interface, while its implementation continues to be built and tested.
On a practical level, the Spring Framework works especially well with interfaces. Its AOP facilities are built around JDK proxies,2 making it easy to extend the implementation of an interface with additional services.
Using interfaces to define interactions between components makes unit testing much simpler. By using frameworks such as EasyMock (http://www.easymock.org) or jMock (http:// www.jmock.org) you can easily create mock implementations of your interfaces with just a few lines of code and use these mocks when testing an object and its interactions with its collaborators. Although both EasyMock and jMock can create mocks of classes rather than interfaces, they require runtime bytecode generation and have some caveats that are not present with interface-based mocks.
Note: We will provide extensive coverage of testing a Spring MVC application later in the book. You will learn how to use a mock objects library to help test individual layers of your application.
Connecting layers with interfaces also has the added benefit of reducing compile times and creating more modular builds. Concrete implementation classes can now change without requiring a recompile of any clients dependent on it (because the clients don’t have a physical dependency on any concrete classes). For large systems, this can be very helpful at a build and deployment time.
Using interfaces also enables systems to be so flexible that their implementations can be chosen at startup, or even while the application is at runtime. Because the client is compiled against the interface, the implementation class can be swapped in and out at runtime. This creates a highly dynamic system, further increasing flexibility and decreasing coupling. Many systems take advantage of this ability, such as Spring itself.
In summary, each layer is exposed as an interface. The interface provides a layer of abstraction, making it easy to change the implementation of the layer without affecting the rest of the application.
Layers in a Spring MVC Application
This section contains discussions of each major layer in a typical Spring MVC application. We will also cover some potential deviations from this design. A few discussions will touch on Spring MVC interfaces or classes. Do not fear; we explain each subject in detail in the following chapters.
User Interface Layer
The user interface layer is responsible for presenting the application to the end user. This layer renders the response generated by the web layer into the form requested by the client. For instance, cell phones usually require WML or at least specializations of XHTML. Other clients may want PDFs for their user interface. And, of course, browsers want the response rendered as XHTML. We keep the user interface rendering layer separate from the web layer (discussed next) so that we can reuse the web layer as much as possible.
Spring MVC’s User Interface Layer
Spring MVC does a nice job of isolating the UI concerns into a few key interfaces. The org.springframework.web.servlet.The view interface represents a view, or page, of the web application. It is responsible for converting the result of the client-requested operation (the response model) into a form viewable by the client.
Navigation logic is one of two important functions handled by the web layer. It is responsible for driving the user through the correct page views in the correct order. This can be as simple as mapping a single URL to a single page or as complex as a full workflow engine.
Managing the user experience and traveling through the site is a unique responsibility of the web layer. Many of the layers throughout this chapter assume much more of a stateless role. The web layer, however, typically does contain some state to help guide the user through the correct path.
There typically isn’t any navigation logic in the domain model or service layer; it is the sole domain of the web layer. This creates a more flexible design because the individual functions of the domain model can be combined in many different ways to create many different user experiences.
The web layer’s second main function is to provide the glue between the service layer and the world of HTTP. It becomes a thin layer, delegating to the service layer for all coordination of the business logic. The web layer is concerned with request parameters, HTTP session handling, HTTP response codes, and generally interacting with the Servlet API.
The HTTP world is populated with request parameters, HTTP headers, and cookies. These aspects are not business logic–specific and thus are kept isolated from the service layer. The web layer hides the details of the web world from the business logic.
Moving the web concerns out of the business logic makes the core logic very easy to test. You won’t be worrying about setting request variables, session variables, HTTP response codes, or the like when testing the business layer. Likewise, when testing the web layer, you can easily mock the business layer and worry only about issues such as request parameters. Chapter 10 offers a more detailed discussion on testing the web layer.
Divorcing the web concerns from the service layer also means the system can export the same business logic via multiple methods. This reduces code duplication and allows the system to easily add connection mechanisms, such as HTTP, SOAP, or XML-RPC, quickly and easily. The web layer becomes just another client connection mechanism, providing access to core business functionality, but never implementing the functionality directly.
The web layer can be implemented as simply as servlets, for instance. These servlets will perform the work of turning request parameters into meaningful objects for the service layer, and then calling a method on a service interface. The web layer is also responsible, among other things, for turning any business exceptions into appropriate error messages for end users.
Higher-level frameworks, such as Spring MVC and Tapestry, offer sophisticated mechanisms for this translation between the raw request parameters and the business logic layer. For instance, Spring MVC will map request parameters onto plain old Java objects (POJOs) that the business logic can operate on directly. Spring MVC also implements sophisticated workflows for processing requests, structuring the way the request is handled and making extension easy.
There are two main types of web layer implementations: request/response frameworks and component frameworks. A request/response framework is built to interact directly with the Servlet API and the HttpServletRequest and the HttpServletResponse. These types of frameworks are considered to have a push model because the user code will compile a result and then push it out to be rendered. Spring MVC is considered a request/response framework.
Other frameworks have adopted different approaches to processing a web request. Some frameworks, such as Tapestry and JavaServer Faces (JSF), are considered component-based. Those frameworks attempt to not only hide the Servlet API from you but also make programming for the web feel like programming a Swing application. Those frameworks are essentially event-driven, as the components respond to events originally coming from the web layer.
Both types of programming models have their advantages and disadvantages. We believe Spring MVC is a good balance. It provides a rich hierarchy of implementations for handling requests, from the very basic to the very complex. You can choose how tightly you wish to couple yourself to the Servlet API. Using the base Spring MVC classes does expose you to the Servlet API. On the other hand, you will see that with Spring Web Flow or the ThrowawayController, the Servlet API can be hidden completely. As with many things in the Spring Framework, the developer is left to choose what is best for that particular situation.
Spring MVC Web Layer
Spring MVC provides an org.springframework.web.servlet.mvc. Controller interface and a very rich class hierarchy below it for its web layer contract. Put very simply, the Controller is responsible for accepting the HttpServletRequest and the HttpServletResponse, performing some unit of work, and passing off control to a View. At first glance, the Controller looks a lot like a standard servlet. On closer inspection, the Controller interface has many rich implementations and a more complete life cycle.
Out of the box, Spring MVC provides many Controller implementations, each varying in its complexity. For instance, the Controller interface simply provides a method analogous to the servlet’s do Service method, assisting very little in the way of navigation logic. On the other hand, the SimpleFormController implements a full single-form workflow, from the initial view of the form, to validation, to form submission. For very complex workflows and user experiences, Spring Web Flow provides a declarative means to navigate a user through a set of actions. Spring Web Flow contains a full-featured state machine so that all of the logic for a user’s path through the system is moved out of the Controllers. This simplifies the wiring and configuration of complex workflows.
When a Controller wants to return information to the client, it populates a ModelAndView. The ModelAndView encapsulates two pieces of information. It contains the model for the response, which is merely a Map of all the data that makes up the response. It also contains a View reference or the reference name for a View (to be looked up by a ViewResolver).
The service layer plays a very important role for both the client and the system. For the client, it exposes and encapsulates coarse-grained system functionality (use cases) for easy client usage. A method is coarse-grained when it is very high level, encapsulating a broad workflow and shielding the client from many small interactions with the system. The service layer should be the only way a client can interact with the system, keeping coupling low because the client is shielded from all the POJO interactions that implement the use case.
For the system, the service layer’s methods represent transactional units of work. This means with one method call, many POJOs and their interactions will be performed under a single transaction. Performing all the work inside the service layer keeps communication between the client and the system to a minimum (in fact, down to one single call). In a highly transactional system, this is important to keep the transaction life span to a minimum. As an added benefit, moving the transactions to a single layer makes it easy to centralize the transaction configurations.
Each method in the service layer should be stateless. That is, each call to a service method creates no state on the object implementing the service interface. No single method call on a service object should assume any previous method calls to itself. Any state across method calls is kept in the domain model.
In a typical Spring MVC application, a single service layer object will handle many concurrent threads of execution, so remaining stateless is the only way to avoid one thread clobbering another. This actually leads to a much more simple design, because it eliminates the need to pool the service objects. This design performs much better than a pool of instances because there is no management of checking the object in and out of the pool. Using a singleton for each service object keeps memory usage to a minimum as well.
This layer attempts to provide encapsulations of all the use cases of the system. A single use case is often one transactional unit of work, and so it makes sense these two aspects are found in the service layer. It also makes it easy to refer to one layer for all the high-level system functionality.
Consolidating the units of work behind a service layer creates a single point of entry into the system for end users and clients. It now becomes trivial to attach multiple client communication mechanisms to a single service interface. For instance, with Spring’s remoting capabilities, you can expose the same service via SOAP, RMI, Java serialization over HTTP, and, of course, standard XHTML. This promotes code reuse and the all-important DRY (Don’t Repeat Yourself) principle by decoupling the transactional unit of work from the transport or user interface.
Domain Model Layer
The domain object model is the most important layer in the system. This layer contains the business logic of the system, and thus, the true implementation of the use cases. The domain model is the collection of nouns in the system, implemented as POJOs. These nouns, such as User, Address, and ShoppingCart, contain both state (user’s first name, user’s last name) and behavior (shoppingCart.purchase()). Centralizing the business logic inside POJOs makes it possible to take advantage of core object-oriented principles and practices, such as polymorphism and inheritance.
Data Access Layer
The data access layer is responsible for interfacing with the persistence mechanism to store and retrieve instances of the object model. The typical CRUD methods are implemented by this layer.
The data access functionality gets its own layer for two reasons. Delegating the persistence functionality into its own layer protects the system from change and keeps tests quick to run and easy to write.
One of the primary reasons for abstraction in object-oriented systems is to isolate sections of the applications from change. The data access functionality is no different, and it is designed to isolate the system from changes in the persistence mechanisms.
Spring Framework Data Access Layer
The Spring Framework really shines when providing data access interfaces. The framework doesn’t have a single common interface for all data access operations, because each toolkit (Hibernate, JDBC, iBATIS, and so on) is so varied. Your business needs will usually dictate the interface design. However, Spring does provide common patterns for interacting with the data access layer. For example, the template pattern is often used by data access operations to shield the implementer from common initialization and cleanup code. You will find template implementations for Hibernate (HibernateTemplate), JDBC (JdbcTemplate), iBATIS (SqlMapTemplate), and others inside the org.springframework.jdbc and org.springframework.orm packages.