Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert existing Spring application to Spring-Boot

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.

like image 433
Alex Avatar asked Mar 23 '15 13:03

Alex


People also ask

Can we convert Spring MVC to Spring Boot?

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.

Can we use Spring Boot for non Spring application?

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.


1 Answers

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 WebInitializerclass 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.

like image 120
Alex Avatar answered Oct 06 '22 05:10

Alex