简体   繁体   中英

Spring MVC annotation based Configuration for multimodule project

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;
    }
}

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/");
    }
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM