Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have a module/jar that I've created and am using as a util library. I created a service in there like so:

@Service
public class PermissionsService { ... }

... where this resides in a package here: com.inin.architect.permissions and in my main application, I'm referencing/loading this jar (i.e. set as a dependency in the maven POM.xml file for the app) like so:

<dependency>
        <groupId>com.inin.architect</groupId>
        <artifactId>permissions</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>

and within the application I want to use that service like:

@Autowired
PermissionsService permissions

In the application's spring setup, I've got this:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.inin.generator", "com.inin.architect.permissions" })
public class WebConfig extends WebMvcConfigurerAdapter implements ServletContextAware { }

However when I run my application under tomcat, it complains that there isn't a bean for the PermissionsService: "org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ..."

So, how can I bring over the bean from the lib into my application? Surely there's a way. Do you have to set the library up as a full blown spring MVC application so that this can work? i.e. do you have to have @Configuration and @ComponentScan setup in the lib as well?

like image 474
BrianP Avatar asked Apr 10 '15 21:04

BrianP


4 Answers

You have to scan at least the package containing the class you want to inject. For example, with Spring 4 annotation:

@Configuration
@ComponentScan("com.package.where.my.class.is")
class Config {
...
}

It is the same principle for XML configuration.

like image 164
Benjamin Boutier Avatar answered Oct 21 '22 17:10

Benjamin Boutier


Just a note on this, but you could decouple your dependency from spring. In your @Configuration class create

@Bean public PermissionsService  permissionsService(){
   return new PermissionsService()
}

This will also allow it to be injected. Not that you have to remove your spring annotation, just an option making it potentially usable outside of spring.

like image 43
Maleck13 Avatar answered Oct 21 '22 17:10

Maleck13


Ok - i had exactly the same problem - i wanted to autowire a mongo db repository interface from an external jar.

  • I could autowire every bean from that jar with using

    @SpringBootApplication(scanBasePackages = {"com.myrootpackage"})

  • However - autowiring the interface always failed with "Could not find blablabla..."

But the interface was in the same package as the beans i could import. It turned out that searching for the mongo db interfaces is NOT taking the scanBasePackages from the @SpringBootApplication into consideration!

It has to be explicitly configured via

@EnableMongoRepositories(basePackages = {"com.myrootpackage"})

Or you could move the main class "up" so the default searching works also for the mongo interfaces. So i understood the problem and found a solution. But i am still a bit unhappy because i need to configure the same lookup path twice. I find it stupid honestly.

like image 10
Holgi P Avatar answered Oct 21 '22 17:10

Holgi P


I faced the same issue while scanning other classes from other project dependencies, The scanning solution depends on the type of classes you need to scan as follows:

if they are normal @Component, @Service annotations use

@ComponentScan({"com.mypackge1","com.mypackage2"})

If the type of classes are domain objects based on entities use

@EntityScan("com.mypackge1.domain")

If JPA repository classes

@EnableJpaRepositories(basePackages = {"com.mypackage.repository"})

If Redis repository classes use

@EnableRedisRepositories(basePackages = {"com.mypackage.repository"})

Same for Mongo, etc.

like image 4
Hany Sakr Avatar answered Oct 21 '22 17:10

Hany Sakr