By Subham Aggarwal | 5/25/2017 | General |Beginners

Bootstrapping a Spring Web app

Bootstrapping a Spring Web app

In this tutorial, we will explain how to bootstrap a Spring web application and more importantly, how to make the necessary jump from an XML configuration to a Java annotation based configuration.

 

When we start to move from XML to Java based configuration, it is important to understand that we can do it step by step and don’t have to enforce it in our complete app all at once. We will be looking at it in more detail, right now!

Maven pom.xml

Let us have a look at the shortest and most basic maven configuration required for Spring Web MVC to be included in our project:

<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="
     http://maven.apache.org/POM/4.0.0
     http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.discoversdk</groupId>
  <artifactId>spring</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>

  <properties>
     <spring.version>4.0.5.RELEASE</spring.version>
  </properties>
  <dependencies>
     <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
        <exclusions>
           <exclusion>
              <artifactId>commons-logging</artifactId>
              <groupId>commons-logging</groupId>
           </exclusion>
        </exclusions>
     </dependency>
      
  </dependencies>
  <build>
     <finalName>rest</finalName>
     <plugins>
        <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-compiler-plugin</artifactId>
           <version>3.1</version>
           <configuration>
              <source>1.8</source>
              <target>1.8</target>
              <encoding>UTF-8</encoding>
           </configuration>
        </plugin>
     </plugins>
  </build>

</project>

CGLib Dependency before Spring 3.2

It is worth noting that including cglib as a dependency comes with a valid reason—the entire configuration cannot function without it. If removed, Spring will throw an error as follows:

 

Caused by: java.lang.IllegalStateException: CGLIB is required to process @Configuration classes. Either add CGLIB to the classpath or remove the following @Configuration bean definitions

 

The reason this occurs can be understood by the way Spring deals with @Configuration classes. These classes are effectively beans, and because of this they need to be aware of the Context, and respect scope and other bean semantics. This is achieved by dynamically creating a cglib proxy with this awareness for each @Configuration class, hence the cglib dependency.

Also, because of this, there are a few other restrictions for Configuration annotated classes as well:

  • Configuration classes should not be final
  • They should have a constructor with no arguments

CGLib Dependency after Spring 3.2

With the release of Spring 3.2 and later versions, it is no longer required to add cglib as a dependency. This is because Spring is in now inlining cglib which will ensure that all class based proxying functionality will work by default with Spring 3.2.

 

The new dependency for cglib is now kept under the package org.springframework.cglib. By changing the package, Spring ensures no conflict will occur when we decide to upgrade the Spring version in our project.

Java Based configuration

Now that it is smarter, faster, and less-error prone, we can actually use Java and Java based annotations to configure Spring and other related Beans in a Java class which enables debugging as well. Let us a look at a basic configuration Java class now.

@Configuration
@ImportResource({"spring-context1.xml", "spring-context2.xml"})
@ComponentScan( basePackages = "com.discoversdk" )
@PropertySource({
 "classpath:mvc.properties",
 "classpath:root.properties"
})
public class AppConfig{
  @Bean
  public static PropertySourcesPlaceholderConfigurer
    properties() {
 
     return new PropertySourcesPlaceholderConfigurer();
  }
}

Now, let’s study each part of this class individually to understand it completely:

  • @Configuration: Annotating a class with the @Configuration specifies that the class can be used by the Spring IoC container as a source of bean definitions.
  • @ImportResource: Indicates one or more files from which resources like existing XML configurations needs to be imported. This may be the configuration which is still being migrated from XML to Java, or simply the legacy configuration that you wish to keep. The equivalent XML annotation that is replaced is:

 

<import resource="spring-context1.xml" />
<import resource="spring-context2.xml" />
  • @ComponentScan: This annotation directs the Spring IoC container to scan for components like Controllers etc. in the specified package. The equivalent XML configuration would be:

      

<context:component-scan base-package="com.discoversdk" />

 

  • @Bean: This annotation marks creation for a bean. The earlier related XML looks like:

 

    <context:property-placeholder
 location="classpath:persistence.properties, classpath:web.properties"
