Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot And Multi-Module Maven Projects

I am struggling to get a multi-module Spring Boot Maven project setup correctly. Are there any example projects that I can reference? Currently I have my project structured like this.

Data Module: Basically my data layer. Is contains my POJOs and my database repo interfaces (PagingAndSortingRepository). This module will be a dependency of the other modules in the project. Currently I have placed a Config class in the module that looks like this

public class Config {

  @Configuration
  @Profile("cloud")
  static class CloudConfiguration extends AbstractCloudConfig {
    @Bean
    public DataSource dataSource() {
      return connectionFactory().dataSource("session-questions-sql", new DataSourceConfig(new PoolConfig(4, 4), new ConnectionConfig("")));
    }

  }


  @Configuration
  @Profile("default")
  static class LocalConfiguration {
  }
}

I figured this configuration would be common between the other two modules so it belonged in the data module.

Text Module: The is a very simple module, it contains a single REST API controller that will be called when a text message is sent to a certain phone number. It stores the text message in the DB and uses one of the repo interfaces from the cdata module to do so. This module is being built as an executable jar file and contains a class which implements EmbeddedServletContainerCustomizer.

@Configuration
@ComponentScan
@EnableAutoConfiguration
@EnableJpaRepositories
public class App implements EmbeddedServletContainerCustomizer {

  public static void main(String[] args) throws Exception {
      SpringApplication.run(App.class, args);
  }

  @Override
  public void customize(ConfigurableEmbeddedServletContainer container) {
    //Enabled UTF-8 as the default character encoding for static HTML resources.
    //If you would like to disable this comment out the 3 lines below or change
    //the encoding to whatever you would like.
    MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT);
    mappings.add("html", "text/html;charset=utf-8");
    container.setMimeMappings(mappings );
  }
}

When I run the jar I get errors saying that rest controller class cannot autowire beans from my data module. I saw some posts saying that you should add the package name to the @ComponentScan annotation. For example

@ComponentScan("com.example.data")

Doing this will let the embedded tomcat server start, but I think adding that package alone causes Spring to not find my REST controller in my text module because I am getting 404s when hitting the API. So I added my text package as well

@ComponentScan({"com.example.data","com.example.text"})

However this brings me back to the same error, Spring cannot find my beans from the data module to autowire to my REST controller.

java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:53)
    at java.lang.Thread.run(Thread.java:744)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'twilioController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.example.data.controllers.QuestionRepo com.example.questions.text.controller.TwilioController.questionRepo; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.example.data.controllers.QuestionRepo] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:292)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:703)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:120)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:648)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:909)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:898)
    at com.example.text.App.main(App.java:34)
    ... 6 more
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.example.data.controllers.QuestionRepo com.example.text.controller.TwilioController.questionRepo; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.example.data.controllers.QuestionRepo] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:508)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289)
    ... 22 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.example.data.controllers.QuestionRepo] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1103)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:963)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480)
    ... 24 more

Does anyone have any pointers on how to do this properly?

like image 820
Ryan Baxter Avatar asked Aug 01 '14 00:08

Ryan Baxter


People also ask

What is the use of multi-module project in spring boot?

A Spring Boot project that contains nested maven projects is called the multi-module project. In the multi-module project, the parent project works as a container for base maven configurations. In other words, a multi-module project is built from a parent pom that manages a group of submodules.

What is multi-module project in Maven?

A multi-module project is built from an aggregator POM that manages a group of submodules. In most cases, the aggregator is located in the project's root directory and must have packaging of type pom. The submodules are regular Maven projects, and they can be built separately or through the aggregator POM.

Does Maven support multi project build?

As seen in the introduction to the POM, Maven supports project aggregation in addition to project inheritance. This section outlines how Maven processes projects with multiple modules, and how you can work with them more effectively.


1 Answers

The repositories are scanned automatically from the package of your application class (the one annotated with @EnableAutoConfiguration). If that default does not suit you, you can easily fallback on @EnableJpaRepositories with the relevant packages.

I can see com.example.data and com.example.text. I guess you might have a project specific package as com.example is probably too broad. So one way to fix that would be to put your application in com.example (or whatever the root package of your app is).

Check also the doc

like image 106
Stephane Nicoll Avatar answered Oct 01 '22 23:10

Stephane Nicoll