9

I have a Spring Boot project and I can't get components from an external jar to be autowired. When I try to, I got a org.springframework.beans.factory.NoSuchBeanDefinitionException saying that can't find a bean with that name available.

I tried some solutions found in similar questions, like these ones:

How to autowire @service from external Jar in Spring

Spring Boot @autowired does not work, classes in different package

How can I @Autowire a spring bean that was created from an external jar?

..but still can't managed it to work.

Here is an example of what I'm trying to accomplish:

enter image description here

Here is boot class in the Spring Boot project spring-project-example

package com.springdi.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;

import com.dependency.example.DependencyBasePackageClass;
import com.dependency.example.somepackage.SomeBean;

@SpringBootApplication
@ComponentScan(basePackages = {"com.springdi.example"}, basePackageClasses = DependencyBasePackageClass.class)
public class SpringProjectExampleApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringProjectExampleApplication.class, args);

        String beanName = SomeBean.class.getName();
        System.out.printf("%s can be autowired: %s\n", beanName, String.valueOf(context.containsBean(beanName)).toUpperCase());
    }
}

It's just a simple Spring Boot project checking if it is possible to autowire a component present in the dependency jar.

Here is the component in the jar (dependency-example-1.0.0.jar)

package com.dependency.example.somepackage;

import org.springframework.stereotype.Component;

@Component
public class SomeBean {

    public void someMethod() {
        System.out.println("Some process...");
    }
}

And here is the base package class of this same jar

package com.dependency.example;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * Just a class to serve as the root for component
 * scanning in "com.dependency.example" and its sub-packages
 */
@Configuration
@ComponentScan
public class DependencyBasePackageClass {

}

I've already tried @Import(DependencyBasePackageClass.class) in SpringProjectExampleApplication and @ComponentScan with basePackages and basePackageClasses, but no success.

I also tried using @SpringBootApplication(scanBasePackageClasses = {SpringProjectExampleApplication.class, DependencyBasePackageClass.class})

and the not type safe @SpringBootApplication(scanBasePackages = {"com.springdi.example", "com.dependency.example"}).

@Configuration @ComponentScan({"com.dependency.example"}) also fails, context.containsBean("com.dependency.example.somepackage.SomeBean") still returns false.

This jar is included in classpath and in the pom.xml as a dependency

<dependencies>
    <!-- other dependencies -->

    <dependency>
        <groupId>com.rbaggio</groupId>
        <artifactId>dependency-example</artifactId>
        <version>1.0.0</version>
        <scope>system</scope>
        <systemPath>${basedir}/lib/dependency-example-1.0.0.jar</systemPath>
    </dependency>
</dependencies>

Could it be the location of the jar, the way it is included or some extra configuration needed?

I'd appreciate any help! Thanks in advance.

Renan Baggio
  • 411
  • 1
  • 4
  • 11
  • 1
    `@ComponentScan` is hindering in finding that dependent bean. Do `@Import` or create a bean that returns the dependent project. – Faraz Jun 14 '19 at 00:51

1 Answers1

20

Okey some basic things, you have mixed up your packages a bit.

@SpringBootApplication will scan all classes in packages below the class this is annotated on. This annotation is an alias for @EnableAutoConfiguration, @Configuration and @ComponentScan means that @ComponentScan(basePackages = {"com.springdi.example"}, basePackageClasses = DependencyBasePackageClass.class) is not needed.

com.springdi.example     // class with @SpringBootApplication annotation
         |
         |
         |
com.springdi.example.*    // Will find all @Service, @Component, @Configuration
                          // in subpackages below the @SpringBootApplication 
                          // annotation

You can read more about the annotation here SpringBootApplication

Since your other annotated classes are NOT in the same package structure as the @SpringBootApplication you need to define all the places you want to scan for annotations.

@SpringBootApplication(scanBasePackages = {"com.springdi.example", "com.dependency.example"})

will probably include all the packages that you want to scan through.

Toerktumlare
  • 12,548
  • 3
  • 35
  • 54
  • 1
    I've tried this too, but no success... applicationContext.containsBean("com.dependency.example.somepackage.SomeBean") still returns false. I think the problem can be the way the jar is included in classpath or some missing annotation. Anyway, thank you. – Renan Baggio Jun 14 '19 at 01:13
  • 1
    you need to remove the second `@ComponentScan` in your DependencyBasePackageClass – Toerktumlare Jun 14 '19 at 01:57
  • Still doesn't work.. but if I give a name to SomeBean like @Component("someBean") somehow it works. It seems that I'll have to name every single bean in the included jars in order to make use of them with @Autowired – Renan Baggio Jun 14 '19 at 02:25
  • if you skip the package name when asking for the bean. applicationContext.containsBean("someBean") – Toerktumlare Jun 14 '19 at 02:37
  • 1
    you can use this to list all loaded beans https://stackoverflow.com/questions/33348937/print-all-the-spring-beans-that-are-loaded-spring-boot – Toerktumlare Jun 14 '19 at 02:39
  • 1
    It also works. And listing all loaded beans will be helpful. Thank you Thomas! (I'll be accepting your answer above) – Renan Baggio Jun 14 '19 at 02:47
  • perfect, this is what I needed, I do have to ask the question is a bad practice design wise to have beans in external libraries? – Snedden27 May 20 '20 at 14:16
  • @Snedden27 nothing mentioned from the spring boot team. But usually if you want to write a library that gets loaded with spring boot is to write a "spring boot starter" that will load in the needed beans during some specific conditions – Toerktumlare May 20 '20 at 18:10