O Papel Central do DispatcherServlet
O DispatcherServlet é o componente fundamental do framework Spring Web MVC, atuando como um controlador frontal unificado para todas as requisições web. Inspirado no padrão de design Front Controller, ele centraliza o ponto de entrada para aplicações web, delegando responsabilidades específicas aos componentes apropriados e garantindo a integração perfeita com o contêiner IoC (Inversion of Control) do Spring, permitindo que a aplicação aproveite todos os benefícios da estrutura.
As principais funções do DispatcherServlet incluem:
- Processamento de Uploads: Gerencia o tratamento de requisições do tipo
multipart, como uploads de arquivos, utilizando umMultipartResolver. - Mapeamento de Requisições: Utiliza um
HandlerMappingpara associar as requisições HTTP a controladores específicos, retornando uma cadeia de execução (HandlerExecutionChain) que pode incluir o handler e vários interceptadores (HandlerInterceptor). - Adaptação de Handlers: Através de um
HandlerAdapter, oDispatcherServletsuporta diversos tipos de handlers (controladores), adaptando a interface para a execução. - Resolução de Vistas: Transforma nomes lógicos de vistas em implementações de vistas concretas usando um
ViewResolver. - Resolução de Localização: Determina as informações de localidade (
Locale) para suporte à internacionalização. - Renderização da Vista: Executa a renderização final da vista para o cliente.
- Tratamento de Exceções: Em caso de erros durante a execução, o
HandlerExceptionResolveré acionado para gerenciar e apresentar respostas de erro adequadas.
Em suma, o DispatcherServlet coordena o fluxo de requisições e respostas, oferecendo pontos de extensão flexíveis em cada etapa do processo.
Configuração Básica do DispatcherServlet no web.xml
A configuração do DispatcherServlet é tipicamente realizada no descritor de implantação da aplicação web, o arquivo web.xml. Abaixo, um exemplo de configuração:
<!-- Definição do DispatcherServlet para o Spring MVC -->
<servlet>
<servlet-name>minhaAppMvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/config/spring-web-config.xml</param-value>
</init-param>
<!-- Carrega o servlet na inicialização da aplicação -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Mapeamento de URL para o DispatcherServlet -->
<servlet-mapping>
<servlet-name>minhaAppMvc</servlet-name>
<!-- Todas as requisições serão processadas pelo DispatcherServlet -->
<url-pattern>/</url-pattern>
</servlet-mapping>
Parâmetros de inicialização (<init-param>) podem ser utilizados para personalizar o comportamento do DispatcherServlet:
contextClass: Define a classe que implementaWebApplicationContextpara criar o contexto do servlet. O padrão éXmlWebApplicationContext.contextConfigLocation: Especifica o(s) caminho(s) para os arquivos de configuração do contexto. Pode ser uma lista de caminhos separados por vírgula. Se não especificado, o Spring procurará por um arquivo no formato/WEB-INF/[servlet-name]-servlet.xml. No exemplo acima, ele buscaspring-web-config.xmlno classpath.namespace: Atribui um nome para o contexto da aplicação web. O valor padrão é[servlet-name]-servlet.
A Relação entre Contextos de Aplicação
Em ambientes web Spring, é comum ter uma hierarquia de contextos de aplicação. A configuração abaixo mostra a criação de um contexto raiz, geralmente para beans de infraestrutura (DAO, Service):
<!-- Parâmetro para o Listener do Contexto Raiz -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:config/app-datasource.xml,
classpath:config/app-services.xml
</param-value>
</context-param>
<!-- Listener para carregar o Contexto Raiz -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
O ContextLoaderListener inicializa um WebApplicationContext (conhecido como contexto raiz) que é compartilhado por toda a aplicação. Este contexto geralmente contém beans de negócio e persistência (e.g., serviços e DAOs) que não dependem da tecnologia de apresentação.
O DispatcherServlet, por sua vez, inicializa seu próprio WebApplicationContext. Este contexto do servlet é um "filho" do contexto raiz. Isso significa que os beans definidos no contexto do DispatcherServlet podem referenciar os beans do contexto raiz, mas o contrário não é verdadeiro. O contexto do DispatcherServlet é dedicado a beans relacionados à camada web, como controladores, mapeadores de handlers e resolvedores de vistas.
Visualmente, essa relação pode ser pensada como: o contexto raiz provê recursos globais e de infraestrutura (como serviços e repositórios) para toda a aplicação, enquanto cada DispatcherServlet (pode haver mais de um em uma aplicação) tem seu próprio contexto, especializado em componentes web (como controladores), que herda e acessa os recursos do contexto raiz. Isso promove uma arquitetura modular e desacoplada.
Sequência de Inicialização do DispatcherServlet
A inicialização do DispatcherServlet segue uma hierarquia de classes no Spring Framework:
HttpServletBean: Esta é a base que estendejavax.servlet.http.HttpServlet. Durante o métodoinit()padrão do servlet, ele processa os parâmetros de inicialização definidos noweb.xmle os injeta como propriedades na própria instância do servlet. Ele também oferece um ponto de extensão, o métodoinitServletBean(), que é implementado pelas subclasses.FrameworkServlet: EstendeHttpServletBeane é responsável pela inicialização doWebApplicationContextpara o servlet. No métodoinitServletBean(), ele cria e configura o contexto web. Após a inicialização do contexto, ele chama o métodoonRefresh(), que é um ponto de extensão para a configuração específica do framework.DispatcherServlet: Esta é a classe concreta que estendeFrameworkServlete implementaonRefresh(). NoonRefresh(), oDispatcherServletexecuta as configurações específicas para o Spring Web MVC. Isso inclui a inicialização dos diversos componentes estratégicos (comoHandlerMapping,HandlerAdapter,ViewResolver, etc.) que ele usará para processar as requisições. Se um contexto raiz (doContextLoaderListener) estiver presente, ele será definido como o pai do contexto doDispatcherServlet.
As estratégias padrão utilizadas pelo DispatcherServlet (quando não configuradas explicitamente) são carregadas de um arquivo de propriedades chamado DispatcherServlet.properties, localizado no mesmo pacote da classe DispatcherServlet.
Beans Especiais Utilizados pelo DispatcherServlet
Dentro do seu WebApplicationContext, o DispatcherServlet utiliza uma série de beans especiais (também conhecidos como objetos de estratégia) para gerenciar o fluxo de requisições. Estes são alguns dos mais importantes:
Controller: Representa o "C" no MVC. Responsável por processar requisições após o mapeamento doHandlerMapping.HandlerMapping: Mapeia requisições de entrada (URLs) para handlers (geralmente controladores). Retorna umHandlerExecutionChainque contém o handler e interceptadores associados.HandlerAdapter: Permite que oDispatcherServletinvoque qualquer tipo de handler, independentemente de sua interface, agindo como um adaptador para o handler retornado peloHandlerMapping.ViewResolver: Traduz um nome lógico de vista (string) retornado por um controlador para uma implementação de vista concreta (e.g., um arquivo JSP, uma template Thymeleaf).LocaleResolver: Deterimna a localidade do usuário (idioma, região) a partir da requisição, essencial para internacionalização.ThemeResolver: Habilita a aplicação de temas (estilos visuais) a uma aplicação, permitindo mudar a aparência da interface do usuário.MultipartResolver: Trata requisições de upload de arquivos (multipart/form-data), extraindo os arquivos da requisição HTTP.HandlerExceptionResolver: Fornece um mecanismo para resolver exceções que ocorrem durante o processamento da requisição, permitindo mapear exceções para vistas de erro específicas.RequestToViewNameTranslator: Uma estratégia que, quando um controlador não retorna um nome de vista explícito, deriva um nome lógico de vista a partir da URL da requisição.FlashMapManager: Gerencia osFlashMaps, que são usados para armazenar atributos por um curto período, tipicamente para serem usados após um redirecionamento (e.g., mensagens de sucesso ou erro que precisam ser exibidas na próxima página).