Google App Engine

Optimizing Spring Framework for App Engine Applications

Matt Stephenson / Wally Yau
Nov 2012

Introduction

Central to the Spring Framework is its Inversion of Control (IoC) container, alternatively known as Dependency Injection. It allows developers to compose disparate components into a fully working application ready for use. When an application is first loaded, Spring parses the configuration metadata and combine the application classes to create an application context. Depending on the complexity of the application, the initial time required to instantiate the framework can take a long time. This does not pose any problem for services that run in a load once and run forever environment but may become a problem for App Engine applications. App Engine frontend instances are dynamically scaled. That means App Engine automatically creates new instances when load increases and turns off instances when they are not being used. Reloading instances may result in additional latency for users. Frontend instances also have a 60 seconds deadline to complete a given request. Applications that take a long time to load will result in DeadlineExceededException. This article discusses ways you can optimize the initial load time for an application that uses the Spring framework.

Best Practices for App Engine Applications

The following are best practices that can optimize the loading time for App Engine applications that use the Spring Framework.

Reducing or Avoiding the Use of Component Scanning

Spring defines a set of stereotype annotations, which are markers for any class that fulfills a role within an application. For example, the @Repository annotation, which was introduced in Spring 2.0, is used for classes that fulfill the role of Data Access Object of a repository. Another example is the @Controller annotation, which indicates that a particular class serves the role of a controller in the Spring Web MVC framework. Spring provides an option to automatically detect stereotyped classes and register corresponding BeanDefinitions with the ApplicationContext, eliminating the need to specify the stereotyped classes in the XML configuration metadata file. This is achieved by implicitly detecting the candidate components by scanning the classpath and matching against filters.

Real-time component scanning is enabled by using the context:component-scan configuration element in the Spring XML configuration file.

When component scanning is enabled, during the application initialization phase Spring will have to read a large amount of data from the file system in real-time to scan for the stereotyped classes on the classpath. This can cause the initial request to an App Engine application to take an indeterministic amount of time to complete, despite the fact that the App Engine’s virtual file system is a very high performance system.

Disable component scanning by not using the following configuration element in the Spring XML configuration file:

<!-- Component scanning will significantly slow down application initialization time -->
<context:component-scan base-package=””/>

Instead, explicitly declare your dependencies, such as:

<bean id=”myComponentBean” class=”org.foo.MyComponent”/>
<bean id=”myOtherComponentBean” class=”org.bar.MyComponent”/>

If you must use component scanning, pay extra attention to the base-package. If the base-package references classes in a large JAR file, or if it references a significant number of JAR files, or if the base-package refers to a large amount of .class files, the application’s performance will be impacted negatively.

Here are some tips to help mitigate the impact of component scanning on your application’s performance:

  • Breaking up larger JAR files can improve performance of classpath scanning. This is because the application does not have as many classes to scan if Spring can determine which JARS are relevant.
  • It is not advisable to attempt to perform classpath scanning with UberJars or any other form of JAR files generated from “JAR composing” build tools.
  • The use of filters on annotations (e.g. the context:exclude-filter tag) will not help performance in App Engine. There are facilities in place that make this an insignificant performance gain for the application.
  • Try to avoid uploading a large amount of .class files; attempt to “JAR up” these .class files into smaller JAR files that will be compressed and therefore faster to load.

Reducing or Avoiding the Use of Relationship Autowiring

The Spring container can automatically wire relationships between collaboration beans using introspection of the bean classes. This eliminates the need to explicitly specify the relationships as properties or constructor arguments within the application configuration metadata.

Let’s see how the “automatic wiring” of the relationships is enabled. For example, consider the following Spring MVC Controller class with a DAO member,

@Controller
@RequestMapping("/movie")
public class MovieController {
  MovieDaoInterface movieDao;
  public void setMovieDao(MovieDaoInterface movieDao) {
    this.movieDao = movieDao;
  }
}

The Spring IoC uses the following XML configuration to set the member property for MovieController.

<bean class="com.example.controller.MovieController">
  <property name="movieDao" ref="movieDao"></property>
</bean>
<!-- movieDao is defined elsewhere in the container configuration -->
<bean id="movieDao" class="com.example.dao.MovieDao" />

Instead, you enable autowire by using the context:annotation-config element in the spring configuration file and define the bean as shown next:

<context:annotation-config />  <!-- Turn on Autowired -->
<bean class="com.example.controller.MovieController" autowire="byType">
</bean>

While automatic wiring can significantly reduce the complexity of specifying properties or constructor arguments through the use of the XML-based configuration, it significantly increases the time required to resolve the beans during application initialization time. The time penalty is worse when the wiring mode is byType. This is because, in this mode, Spring has to iterate over every bean defined in the application context and must perform Java introspection to find out its type.

