Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring MVC why this Hello World run well without annotation-driven tag (unlike any other project Spring)

I have begin to study Spring MVC reading this tutorial: http://viralpatel.net/blogs/spring-3-mvc-create-hello-world-application-spring-3-mvc/

Ok, this is very clear for me.

In this example I have the web.xml file to configure my web application:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee    /web-app_2_5.xsd"
id="WebApp_ID" version="2.5">

<display-name>Spring3MVC</display-name>
<welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
</welcome-file-list>

<servlet>
    <servlet-name>spring</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>*.html</url-pattern>
</servlet-mapping>

And the spring-servlet.xml file used to configure mu DispatcherServlet:

<?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:p="http://www.springframework.org/schema/p"
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.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<context:component-scan
    base-package="net.viralpatel.spring3.controller" />

<bean id="viewResolver"
    class="org.springframework.web.servlet.view.UrlBasedViewResolver">
    <property name="viewClass"
        value="org.springframework.web.servlet.view.JstlView" />
    <property name="prefix" value="/WEB-INF/jsp/" />
    <property name="suffix" value=".jsp" />
</bean>

And, as you can see in the previus link I have only a controller class that handle the HTTP Request toward "/hello" URL...ok...this is clear for me...

Next to this example I have create a new Spring MVC Project by the related template project in STS\Eclipse.

This example is very very similar to te previus one: I always have the web.xml file to confiure my web app, a file to configure the DispatcherServlet and a controller class that handle the HTTP Request.

But there is some difference that I can not understand.

This is my web.xml configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
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_2_5.xsd">

<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>


<!-- Creates the Spring Container shared by all Servlets and Filters -->

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- Processes application requests -->
<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

And this is the servlet-context.xml file (the configuration file that configure my DispatcherServlet):

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<context:component-scan base-package="com.mycompany.maventestwebapp" />
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />

<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />

<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <beans:property name="prefix" value="/WEB-INF/views/" />
    <beans:property name="suffix" value=".jsp" />
</beans:bean>

Ok, as you can see there is some difference in the configuration files of the two example:

In the project created by STS\Eclipse, within the servlet-context.xml file I have these configuration that are not present in the first example that I posted:

<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />

Ok...I have read a lot of documentation about this configuration tag: means that you can define spring beans dependencies without actually having to specify a bunch of elements in xml or implement an interface or extend a base class. When spring starts up it reads its xml configuration file and looks for and Foo was marked up with @Controller it knows that the class is a controller and treats it as such. By default spring assumes that all the classes it should manage are explicitly defined in the beans.xml file. Then there is the component scanning tag that tell to Spring that it should search the class path for all the classes under com.mycompany.maventestweapp and look at each class to see if it has a @Controller, or @Repository, or @Service, or @Component and if it does then Spring will register the class with the bean factory as if you had typed in the xml configuration files. BLABLABLA ETCETCETC BLABLA

Ok, this is absolutly clear for me !!! I think that I have NO PROBLEM to understand why I have the annotation-driven tag inside the DispatcherServler configuration file of my second example, this is clear.

The problem is to understand WHY I HAVE NOT THIS TAG in the DispatcherServlet configuration file of my first example and why it work well If I try to delete this tag form the servlet-context.xml file (in my second example) this don't run and go into error sayng me: HTTP Status 404 - and in the stack trace I have: WARN : org.springframework.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/maventestwebapp/] in DispatcherServlet with name 'appServlet'

I think that it is rational behavior because Spring has not enabled the annotation support, so have not register my controller class (using annotation-driven and annotating my controller class with @Controller is how if I have this class explicitly defined in a bean.xml file), so can't use the methods of this bean to handle HTTP Request...ok...this sound good...

But then why in the first example works without having annotation-driven tag ? I have no annotation-driven tag (so I am not enabling the use of annotation to declare what class is a Spring bean such as a controller) and I have not explicitly declared this class in a beans.xml file...so should not work as the second example does not work when I remove the annotation-driven tag...but it work :-/

I am going crazy to understand why...

Please, can you help me?

Thank you so much

Andrea

like image 976
AndreaNobili Avatar asked Dec 02 '12 17:12

AndreaNobili


People also ask

Why we use MVC annotation driven?

mvc:annotation-driven is used for enabling the Spring MVC components with its default configurations. If you dont include mvc:annotation-driven also your MVC application would work if you have used the context:component-scan for creating the beans or defined the beans in your XML file.

Is Spring MVC still used?

Yes. Whenever someone uses Spring Boot for creating RESTful web services, chances are they are using Spring MVC (part of Spring Web starter, see http://start.spring.io and search Web in dependencies) although Spring has also been offering another web framework, Spring WebFlux.

Does spring boot eases the development of new spring application?

Spring Boot is a Framework from “The Spring Team” to ease the bootstrapping and development of new Spring Applications. It provides defaults for code and annotation configuration to quick start new Spring projects within no time.


1 Answers

<mvc:annotation-driven> is a helper tag that provides additional services:

  • Register the default handler mappings
  • Message conversion (for example, converting the object returned in the controller to JSON)
  • JSR 303 validation (@Valid annotation)
  • Conversion service (if the converter is specified then the controller will be able to take entities as arguments, i.e. the textual ids from request will be converted to the actual business objects with the MVC layer. The same goes for other objects like Dates, Enums etc.)
  • Maybe even more features will be added in the new versions of Spring..

it is implemented with AnnotationDrivenBeanDefinitionParser in org.springframework.web.servlet.config package

It's not required for your simple controller to work, if you have appropriate mappings (you can add the required beans explicitly if you want). But if you want to do some more or less advanced stuff for example JSR 303 validation, implementing a REST service with JSON, registering a conversion service for MVC, this tag turns out to be useful because it keeps the configuration of these services in one place.

That is why it's included into the Spring template project(template project is rather a starting point for developing a Spring application(so you can just go and put @Responsebody on the values returned by the controller methods or add a converter to MVC) than just an example for the Spring learners).

Also please note that the handler mapping configuration changed in Spring 3.1:

Prior to Spring 3.1, type and method-level request mappings were examined in two separate stages -- a controller was selected first by the DefaultAnnotationHandlerMapping and the actual method to invoke was narrowed down second by the AnnotationMethodHandlerAdapter.

like image 96
Boris Treukhov Avatar answered Nov 15 '22 07:11

Boris Treukhov