Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot multi module Maven project @Autowired does not work

This is really strange. I started my Spring Boot project as a single maven project and all worked perfectly. Basically it is a Spring MVC app with security and mail.

Then when I saw that some components like service, repository, model will be reused by a standalone application, I decided to split the maven project into sub-modules.

Suddenly no autowiring started to work. After some investigation I found out that I need to explicitly put the packages in my Application of the standalone app:

@ComponentScan (basePackages={"service"})
@EnableJpaRepositories(basePackages={"repository"})
@EnableAutoConfiguration
@EntityScan(basePackages={"model"})

OK, after that my custom classes started getting autowired. But another problem appeared:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.mail.javamail.JavaMailSender service.impl.UserServiceImpl.mailSender; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.mail.javamail.JavaMailSender] 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:334)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1210)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)
    at com.me.newsaggregator.rsscollector.RsscollectorApplication.main(RsscollectorApplication.java:18)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.mail.javamail.JavaMailSender service.impl.UserServiceImpl.mailSender; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.mail.javamail.JavaMailSender] 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:561)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
    ... 16 common frames omitted
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.mail.javamail.JavaMailSender] 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:1301)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1047)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:533)

So it looks like standard packages are not getting autowired anymore. pom.xml of this standalone app:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
    <dependency>
        <groupId>com.sun.mail</groupId>
        <artifactId>javax.mail</artifactId>
        <version>1.5.4</version>
    </dependency>

Please help.

like image 615
ACV Avatar asked Sep 03 '15 19:09

ACV


People also ask

Why Autowired is not working?

When @Autowired doesn't work. There are several reasons @Autowired might not work. When a new instance is created not by Spring but by for example manually calling a constructor, the instance of the class will not be registered in the Spring context and thus not available for dependency injection.

How do I run a 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.


2 Answers

A very easy way to fix this: Set the

scanBasePackages

to your root package, to me is :org.umasuo, so that the spring can scan all the class you need to scan.

@SpringBootApplication(scanBasePackages = "you.root.package")
public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
}

Actually, we can have a look at how the spring do the package scan, so that we can know it well.

like image 54
Bruce Avatar answered Sep 24 '22 06:09

Bruce


Finally I got it working. Besides adding the above mentioned annotations I had to:

  1. Add the class MailConfiguration into the package where the standalone application resided (com.my.newsaggregator.rsscollector)
  2. Add the standalone application base package (com.my.newsaggregator.rsscollector) to @ComponentScan

Here is what I mean:

package com.my.newsaggregator.rsscollector;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.orm.jpa.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@ComponentScan (basePackages={"service","com.my.newsaggregator.rsscollector"})
@EnableJpaRepositories(basePackages={"repository"})
@EnableAutoConfiguration
@EntityScan(basePackages={"model"})

public class RsscollectorApplication {

    public static void main(String[] args) {
        SpringApplication.run(RsscollectorApplication.class, "--debug").close();
        System.out.println("done");

    }
}

By the way, the same will happen to your JUnit tests. In my case I got an error about Spring Security not being autowired.

like image 23
ACV Avatar answered Sep 22 '22 06:09

ACV