lunes, junio 20, 2011

Tonari No To To Ro Totoro To To Ro Totoro, Kodomo No Toki Ni Dake Anata Ni Otozureru, Fushigina Deai (Tonari No Totoro - Ghibli Songs)

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 some new functionalities.

To summarize them we can name:

  • Configuring Spring Web MVC application without web.xml (post).
  • Cache abstraction has been revised.
  • A new "packagesToScan" feature for JPA.
  • REST support refinements with respect to URI templates.
  • And many more refinements.

In current post I will talk about Java-based container configuration approach to setting up a Spring Web MVC application.

As a reference application we are going to migrate Spring MVC Template Project to 100% Java-based container configuration.

If you are using STS, you can create a new Spring project from Spring Template Project wizard:

One of these templates is for creating a Spring Web MVC application. In my STS version, this template creates a XML-based container configuration project.

As you have already noted, important elements of this project are: 
  • HomeController that redirects to home.jsp page.
  • web.xml file where Spring DispatcherServlet (loading servlet-context.xml) and ContextLoaderListener (loading root-context.xml) are specified.
  • root-context.xml defining shared resources visible to all other web components.
  • servlet-context.xml defining servlet's request-processing infrastructure, and importing controllers.xml configuration file.
  • controllers.xml as its name suggests configures controllers.

What we are going to create is a revision of Spring MVC Template Project that instead of setting up project using XMLs, is configured using Java classes. The new directory structure is:

If you look carefully, under src/main/webapp directory, there are no XML Spring configuration files. And no web.xml, but I will talk about that later. For now imagine that under WEB-INF there is a web.xml file.

See that structure is very similar to previous one, but spring directory is removed and config package is created. Moreover XML files have been converted to  standard classes.

Again ignore strange WebAppInitializer class that has appeared. Let's see applied changes:

root-context.xml has its equivalent with mytld.mycompany.myapp.config.RootContextConfig.

Most important thing in previous class is @Configuration annotation. This annotation indicates that the class can be used by the Spring IoC container as a source of bean definitions.

Class that replaces servlet-context.xml file is:

I am going to show you servlet-context.xml content so you can ensure that XML and Class contain  the same parameters.

Apart from @Configuration annotation, this class is annotated with @EnableWebMvc, which enables @Controller programming model, and @Import for importing other bean definitions, like servlet-context.xml imports controllers.xml. This class extends from WebMvcConfigurerAdapter because some extra configuration is required. WebMvcConfigurerAdapter defines options for customizing or adding to the default Spring MVC configuration. In summary it provides customizing parameters as mvc namespace does. In our case, as servlet-context does, we define static resources path to /resources/, so we only override configureResourceHandling method. If for example we would like to register interceptors, configureInteceptors method should be overridden. And finally @Bean is used for creating the view resolver bean. @Bean methods define instantiation, configuration, and initialization logic for objects to be managed by the Spring IoC container.

Next class is called ControllerConfig and is the responsible of registering controllers. In this case @Bean approach is used because component-scan is not supported directly. Anyway you can use scan method of AnnotationConfigApplicationContext for same purpose but in this case first choice has been chosen.

And finally web.xml must be changed for loading Java-based configuration instead of XML-based ones. In this case contextClass parameter of DispatcherServlet and ContextLoader listener must be changed to AnnotationConfigWebApplicationContext so Spring IoC Container can load beans from configuration classes, and contextConfigLocation must be pointing to configuration classes, and not XML files.

And I suppose you are wondering why in previous directory structure cannot be seen web.xml but WebAppInitializer class. This is explained in my post, and is another new feature of Spring 3.1 M2, that you can configure a Spring Web MVC application with no web.xml.

So if you want a 100% Java-based configuration, simply removes web.xml file and creates the WebAppInitializer class, which looks like:

As you can see, same elements of web.xml are present but they are configured in a programmatic way.

Hope you find the post useful, of course you can create hybrid applications, mixing elements configured in XML way and other ones configured in Java classes.

Two Spring Template Projects are provided, one configuring Spring MVC application in a Java-based fashion and web.xml, and another one 100% Java-based configured.

Spring Template Project with web.xml
Spring Template Project no web.xml


5 comentarios:

Chris Beams dijo...

Nice post, Alex! Just one suggestion: I would recommend naming your "Controller" @Configuration class "ControllerConfig" or something similar. This will help avoid confusion with Spring's own @Controller annotation, and it's probably a good idea in general to use a "Config" or "Configuration" suffix to clarify the purpose of @Configuration classes.

Alex dijo...

Chris, Thank you very much for you comment. I have changed in post the names of classes, and soon I will change zip contents too.

Alex dijo...

All changes done. Thanks again Chris.

Ralph dijo...

Instead of @Import({ControllerConfig.class}) you could use a component-scan annotation. Something like this works. This way you don't need the ControllerConfig class anymore.

@ComponentScan(basePackages = "mytld.mycompany.myapp", useDefaultFilters = false,
includeFilters = { @Filter(type = FilterType.ANNOTATION, value = Controller.class) })
public class ServletContextConfig extends WebMvcConfigurerAdapter {

Alex dijo...

Thanks for the comment Ralph, it is also a nice possibility, but because I wanted that Java files seems as much as possible to XML files.