10

I'm trying to use @Autowired annotation for a Service class in Spring Boot application, but it keeps throwing No qualifying bean of type exception. However, if I change the service class to a bean, then it works fine. This is my code:

package com.mypkg.domain;
@Service
public class GlobalPropertiesLoader {

    @Autowired
    private SampleService sampleService;        
}

package com.mypkg.service;
@Service
public class SampleService{

}

And this is my SpringBoot class:

package com.mypkg;

import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;

@SpringBootApplication
@EnableJpaRepositories
@Import(RepositoryRestMvcConfiguration.class)
@EnableTransactionManagement
public class TrackingService {
    private static final Logger LOGGER = LoggerFactory.getLogger(TrackingService.class);

    static AnnotationConfigApplicationContext context;

    public static void main(String[] args) throws Exception {
        SpringApplication.run(TrackingService.class, args);
        context = new AnnotationConfigApplicationContext();
        context.refresh();
        context.close();

    }

}

When I try to run this, I get the following exception:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mypkg.service.SampleService] 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)}

But when I remove the @Service annotation from the SampleService class, and add it as a bean in my AppConfig class as below, it works fine:

@Configuration
public class AppServiceConfig {

    public AppServiceConfig() {
    }

    @Bean(name="sampleService")
    public SampleService sampleService(){
        return new SampleService();
    }

}

The classes are in different packages. I am not using @ComponentScan. Instead, I'm using @SpringBootApplication which does that automatically. However, I tried with ComponentScan as well but that didn't help.

What am I doing wrong here?

drunkenfist
  • 2,958
  • 12
  • 39
  • 73
  • Can you show your `Application` class (the one with the `main` method)? – nicholas.hauschild Apr 22 '15 at 20:40
  • I have updated my question with the code for the main class. – drunkenfist Apr 22 '15 at 21:10
  • @drunkenfist Why are you closing the context? You know it will destroy all the beans rite. – minion Apr 23 '15 at 02:18
  • @drunkenfist I couldn't reproduce this issue at first, with pretty much the same code you posted. Then at some stage I realized when I added the `@Service` annotation and hit the quick import, I got two choices. So there was a _second_ `@Service` coming from some dependency I had in my pom, in this case `spring-boot-starter-jersey` but there could be others. It sounds like a long shot, but could you check the exact import for your `@Service`? – ci_ Apr 23 '15 at 08:29
  • I've typed in a similar example and it all works perfectly. As stated above can you check the fully qualified package name of the @Service annotation you are imported ? – PaulNUK Apr 24 '15 at 14:10
  • You should accept @EdduMelendez's answer as it solves your issue and explains in detail why you should do it the way he suggested. – milosmns Jan 23 '18 at 22:35

1 Answers1

18

You are using two ways to build a Spring's bean. You just need to use one of them.

  1. @Service over the POJO

     @Service
     public class SampleService
    
  2. @Bean in the configuration class which must be annotated with @Configuration

     @Bean
     public SampleService sampleService(){
         return new SampleService();
     }
    

@Autowired is resolved by class type then @Bean(name="sampleService") is not needed is you have only one bean with that class type.

EDIT 01

package com.example

@SpringBootApplication
public class Application implements CommandLineRunner {

    public static void main(String... args) {
        SpringApplication.run(Application.class);
    }

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private UserService userService;

    @Override
    public void run(String... strings) throws Exception {
        System.out.println("repo " + userRepository);
        System.out.println("serv " + userService);
    }
}

package com.example.config

@Configuration
public class AppConfig {

    @Bean
    public UserRepository userRepository() {
        System.out.println("repo from bean");
        return new UserRepository();
    }

    @Bean
    public UserService userService() {
        System.out.println("ser from bean");
        return new UserService();
    }
}

package com.example.repository

@Service
public class UserRepository {

    @PostConstruct
    public void init() {
        System.out.println("repo from @service");
    }
}

package com.example.service

@Service
public class UserService {

    @PostConstruct
    public void init() {
        System.out.println("service from @service");
    }

}

Using this code you can comment the AppConfig class and then you will see how UserRepository and UserService are autowired. After that comment @Service in each class and un-comment AppConfig and classes will be autowired too.

Max von Hippel
  • 2,856
  • 3
  • 29
  • 46
Eddú Meléndez
  • 6,107
  • 1
  • 26
  • 35
  • I think you got my question wrong. I'm using only one of the methods. When I annotate it with `@Service` over the POJO, it fails. But when I use `@Bean` in my configuration class, it works. I want to know why the `@Service` way fails. – drunkenfist Apr 22 '15 at 21:19
  • I have updated the answer. static AnnotationConfigApplicationContext context; is used? spring boot manage the lifecycle so not sure why you are using context.refresh() and context.close() – Eddú Meléndez Apr 22 '15 at 21:46
  • For me the `@Service` method is not working. It is only fetching if it is declared as a `@Bean`. – drunkenfist Apr 23 '15 at 01:40
  • I am using spring-boot 1.2.3.RELEASE. Which version are you using? Are you using my example or a mix of both? – Eddú Meléndez Apr 23 '15 at 01:43
  • I have the same issue, I am using spring-boot 1.4.2.RELEASE. It works when I use @Bean(name="sampleService") but does not work when I use only @Bean – Tomasz Janisiewicz Dec 20 '16 at 12:48