Java

Configuring Spring without XML

By Max
February 13, 2014
0

Trying to refresh my knowledge about  the Spring framework, I’ve started to rewrite one of my standalone apps.

Usually the hardest part was the configuration, but as I have discovered, things have changed in the meantime!

So.. Here’s how I have ‘bootstrapped’ my application with just 3 java classes, no XML!

The magic happens due to changes in Servlet 3.0 when @WebServletContextListener annotation was added.

Basically this annotation, along with implementing the ServletContextListener interface provides you with the create/destroy events of the servlet context.


    @WebServletContextListener
    public class TestServletContextListener implements javax.servlet.ServletContextListener {
        ....
        public void contextInitialized(ServletContextEvent sce) {
            ....
        }
        public void contextDestroyed(ServletContextEvent sce) {
            ....
        }
    }

This is exactly what Spring does with it’s SpringServletContainerInitializer implementation, which looks after classes that implement the WebApplicationInitializer interface to delegate the creation of the context;

Enough with words, let’s see some code:


public class WebAppInitializer implements WebApplicationInitializer {
	@Override
	public void onStartup(ServletContext servletContext) throws ServletException {
		WebApplicationContext context = getContext();
		servletContext.addListener(new ContextLoaderListener(context));
		Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(context));
		servlet.addMapping("/*");
		servlet.setLoadOnStartup(1);
	}
	private WebApplicationContext getContext() {
		AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
		context.setConfigLocation("net.melikey.app.config"); //Path for the config classes
		return context;
	}
}

Basically we first created the Spring context and told him to look in the “net.melikey.config” package for additional configuration and then the dispacher servlet.

And now, that we have our servlet running, let’s configure the application!


@Configuration
@ComponentScan("net.melikey.app")
@EnableWebMvc
public class WebappConfig extends WebMvcConfigurerAdapter {
	@Bean
	public InternalResourceViewResolver setupViewResolver() {
		InternalResourceViewResolver resolver = new InternalResourceViewResolver();
		resolver.setPrefix("/WEB-INF/views/");
		resolver.setSuffix(".jsp");
		return resolver;
	}
	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		configurer.enable();
	}
}

And like that we enabled the WebMvc module in spring, we told Spring to look for annotated components in our app package, and we setup a basic ViewResolver. You may have noticed that i have extended WebMvcConfigurerAdapter, which is actually not mandatory but it provides a simple way to configure the default servlet handling behaviour.

And finally the database config:


@Configuration
@ComponentScan("net.melikey.app")
@PropertySource("classpath:db.properties")
@EnableTransactionManagement
@EnableScheduling
public class DatabaseConfig extends WebMvcConfigurerAdapter {
	@Autowired
	Environment env;
	@Override
	//You really need this if your entities reach the view with lazy initialized childs
	public void addInterceptors(InterceptorRegistry registry) {
		OpenEntityManagerInViewInterceptor interceptor = new OpenEntityManagerInViewInterceptor();
		interceptor.setEntityManagerFactory(entityManagerFactory().getObject());
		registry.addWebRequestInterceptor(interceptor);
	}
	// Set up dataSource to be used by Hibernate
	@Bean
	public DataSource getDataSource() {
		BasicDataSource ds = new BasicDataSource();
		ds.setUrl(env.getProperty("url"));
		ds.setDriverClassName(env.getProperty("driver"));
		ds.setUsername(env.getProperty("user"));
		ds.setPassword(env.getProperty("pass"));
		ds.setValidationQuery("select 1 from DUAL");
		return ds;
	}
	// Set up JPA and transactionManager
	@Bean
	public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
		LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
		emf.setDataSource(getDataSource());
		emf.setPackagesToScan("net.melikey.app.model");
		Map<String, Object> opts = emf.getJpaPropertyMap();
		opts.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
		opts.put("generateDdl","true");
		opts.put("hibernate.hbm2ddl.auto","update");
		// ... additional vendor configs
		opts.put("hibernate.show_sql","true");
		HibernateJpaVendorAdapter va = new HibernateJpaVendorAdapter();
		emf.setJpaVendorAdapter(va);
		return emf;
	}
	@Bean
	public PlatformTransactionManager transactionManager() {
		return new JpaTransactionManager(entityManagerFactory().getObject());
	}
}

This class created the Datasource (we used a property file to fetch the configuration), configured the EntityManagerFactory and the TrasactionManager.

And we are good to go! Nice and simple, the only downside appears to be that the application starts a bit slower than with the xml files.

Happy coding!

Comments: 0

Leave a Reply

Your email address will not be published. Required fields are marked *