Explore Spring 4 Features

The recent Spring Version is 4, which is fully integrated with Java 8.

It has Got a lot of features in it bucket now.

In this Blog I am going to explore some of its features with some insight.

First thing that I will start with is: The Spring Java Config.

Recently I have been working on Spring Java Config, I have been trying to migrate one of my existing
Spring Projects (Which had Spring-Security 3.2, Aspects and other features) into a fully Java Based Configuration.
My objective is,there is going to be no XML configuration, even web.xml .

Spring Java config, though it is not a part of Spring 4. It has been introduced in Spring 3.2 .

I will be creating a project with no .xml files bearing any Spring based configuration.

All the configuration will be moved to Java.

In the cloud there are actually a lot of posts bearing a lot of useful information
regarding this Spring Java Based configuration and lot of them are really useful but
I really had hard time in configuring Java config in Spring with AbstractAnnotationConfigDispatcherServletInitializer,
when I am configuring Both Spring Security(Using AbstractSecurityWebApplicationInitializer ) and Spring MVC at the same time.

With AbstractAnnotationConfigDispatcherServletInitializer Only Spring MVC is working Fine
but somehow Spring Security is not in action So ultimately I had to resort to WebApplicationInitializer.
I found it quite handful and readable and easily configurable.
So, lets start with that.

The WebApplicationInitializer can be considered as synonymous to web.xml
The WebApplicationInitializer implementation that has been in effect is:
public class SpringApplicationInitializer implements WebApplicationInitializer 

{

	public void onStartup(ServletContext servletContext) throws ServletException {

		System.out.println(" ********* Application StartUP in Progress ********** ");


		AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
		context.register(SpringWebApplicationConfig.class);
		context.register(SpringSecurityApplicationConfig.class);
		//context.register(SpringCustomPermissionEvaluatorConfig.class);

		ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(context));
		dispatcher.setLoadOnStartup(1);
		dispatcher.addMapping("/config/*");

		/**
		 * Register Character Encoding Filter
		 */

		FilterRegistration.Dynamic characterEncodingFilter =  
				servletContext.addFilter("CharacterEncodingFilter", CharacterEncodingFilter.class); 
		characterEncodingFilter.setInitParameter("encoding", "UTF-8");
		characterEncodingFilter.setInitParameter("forceEncoding", "true");
		characterEncodingFilter.addMappingForUrlPatterns(null, false, "/*"); 

		//End of Character Encoding Filter

		/**
		 *  Register Spring security filter 
		 */

		FilterRegistration.Dynamic springSecurityFilterChain =  
				servletContext.addFilter("springSecurityFilterChain", DelegatingFilterProxy.class); 
		springSecurityFilterChain.addMappingForUrlPatterns(null, false, "/*"); 


		/**
		 * Register Http Custom Filter
		 */

		FilterRegistration.Dynamic customSpringSecurityFilter = servletContext.addFilter("securityFilter", SecurityFilter.class);
		customSpringSecurityFilter.addMappingForUrlPatterns(null, false, "/config/*"); 

		// Register Spring Social filter so that we can disconnect from providers 
		
		
		/*FilterRegistration.Dynamic hiddenHttpMethodFilter =  
         		servletContext.addFilter("hiddenHttpMethodFilter", HiddenHttpMethodFilter.class); 
         		hiddenHttpMethodFilter.addMappingForUrlPatterns(null, false, "/*"); 
		 */

		/**
		 * Registration of Context Loader Listener
		 */
		
		servletContext.addListener(new ContextLoaderListener(context));

		System.out.println(" ********* Application StartUP Completed ********** ");

	}



}
From the contents in the above Files it is Quite evident how all the congurations has been done.
Next comes the Configuration class for dispatcher-servlet.xml .

