Mostrando entradas con la etiqueta java-based spring container configuration. Mostrar todas las entradas
Mostrando entradas con la etiqueta java-based spring container configuration. Mostrar todas las entradas

miércoles, junio 15, 2011

It's Strange But It's True, I Can't Get Over The Way You Love Me Like You Do, But I Have To Be Sure, When I Walk Out That Door (I Want To Break Free - Queen)



Spring Framework 3.1 M2 has been released past week. This new release is the last milestone, and next versions will be tagged as RC.

This new version completes the work started in M1, and adds new functionalities.

To summarize them we can name:

  • Java-based application configuration approach has changed from the @Feature approach in M1 to @Enable* annotations (I will talk about this in next post).
  • Cache abstraction has been revised.
  • A new "packagesToScan" feature for JPA.
  • REST support refinements with respect to URI templates.
  • Many more refinements.

In current post I will talk about one new feature that will allow us to configure Spring Web MVC application without web.xml.

With Servlet 3.0 specification, web.xml is not required anymore, you can configure your servlets using @WebServlet annotation. Prior to Spring 3.1, DispatcherServlet should be declared and configured in web.xml, so although our application was deployed using Servlet 3.0 specification, web.xml was "a must". With Spring 3.1, things are different. You can use WebApplicationInitializer approach for bootstrapping a Spring web application without web.xml.

First of all let’s take a look at traditional way (using web.xml).


No problem here, if you have developed applications using Spring MVC this file will sound you familiar.

But now let’s use WebApplicationInitializer approach.

Spring 3.1 comes with WebApplicationInitializer interface, that must be implemented in Servlet 3.0 environments in order to configure the ServletContext programmatically - as opposed to (or in conjunction with) the traditional web.xml-based approach.

What we need is a class (can be created in any package, next I will explain why!!!) that will implement WebApplicationInitializer. Our equivalent class to previous web.xml is:


See that same information is required, but is provided programmatically instead of using web.xml. Spring application context must be created by you setting config file/s location, DispatcherServlet is still valid and must be registered too using addServlet method, and of course context-param can be added using setInitParameter method. And only creating this class that implements WebApplicationInitializer, you can remove your web.xml from your application.

Look ma' no web.xml and Spring Web application is still working. And now let me explain why if our class is not configured anywhere and moreover is created in any place (inside classpath), is instantiated and its onStartup method called? Servlet 3.0 ServletContainerInitializer is designed to support code-based configuration of the servlet container at startup phase. Spring people have created SpringServletContainerInitializer class that implements ServletContainerInitializer, and this class will be loaded and instantiated and onStartup method invoked by any Servlet 3.0-compliant container during container startup. This occurs through the JAR Services API ServiceLoader.load(Class) method detecting the spring-web module's META-INF/services/javax.servlet.ServletContainerInitializer service provider configuration file.

Hope you like this new feature.

Note: Servlet 3.0 container is required (for example Tomcat 7), and versions of Tomcat <=7.0.14, root mapping ("/") cannot be used.
Download Code.

Music: http://www.youtube.com/watch?v=Odk3W3qLByI

sábado, febrero 19, 2011

Basta Imaginar e Ele Está Partindo, Sereno e Lindo E Se a Gente Quiser....... Ele Vai Pousar.



This week Springsource people have uploaded the first milestone of Spring Framework 3.1.

For my diary work, Environment Abstraction is the best feature developed in current milestone.

Environment Abstraction allows us grouping bean definitions for activation in specific environments. For example you can define two data sources, where one will be used in testing (HSQL configuration) and the other one in production (PostgreSQL). I am sure that in your life using Spring, you have had uploaded by mistake the test database configuration into production code. Environment Abstraction tries to avoid this situation.

Now I have showed you a typical example, but you can also create a custom resolution of place-holders, so for example in test mode you use a properties file with log level property configured to TRACE, and in production the properties file configured to INFO.

Another example that I find it interesting is in acceptance tests. One of my tasks is design and develop planners for robots. In Unit Testing we are mocking the hardware interface with the robot. But in acceptance tests, instead of mocking the hardware interface, we inject an emulator interface, so you can see how a fictional software robot is moving in your screen and validate that all movements are correct visually.

In previous Spring versions, what we have is three Spring XML files, one for production, another one for acceptance tests, and one main file that imports one of both files, so depending on environment we import one file or another. As you can imagine this implies a manual process between production environment and testing environment; although is not tedious, can be omitted so having emulator hardware interface in production instead of driver interface to robot.

With Spring 3.1, only one file is required with both configurations, and depending on environment Spring loads the required beans.

An example of what I am explaining is:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
     <beans profile="test, integration">
          <bean .../>
          <bean .../>
          <context:property-placeholder .../>
     </beans>
     <beans profile="production">
          <bean .../>
          <bean .../>
          <context:property-placeholder .../>
     </beans>
     <beans>
          <bean ..../>
     </beans>
</beans>

First thing you will notice is that beans tag is still the root but also is self-nested. The first two nested beans have an attribute called profile. This attribute inform when the beans it contains are active. First beans are active when configured profile is test or integration, while second ones when production profile is active. The last one definition is always activated.

Continuously we are writing something like "depending on environment", and I suppose you are wondering how you specify that environment.

You have an environment variable called spring.profiles.active where you specify which is the current profile. For setting this variable you can use an export in case of *nix systems, or as parameter execution -Dspring.profiles.active, or in context.xml in case of web applications, ...

For example a valid environment definition should be:

export spring.profiles.active=test

In case you are using Java-based Container Configuration, @Profile("profileName") can be used in beans definition, for specifying profile name.

ApplicationContext has getEnvironment() method for specifying which profiles are activated.

AnnotationConfigApplicationContext ctx = ...
ctx.getEnvironment().setActiveProfiles("dev");
ctx.register(...)
ctx.refresh();


I have developed a simple example that have two classes, where one prints passed message in upper case, and the other one prints the message between sharp character. Depending on profile configuration it changes message format. Moreover the same example is provided but using Java-based Container Configuration.

Download code from my GITHub if you want to see the source code.

I hope you find this new feature as useful as I find, and more important, once you have configured your machines with required environment variable, you won't worry any more about changing configuration files.