Spring MVC: разница между тегами <context: component-scan> и <annotation-driven/">?

Несколько дней назад я начал изучать этот учебник Spring Hello World: http://viralpatel.net/blogs/spring-3-mvc-create-hello-world-application-spring-3-mvc/

В этом учебнике Spring DispatcherServlet настроен с использованием файла spring -servlet.xml, следующего:

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

В этом файле я использую тег context: component-scan, чтобы сказать, что Spring должен сканировать мой файл, ищущий аннотацию, так, например, когда класс контроллера обнаруживает, что метод аннотируется аннотацией @RequestMapping ( "/hello" ), которая знает, что этот метод обрабатывает HTTP-запрос по URL-адресу, заканчивающийся на "/hello". Это просто...

Теперь мое сомнение связано с проектом шаблона Spring MVC, который я мог бы автоматически построить в STS\Eclipse.

Когда я создаю новый проект Spring MVC в STS, у меня есть, что мой DispatcherServlet настроен файлом с именем servlet-context.xml, который содержит некоторую конфигурацию, похожую на предыдущий файл примера.

В этом файле у меня все еще есть тег проверки компонента:

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

но у меня есть еще один тег (похожий на похожую задачу):

<annotation-driven />

В чем разница между этими двумя тегами?
Другая "странная" вещь заключается в том, что предыдущий пример (который не использует тег, основанный на аннотациях) очень похож на проект, созданный STS, с использованием проекта шаблона Spring MVC, но если я удалю тег, управляемый аннотациями, из его файл конфигурации не запускается и дает мне следующую ошибку: Статус HTTP 404

И в stacktrace у меня есть:

WARN: org.springframework.web.servlet.PageNotFound - сопоставления не найдено для HTTP-запроса с URI [/maventestwebapp/] в DispatcherServlet с именем "appServlet"

Но почему? Предыдущий пример хорошо работает без аннотационного тега, и этот класс контроллера очень похож. На самом деле существует только один метод, который обрабатывает HTTP-запрос к пути "/"

Это код моего класса контроллера:

package com.mycompany.maventestwebapp;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * Handles requests for the application home page.
*/
@Controller
public class HomeController {

private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

/**
 * Simply selects the home view to render by returning its name.
 */
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
    logger.info("Welcome home! The client locale is {}.", locale);

    Date date = new Date();
    DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

    String formattedDate = dateFormat.format(date);

    model.addAttribute("serverTime", formattedDate );

    return "home";
}

Может кто-нибудь помочь мне понять эту вещь?

Большое спасибо!

Ответ 1

<mvc:annotation-driven /> означает, что вы можете определить зависимости spring beans, не имея при этом необходимости указывать кучу элементов в XML или реализовывать интерфейс или расширять базовый класс. Например @Repository, чтобы сообщить spring, что класс является Dao без расширения JpaDaoSupport или какого-либо другого подкласса DaoSupport. Аналогично @Controller сообщает spring, что указанный класс содержит методы, которые будут обрабатывать запросы Http без необходимости реализации интерфейса контроллера или расширения подкласса, который реализует контроллер.

При запуске spring он считывает свой файл конфигурации XML и ищет внутри него элементы <bean, если он видит что-то вроде <bean class="com.example.Foo" />, а Foo помечен @Controller, он знает, что класс является контроллером и рассматривает его как таковой. По умолчанию spring предполагает, что все классы, которым он должен управлять, явно определены в файле beans.XML.

Сканирование компонентов с помощью <context:component-scan base-package="com.mycompany.maventestwebapp" /> сообщает spring, что он должен искать путь к классам для всех классов в com.mycompany.maventestweapp и просматривать каждый класс, чтобы увидеть, имеет ли он @Controller или @Repository, или @Service, или @Component, и если это произойдет, то spring зарегистрирует класс с помощью bean factory, как если бы вы набрали <bean class="..." /> в файлах конфигурации XML.

В типичном приложении spring MVC вы обнаружите, что есть два файла конфигурации spring, файл, который настраивает контекст приложения, обычно начинающийся с прослушивателя контекста spring.

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

И файл конфигурации spring MVC обычно начинается с сервлета диспетчера spring. Например.

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

Spring имеет поддержку иерархических bean фабрик, поэтому в случае spring MVC контекст сервлета диспетчера является дочерним по отношению к основному контексту приложения. Если контекст сервлета был запрошен для bean, называемого "abc", он сначала рассмотрит контекст сервлета, если он не найдет его там, он будет выглядеть в родительском контексте, который является контекстом приложения.

Общие beans, такие как источники данных, конфигурация JPA, бизнес-службы определяются в контексте приложения, тогда как конфигурация MVC не является конфигурационным файлом, связанным с сервлетом.

Надеюсь, это поможет.

Ответ 2

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

сообщает Spring сканировать эти пакеты для аннотаций.

<mvc:annotation-driven> 

регистрирует RequestMappingHanderMapping, RequestMappingHandlerAdapter и ExceptionHandlerExceptionResolver для поддержки методов аннотированных контроллеров, таких как @RequestMapping, @ExceptionHandler и т.д., которые поставляются с MVC.

Это также позволяет ConversionService, который поддерживает форматирование выходных данных, зависящих от Annotation, а также верификацию, основанную на аннотации, для входных данных. Он также поддерживает поддержку @ResponseBody, которую вы можете использовать для возврата данных JSON.

Вы можете выполнить то же самое, используя конфигурацию на основе Java, используя @ComponentScan (basePackages = { "...", "..." } и @EnableWebMvc в классе @Configuration.

Ознакомьтесь с документацией 3.1, чтобы узнать больше.

http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-config

Ответ 3

Обозначение с аннотацией указывает на Spring, что он должен сканировать аннотированный beans и не просто полагаться на конфигурацию XML bean. Компонент-сканирование указывает, где искать эти beans.

Вот несколько документов: http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-config-enable