This configuration class implements WebMvcConfigurerAdapter. The usage of this adapter classes has been done for following cases:
1) Registration of Custom WebArgumentResolvers .
2) Registration of Formatters and Converters.
3) ConfigureContentNegotiation support.
4) Adding Interceptors. etc.
The WebMvcConfigurerAdapter class is:
public abstract class WebMvcConfigurerAdapter
  implements WebMvcConfigurer
{
  public void addFormatters(FormatterRegistry registry) {}
  
  public void configureMessageConverters(List> converters) {}
  
  public Validator getValidator()
  {
    return null;
  }
  
  public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {}
  
  public void configureAsyncSupport(AsyncSupportConfigurer configurer) {}
  
  public void addArgumentResolvers(List argumentResolvers) {}
  
  public void addReturnValueHandlers(List returnValueHandlers) {}
  
  public void configureHandlerExceptionResolvers(List exceptionResolvers) {}
  
  public MessageCodesResolver getMessageCodesResolver()
  {
    return null;
  }
  
  public void addInterceptors(InterceptorRegistry registry) {}
  
  public void addViewControllers(ViewControllerRegistry registry) {}
  
  public void addResourceHandlers(ResourceHandlerRegistry registry) {}
  
  public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {}
}

	
	
So, from the above class definition it is quite evident what actually is WebMvcConfigurerAdapter. Now the implementation class for WebMvcConfigurerAdapter is:
@Configuration
@Import({SpringCustomPermissionEvaluatorConfig.class})
@EnableWebMvc
@ComponentScan({"com.springjavaconfig.controller","com.springjavaconfig.service"})
@ImportResource("classpath:/aspect-config.xml")


public  class SpringWebApplicationConfig extends WebMvcConfigurerAdapter {

	
	@Override
	public void addArgumentResolvers(
			List argumentResolvers) {
		// TODO Auto-generated method stub
		argumentResolvers.add(dataInjectArgResolver());
		super.addArgumentResolvers(argumentResolvers);
	}
	
	
	@Override
	public void addFormatters(FormatterRegistry registry) {
		registry.addFormatter(addressFormatter());
		registry.addFormatterForFieldAnnotation(customDateAnnotationFormatterFactory());
		
	}
	
	@Bean
	public InternalResourceViewResolver viewResolver() {
		InternalResourceViewResolver viewResolver 
                          = new InternalResourceViewResolver();
		viewResolver.setViewClass(JstlView.class);
		viewResolver.setPrefix("/WEB-INF/views/");
		viewResolver.setSuffix(".jsp");
		return viewResolver;
	}

	
	@Bean
	public MultipartResolver multipartResolver()
	{
		org.springframework.web.multipart.commons.CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
		commonsMultipartResolver.setMaxUploadSize(100000);
		return commonsMultipartResolver;
	}
	
	

	
	@Bean
	public HandlerMethodArgumentResolver dataInjectArgResolver()
	{
		return new CustomHandlerArgumentResolver();
	}
	
	@Bean 
	public Formatter addressFormatter()
	{
		return new AddressFormatter();
	}
	
	@Bean
	public AnnotationFormatterFactory customDateAnnotationFormatterFactory()
	{
		return new CustomDateAnnotationFormatterFactory();
	}
	
	@Bean
	public DataInjectObject dataInjectObject()
	{
		DataInjectObject dataInjObj = new  DataInjectObject();
		dataInjObj.setId(999);
		dataInjObj.setName("KOOOOOLLLL");
		return dataInjObj;
	}
	
	
	
}

Before going into the details of WebMvcConfigurerAdapter implementation lets view the
java configuration file for spring-security.xml .
@Configuration
@EnableWebSecurity
public class SpringSecurityApplicationConfig extends WebSecurityConfigurerAdapter{
	
	@Autowired
	public void configure(AuthenticationManagerBuilder auth) throws Exception {
	  auth.inMemoryAuthentication().withUser("user1").password("user1").roles("USER");
	  
	}
	  
