Spring MVC annotation based Configuration for multimodule project
Asked Answered
H

2

14

I implemented two maven based independent web project implemented using Spring MVC, hibernate and Jax-RS.

But my requirement changed and now I need to combine both the project as a sub project into another project which is our parent project. So I use maven multimodule configuration.

Project 1: Parent project

<packaging>pom</packaging>
<modules>
    <module>../child1</module>
    <module>../child2</module>
</modules>

Child 1:

<packaging>jar</packaging>
<parent>
    <groupId>com.xyz.alpha</groupId>
    <artifactId>parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <relativePath>../parent</relativePath>
</parent>

Child 2:

<packaging>jar</packaging>

<dependency>
        <groupId>com.xyz.alpha</groupId>
        <artifactId>child1</artifactId>
        <version>2.0.2</version>
</dependency>
<parent>
    <groupId>com.xyz.alpha</groupId>
    <artifactId>parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <relativePath>../parent</relativePath>
</parent>

But I need to configure project in Java in such a way that it will scan components of the parent and both the child project and execute project. Currently I have separate configuration for each project as:

AppIntializer.java

public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { AppConfig.class };
    }
 
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return null;
    }
 
    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

AppConfig.java

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.x.y")
public class AppConfig extends WebMvcConfigurerAdapter{
     
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }
    
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
    
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
      
    }
}

HibernateConfiguration.java

@Configuration
@EnableTransactionManagement
@ComponentScan({ "com.x.y.configuration" })
@PropertySource(value = { "classpath:application.properties" })
public class HibernateConfiguration {
 
    @Autowired
    private Environment environment;
 
    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan(new String[] { "com.x.y.model" });
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
     }
     
    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
        dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
        dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
        dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
        return dataSource;
    }
     
    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
        properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
        properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("hibernate.hbm2ddl.auto"));
        return properties;        
    }
     
    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory s) {
       HibernateTransactionManager txManager = new HibernateTransactionManager();
       txManager.setSessionFactory(s);
       return txManager;
    }
}
Hourigan answered 1/7, 2016 at 11:5 Comment(3)
Spring has a number of official tutorials followed by multimodule source code. Based on this, each module has it's own configuration. The parent one is child of spring-boot-starter-parent. So, you can build it by single action but you still have to run each one manually. GitHub ref>>Ushijima
The packaging type you are looking for is EAR, that will allow you to build and execute the whole project by single action and resolve crossmodule dependencies as well.Ushijima
I don't understand, why do you want to scan the parent? The parent is the root POM here, which isn't supposed to contain Java sources. What JAR do you want to launch and how?Highminded
D
1

The best configuration for this is to use something called Maven Reactor project. Good is that it seems you are using it.

Firstly, your parent should not have any spring component, it should by composed of POM only (BOM - bill of materials) to define only dependency versions and maybe some plugins to be shared accross submodules. These dependencies should by in DependencyManagement tag and plugins should be in PluginManagement but it really depends on your need to enforce or not some behaviour in submodules.

If you have parent POM and two submodules and you want scan both submodules for Spring components then I would personally create third submodule with the same parent POM and both submodules as dependencies. In your main class, I would simply define @SpringBootApplication with custom @ComponentScan which has an argument defining packages to scan. You can fill that argument with package prefixes of both modules and you are good to go.

Other way is to create totally independent project which depends on those submodules. This demands however that you have those submodules installed in your local maven repository. In the first solution, you must not have these installed in your repo if you always build entire project at once.

Deangelo answered 18/5, 2020 at 7:1 Comment(0)
A
0

The second module if its spring Mvc or any webapplication module, then it should have a dependency of first module. Drafting an sample structure below, Hope this helps:

child1 pom:

<parent>
    <groupId>com.xyz.alpha</groupId>
    <artifactId>parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>child1-app</artifactId>
<packaging>jar</packaging>
<build>
</build>
<dependencies>
</dependencies>

child2 pom:

<parent>
    <groupId>com.xyz.alpha</groupId>
    <artifactId>parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>child2-Webapp</artifactId>
<packaging>war</packaging>
<build>
</build>
<dependencies>
    <dependency>
        <groupId>org.sonatype.mavenbook.multi</groupId>
        <artifactId>child1-app</artifactId>
        <version>1.0</version>
      </dependency>
</dependencies>

Also, you can wire up depending Hibernate configuration in the app configuration like:

@Import({HibernateConfiguration.class})
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.x.y")
public class AppConfig extends WebMvcConfigurerAdapter{
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }
}
Aliciaalick answered 4/7, 2016 at 20:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.