If you need to use autowire, make sure that the container is reasonably sized and it uses the byName mode.

Disabling XML Validation in Production

To further reduce the loading time of an application, you can disable XML validation in production by following the steps below:

  1. Create a class that extends XmlWebApplicationContext.
  2. Override the initBeanDefinitionReader method.
  3. Set the XmlBeanDefinitionReader validation mode to VALIDATION_NONE. XML validation is enabled if an App Engine application runs within the App Engine SDK and disabled when it runs in production mode.
    import com.google.appengine.api.utils.SystemProperty;
    
    public class Custom XmlWebApplicationContext extends XmlWebApplicationContext {
             protected void init BeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {
                       super.init BeanDefinitionReader(beanDefinitionReader);
                       if (SystemProperty.environment.value() == SystemProperty.Environment.Value.Production) {
                         beanDefinitionReader.setValidating(false);
                         beanDefinitionReader.setNamespaceAware(true);
                       }
                   }
    }
  4. Open the web.xml file.
  5. Create a section.
  6. Add a element whose value is contextClass.
  7. Add a element whose value points to the class that you created before.
  8. <context-param>
      <param-name>contextClass</param-name>
      <param-value>com.example.CustomXmlWebApplicationContext</param-value>
    </context-param>

Using Lazy-Initialized Beans

Spring’s ApplicationContext creates and configures all singleton beans as part of the initialization process. This is desirable because if there are configuration errors they are discovered immediately. But this has a negative side effect of increasing the application loading time.

This may not be an issue for long-lived services which only have to start once, but is not desirable for the dynamic environment of App Engine applications.

For beans that are used less frequently, and are not required when the container initializes for the first request, this problem can be mitigated by setting the lazy-init attribute to true.

Lazy initialization is implemented using Aspect Oriented Programming (AOP), which may introduce a certain amount of control flow that may or may not be necessary. It uses proxies that construct and delegate to the dependent bean after the bean is requested. This can become a performance problem in situations where it would be just as quick to instantiate the dependency bean versus instantiating a delegating proxy. Lazy initialization can also introduce performance problems if it’s used extensively, and can also complicate the process of debugging.

In the Spring Framework the beans are singleton by default. Singletons are scoped within the IoC container. The use of the term singleton in Spring therefore refers to a single instance of the bean within the IoC container and has no strong relation to the lifecycle of the object in the virtual machine. Therefore, multiple instances of a Spring singleton can exist for any given classloader.

Significant application performance can be achieved by carefully choosing which beans must be initialized during the application loading time.

Avoiding Constructor Injection by Name

Spring 3.0 added support for using the constructor parameter name for value disambiguation. Let’s consider the following sample class as an example:

public class Movie {
  private String name;
  private String synopsis;

  public Movie(String name, String synopsis) {
    this.name = name;
    this.synopsis = synopsis;
  }
}

The corresponding configuration using injection by name is shown as below:

<bean id="movie" class="example.Movie">
  <constructor-arg name="name" value="ET" />
  <constructor-arg name="synopsis" value="Help ET go home" />
</bean>

To make this work “out of the box”, Spring requires that the code must be compiled with the debug flag enabled (-g for all debugging info, or -g:vars to be precise, for the local variable debug information). This allows Spring to look up the parameter name in the debug information. However, since this information is not cached in the JVM, it must be loaded from disk which causes significant I/O time penalty.

To solve this problem you can use one of the following guidelines:

  1. Use the @ConstructorProperties annotation to explicitly name your constructor arguments as shown next.
    public class Movie {
      // Fields omitted
      @ConstructorProperties(({“name”, “synopsis”})
      public Movie(String name, String synopsis) {
        this.name = name;
        this.synopsis = synopsis;
      }
    }
  2. Define the bean without using constructor injection by name:
    <bean id="movie" class="example.Movie">
      <constructor-arg index=0 value="ET" />
      <constructor-arg index=1 value="Help ET go home" />
    </bean>

However, constructor injection by name is a bad programming practice. It is an anti-pattern of dependency injection which relies on the consistent naming of constructor arguments. Here are the potential problems that may lead to problems that are difficult to debug.

  1. When utilizing software that you do not control, the effective definition of the interface itself is extended to include information that is not part of the standard method signature in Java. Therefore, it is entirely possible that someone could change the name of a constructor argument without revising the major or minor versions of the built artifact, causing your application to fail.
  2. Constructor injection can become problematic with any framework or system that rewrites the class bytecode using something similar to ASM. In Java, it is entirely possible to obtain the bytecode of a specific class and modify it to be reloaded by a classloader. Doing so can break linkage of the subsequently defined class with the source it was originally defined with. This means the lookup of the names of the constructor arguments will fail and this again may break the application unpredictably.

Authentication required

You need to be signed in with Google+ to do that.

Signing you in...

Google Developers needs your permission to do that.