	@Override
	protected void configure(HttpSecurity http) throws Exception {
  
	  http.authorizeRequests()
      /*.antMatchers("/config/admin").hasRole("USER")*/
	  .antMatchers("/j_spring_security_check").permitAll()
	  .antMatchers("/**").hasRole("USER")
      .and()
      .formLogin();

	  http.csrf().disable();
	 /* http.csrf().csrfTokenRepository(customCSRFTokenRepository());
	  http.csrf().requireCsrfProtectionMatcher(customCSRFRequestMatcher());
	  */
	  
	  http.exceptionHandling().accessDeniedHandler(customAccessDeniedHandler());
	  
	}
	
	@Bean
	public CustomCSRFRequestMatcher customCSRFRequestMatcher()
	{
		return new CustomCSRFRequestMatcher();
	}
	
	@Bean
	public CustomAccessDeniedHandler customAccessDeniedHandler()
	{
		return new CustomAccessDeniedHandler();
	}
	
	@Bean
	public CustomCSRFTokenRepository customCSRFTokenRepository()
	{
		return new CustomCSRFTokenRepository();
	}


}
The annotation @EnableWebSecurity configures the Spring security configuration.
We add this annotation to the @Configuration class to have the have the Spring Security
configuration defined WebSecurityConfigurerAdapter base class and overriding individual methods.
This annotation automatically enables CSRF support. So we have disabled it using configure(HttpSecurity http). Lets explore all the features the last two configuration Files one be one.

First start with WebMvcConfigurerAdapter implementation.

The @Import({SpringCustomPermissionEvaluatorConfig.class}) imports the Configuration in SpringCustomPermissionEvaluatorConfig. The content of SpringCustomPermissionEvaluatorConfig is:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SpringCustomPermissionEvaluatorConfig extends
		GlobalMethodSecurityConfiguration {

	/*
	 * All the Method level secured Beans to be configured Here.
	 * 
	 */
	
	
	protected MethodSecurityExpressionHandler createExpressionHandler()
	  {
	    return expressionHandler();
	  }
	
	
	@Bean
	  protected MethodSecurityExpressionHandler expressionHandler() {
		  return defaultExpressionHandler();
	  }

	  @Autowired
	  public void registerGlobal(AuthenticationManagerBuilder auth) throws Exception {
	    auth
	        .inMemoryAuthentication()
	          .withUser("user1").password("user1").roles("USER");
	    }

	
	
	  
	  @Bean
	  public PriviledgeEvaluator priviledgeEvaluator()
	  {
		  return new CustomPriviledgeEvaluator();
	  }
	
	
	  @Bean
	  public CustomMethodSecurityExpressionHandler defaultExpressionHandler()
	  {
		  CustomMethodSecurityExpressionHandler methodSecurityExpressionHandler = new CustomMethodSecurityExpressionHandler();
		  methodSecurityExpressionHandler.setPermissionEvaluator(null);
		  methodSecurityExpressionHandler.setPriviledgeEvaluator(priviledgeEvaluator());
		  return methodSecurityExpressionHandler;
	  }
	  
    }

This configuration file corresponds to enabling global method security with custom Privilege Evaluator and Expression Handler.

By using @Import we can import some external configuration in the enclosing class.

@EnableWebMvc configures Spring MVC related configurations and is synonymous to

@ComponentScan({"com.springjavaconfig.controller","com.springjavaconfig.service"}) is similar to

@ImportResource("classpath:/aspect-config.xml") we can import configurations defined in xml in a Java config.

(This is another important and interesting feature we will experience its magic when we will explore Aspects configuration)
In my Next post I will continue from the point I am leaving here.
Till then Happy Coding.

Comments

  1. Is this article still relevant to Spring Security 4.1?

    ReplyDelete
  2. Thanks for this useful article. More than two years have passed, but I had the exact same problems as you had bringing Spring Security into action using an AbstractAnnotationConfigDispatcherServletInitializer...

    ReplyDelete

Post a Comment

Popular posts from this blog

Use of @Configurable annotation.

Spring WS - Part 5

Spring WS - Part 4