ignore-unresolvable="true"/>

Servlet Context listener (Web.xml approach)

Using web.xml, we would have the following sample XML based file in our project as web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="
   http://java.sun.com/xml/ns/javaee"
   xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="
      http://java.sun.com/xml/ns/javaee
      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
   id="rest" version="3.0">
  <context-param>
     <param-name>contextClass</param-name>
     <param-value>
 org.springframework.web.context.support.AnnotationConfigWebApplicationContext
     </param-value>
  </context-param>
  <context-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>com.discoversdk.spring.root</param-value>
  </context-param>
  <listener>
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <servlet>
     <servlet-name>discoversdk</servlet-name>
     <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
     </servlet-class>
     <init-param>
        <param-name>contextClass</param-name>
        <param-value>
           org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
     </init-param>
     <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>com.discoversdk.spring.discoversdk</param-value>
     </init-param>
     <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
     <servlet-name>discoversdk</servlet-name>
     <url-pattern>/api/*</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
     <welcome-file />
  </welcome-file-list>
</web-app>

Let us see how it actually works:

  1. A web application WAR is being deployed by the user.
  2. Servlet container (Tomcat) reads web.xml.
  3. Servlet context listener ContextLoaderListener is being instantiated (if defined as <listener> inside the web.xml) by servlet container.
    1. ContextLoaderListener creates new WebApplicationContext with application context XML configuration.
    2. Your ROOT context beans are registered and instantiated by BeanFactory inside the application context.
  4. DispatcherServlet is being instantiated by servlet container.
    1. DispatcherServlet creates its own WebApplicationContext (WEB-INF/{servletName}-servlet.xml by default) with the ROOT context as its parent.
    2. Your servlet beans are registered and instantiated by BeanFactory inside the application context.
    3. DispatcherServlet registers some default beans in case you did not provide them yourself.

Servlet container initializer (non web.xml) approach

This one is possibility with Servlet 3 features.

  1. A web application WAR is being deployed by the user.
  2. Servlet container searches for classes implementing ServletContainerInitializer via Java's ServiceLoader.
  3. Spring's SpringServletContainerInitializer is found and instantiated by servlet container.
  4. Spring's initializer reads web application's class-path and searches for WebApplicationInitializer implementations.
  5. Your WebApplicationInitializer is found (btw. check its JavaDoc!!!) and instantiated by SpringServletContainerInitializer.
    1. Your WebApplicationInitializer creates new ROOT WebApplicationContext with XML or @Configuration based configuration.
    2. Your WebApplicationInitializer creates new servlet WebApplicationContext with XML or @Configuration based configuration.
    3. Your WebApplicationInitializer creates and registers new DispatcherServlet with the context from previous step.
  6. Servlet container finishes the web application initialization and instantiates components which were registered by their class in previous steps.

Conclusion

The Java based approach is much more flexible. We can just leave the context creation to DispatcherServlet or even the whole instantiation of DispatcherServlet itself to servlet container (just register servlet DispatcherServlet.class instead of its instance).

 

In this article, we learned about how to make the leap from XML to Java slowly and how it is different in latest versions of Spring framework.

By Subham Aggarwal | 5/25/2017 | General

{{CommentsModel.TotalCount}} Comments

Your Comment

{{CommentsModel.Message}}

Recent Stories

Top DiscoverSDK Experts

User photo
3355
Ashton Torrence
Web and Windows developer
GUI | Web and 11 more
View Profile
User photo
3220
Mendy Bennett
Experienced with Ad network & Ad servers.
Mobile | Ad Networks and 1 more
View Profile
User photo
3060
Karen Fitzgerald
7 years in Cross-Platform development.
Mobile | Cross Platform Frameworks
View Profile
Show All
X

Compare Products

Select up to three two products to compare by clicking on the compare icon () of each product.

{{compareToolModel.Error}}

Now comparing:

{{product.ProductName | createSubstring:25}} X
Compare Now