I have configured and working Spring-based REST application, but now I'd like to convert it to Spring-Boot.
My application uses Spring-Data-JPA on top of JPA datasource with Hibernate provider:
@Configuration
@EnableJpaRepositories("foo.bar.web.repository")
@EnableTransactionManagement
public class RepositoryConfig {
// properties ommited
@Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(className);
dataSource.setUrl(url);
dataSource.setUsername(userName);
dataSource.setPassword(password);
return dataSource;
}
@Bean
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factory.setPackagesToScan("foo.bar.web.domain");
factory.setDataSource(dataSource());
factory.setJpaPropertyMap(new HashMap<String, Object>() {{
put("hibernate.dialect", dialect);
put("hibernate.hbm2ddl.auto", hbm2ddl);
}});
factory.afterPropertiesSet();
return factory.getObject();
}
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
return transactionManager;
}
}
My REST endpoints implemented using SpringMVC with following configuration:
@Configuration
@EnableWebMvc
@ComponentScan("foo.bar.web.controller")
public class MvcConfig extends WebMvcConfigurerAdapter {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
@Bean
public MultipartResolver multipartResolver() {
return new CommonsMultipartResolver();
}
}
Web initializer:
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{
ApplicationConfig.class,
RepositoryConfig.class
};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{MvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
The problem is that I don't want to use Spring-Boot auto configuration because I'd like to reuse my existing configuration classes with minimal changes, but I cannot find correct way to do this. I tried to implement Spring-boot application class annotated with @SpringBootApplication
, but I'm not 100% sure that my config classes is used, because in this case I get java.lang.ClassCastException: org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean$$EnhancerBySpringCGLIB$$ba21071f cannot be cast to javax.persistence.EntityManagerFactory
.
Also I tried throw away @EnableAutoConfiguration annotation from application class and add TomcatEmbeddedServletContainerFactory
bean to my context manually, but in this case the embedded tomcat is not configured properly.
It would be great if somebody can give me a hint how to solve my problem. I believe that all I need to do is somehow replace my WebInitilizer with Spring-Boot config.
Yes, you can use Spring MVC with Spring Boot. To create and run a Spring MVC web application in spring boot, you need to add the spring-boot-starter dependency in your pom. xml file.
The application can also be called as Spring Boot Standalone application. To develop a non web application, your Application needs to implement CommandLineRunner interface along with its run method. This run method acts like a main of your application.
After spending a day in a research, I finally found a solition of my problem. First of all I had to modify my entityManagerFactory() and transactionManager() beans:
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factory.setPackagesToScan("foo.bar.web.domain");
factory.setDataSource(dataSource());
factory.setJpaPropertyMap(new HashMap<String, Object>() {{
put("hibernate.dialect", dialect);
put("hibernate.hbm2ddl.auto", hbm2ddl);
}});
factory.afterPropertiesSet();
return factory;
}
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
Also I totally removed my WebInitializer
class and removed @EnableWebMvc
annotation from MvcConfig
. In Spring-Boot it's not possible to have class extended from WebMvcConfigurerAdapter
in classpath because if Spring-Boot find it, all automatic configuration related to SpringMVC will be skipped. Here is the final version of my MvcConfig
class:
@Configuration
@ComponentScan("foo.bar.web.controller")
public class MvcConfig {
@Bean
public MultipartResolver multipartResolver() {
return new CommonsMultipartResolver();
}
}
I used the version of Spring-Boot application class which shown in doc:
@SpringBootApplication(exclude = MultipartAutoConfiguration.class)
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
Note, that in my case I had to exclude MultipartAutoConfiguration
from auto configuration because I've already have this feature configured in MvcConfig
. Bun it is also possible to leave it autoconfigured, but in this case I had to tune allowed file size in application.properties config file or add a MultipartConfigElement bean to my classpath.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With