Nesse artigo, veremos como criar uma aplicação Spring sem precisar criar os tradicionais arquivos XML web.xml e spring-servlet.xml. Usaremos aqui apenas classes Java com as devidas anotações.
O artefato central do suporte do Spring para configuração baseado em código Java é a anotação de classe @Configuration
. Classes anotadas dessa forma consistem basicamente de métodos anotados com @Bean
que definem a instancialização, configuração e lógica para os objetos gerenciados pelo Spring.
Anotar uma classe com @Configuration
indica que essa classe pode ser usada pelo Spring como fonte de definições de beans. A classe mais simples a fazer uso de @Configuration
seria a seguinte:
@Configuration public class AppConfig { }
Uma aplicação pode fazer uso de um ou várias classes anotadas com @Configuration
. @Configuration
é meta-anotada como @Component
. Dessa forma, classes anotadas com @Configuration
são candidatas à escaneamento de componentes e podem tirar vantagem da anotação @Autowired
em atributos e métodos, mas não em construtores.
Desde a versão 3.0 da specificação do ervlet, podemos eliminar o uso do venerável arquivo web.xml. Para podermos fazer isso, basta criar uma classe que implemente ServletContainerInitializer e um arquivo META-INF/services/javax.servlet.ServletContainerInitializer contendo o nome completo de sua implementação.
Spring
Desde a versão 3.1, o Spring fornece uma implementação da interface ServletContainerInitializer com o nome SpringServletContainerInitializer. Se você der uma olhada no arquivo spring-web-[versão 3.1 ou mais recente].jar verá o arquivo META-INF/services mencionada acima.
A classe SpringServletContainerInitializer delega a sua implementação de
org.springframework.web.WebApplicationInitializer o controle do fluxo de ação. Existe apenas um método que você precisa implementar:
WebApplicationInitializer#onStartup(ServletContext)
Onde você deve especificar o ServletContext que precisa inicializar.
public class WebAppInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) { WebApplicationContext appContext = ?; //set up the context ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(appContext)); dispatcher.setLoadOnStartup(1); dispatcher.addMapping("/"); } }
Configurando os contextos
Como estamos evitando escrever arquivos XML, sugiro que em vez de usar a classe XmlWebApplicationContext, você use AnnotationConfigWebApplicationContext que suporta o escaneamento do classpath por configurações baseadas em anotações do Spring. Você pode explicitamente adicionar classes de configuração também.
Para iniciar ou desligar o contexto, devemos adicionar um ContextLoaderListener.
@Override public void onStartup(ServletContext servletContext) throws ServletException { // Create the root appcontext AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext(); rootContext.register(RootConfig.class); // since we registered RootConfig instead of passing it to the constructor rootContext.refresh(); // Manage the lifecycle of the root appcontext servletContext.addListener(new ContextLoaderListener(rootContext)); servletContext.setInitParameter("defaultHtmlEscape", "true"); // now the config for the Dispatcher servlet AnnotationConfigWebApplicationContext mvcContext = new AnnotationConfigWebApplicationContext(); mvcContext.register(WebMvcConfig.class); // The main Spring MVC servlet. ServletRegistration.Dynamic appServlet = servletContext.addServlet( "appServlet", new DispatcherServlet(mvcContext)); appServlet.setLoadOnStartup(1); Set mappingConflicts = appServlet.addMapping("/"); if (!mappingConflicts.isEmpty()) { for (String s : mappingConflicts) { logger.error("Mapping conflict: " + s); } throw new IllegalStateException( "'appServlet' cannot be mapped to '/' under Tomcat versions <= 7.0.14"); } }
Arquivos de configuração Java
A classe Java RootConfig que especificamos no exemplo anterior precisa usar a anotação @Configuration. Essencialmente essa classe corresponde ao elemento <beans> dos arquivos de configuração do Spring. Os elementos <bean> agora são método com anotação @Bean que retornam uma instância do bean. O elemento <context:component-scan> passa a ser a anotação de classe @ComponentScan.
@Configuration @ComponentScan(basePackages = { "com.rockhoppertech.mvc.service", "com.rockhoppertech.mvc.repositories.internal" }) public class RootConfig { @Bean public SomeClass someClass() { return someInstance; } }
Filtros
Você pode criar qualquer Filtro de Servlets aqui. Nesse link você pode encontrar alguns filtros fornecidos pelo Spring.
No exemplo a seguir, configuramos o filtro CharacterEncodingFilter.
@Override public void onStartup(ServletContext servletContext) throws ServletException { ... FilterRegistration.Dynamic fr = servletContext.addFilter("encodingFilter", new CharacterEncodingFilter()); fr.setInitParameter("encoding", "UTF-8"); fr.setInitParameter("forceEncoding", "true"); fr.addMappingForUrlPatterns(null, true, "/*"); ... }
@Enable*
Os namespaces XML são substituídos pelas anotações de classe que começam com @Enable.
- @EnableWebMvc
- @EnableAsync
- @EnableScheduling
- @EnableLoadTimeWeaving
- @EnableTransactionManagement
Configuração para o Spring MVC
Aqui, criamos uma classe de configuração que contém a anotação @EnableWebMvc, que é definida por DelegatingWebMvcConfiguration. Além disso, você pode querer fazer um escaneamento de componentes por controllers.
Para personalizar os padrões, implemente a interface WebMvcConfigurer ou estenda a classe base WebMvcConfigurerAdapter. Qualquer método sobrecarregado que não retorne NULL será usado no lugar do método padrão.
@Configuration @EnableWebMvc // scan for controllers @ComponentScan(basePackages = { "com.rockhoppertech.mvc.web" }) public class WebMvcConfig extends WebMvcConfigurerAdapter { @Bean ViewResolver viewResolver() { ... } @Bean MessageSource messageSource() { ... } etc.
Agora, iremos mostrar três implementações básicas para classes de Configuração, que são o mínimo necessário para poder executar a sua aplicação sem a necessidade de arquivos XML.
WebAppInitializer.java
@Order(value=1) public class WebAppInitializer implements WebApplicationInitializer { public void onStartup(ServletContext arg0) throws ServletException { // Create the 'root' Spring application context AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext(); rootContext.register(WebAppConfig.class); // Manage the lifecycle of the root application context //container.addListener(new ContextLoaderListener(rootContext)); // Create the dispatcher servlet's Spring application context AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext(); dispatcherContext.register(DispatcherConfig.class); // Register and map the dispatcher servlet ServletRegistration.Dynamic dispatcher = arg0.addServlet("dispatcher", new DispatcherServlet(dispatcherContext)); dispatcher.setLoadOnStartup(1); dispatcher.addMapping("/"); } }
WebAppConfig.java
@EnableWebMvc @ComponentScan(value="spring.example") @Configuration public class WebAppConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/jquery-ui/**").addResourceLocations("/resources/jquery-ui/").setCachePeriod(31556926); registry.addResourceHandler("/bootstrap/**").addResourceLocations("/resources/bootstrap/").setCachePeriod(31556926); registry.addResourceHandler("/extras/**").addResourceLocations("/resources/extras/").setCachePeriod(31556926); } @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } }
DispatcherConfig.java
@Configuration @Import(WebAppConfig.class) public class DispatcherConfig { @Bean public ViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix("/WEB-INF/jsp/"); viewResolver.setSuffix(".jsp"); return viewResolver; } }