12

I am using @ComponentScan and @Component to define my spring beans. What I would like is to declare one of these beans to be autowire-candidate=false.

This could be done with this attribute in xml. Isn't there the equivalent in annotations?

The reason I want this is because I have 2 implementations of the same interface and I don't want to use @Qualifier.

EDIT: Using @Primary is a valid work-around, but autowire-candidate seems to me like a useful feature with its own semantics.

Thanks

Sergey Bespalov
  • 1,746
  • 1
  • 12
  • 29
Nazaret K.
  • 3,409
  • 6
  • 22
  • 31

5 Answers5

9

Looks like Spring refused autowire-candidate=false concept and it no longer supported. There is no analogue with annotations, so @Primary is the best work-around as you noticed.

Another way is to use custom org.springframework.beans.factory.support.AutowireCandidateResolver, which is used in DefaultListableBeanFactory, with logic that exclude undesirable beans from autowire candidates. In such case, the technology will be similar to that used for autowire-candidate=false in SimpleAutowireCandidateResolver.

Sergey Bespalov
  • 1,746
  • 1
  • 12
  • 29
8

Since Spring 5.1 , you can configure autowire-candidate in @Bean through autowireCandidate attribute:

@Bean(autowireCandidate = false)
public FooBean foo() {
      return newFooBean();
}
Ken Chan
  • 84,777
  • 26
  • 143
  • 172
2

You can also use the bean accessor to tune it's visibiltiy.

see Bean visibility

@Configuration
public abstract class VisibilityConfiguration {

    @Bean
    public Bean publicBean() {
        Bean bean = new Bean();
        bean.setDependency(hiddenBean());
        return bean;
    }

    @Bean
    protected Bean hiddenBean() {
        return new Bean("protected bean");
    }
}

You can then @Autowire the Bean class and it will autowire the public bean (without complaining about multiple matching beans)

As a class' definition (unless embedded) does not allow private / protected accessor the work around would be to use an @Configuration class that would instantiate all the beans an publish the public beans while hiding the private/protected (instead of directly annotating the classes @Component \ @Service)

Also package-protected accessor may worth a try to hide @Component annotated classes. I don't know if that may work.

Ghurdyl
  • 1,077
  • 1
  • 12
  • 18
  • Are you sure the Bean Visibility is implemented in Spring? – Whimusical Jan 31 '20 at 12:12
  • 1
    @Whimusical yes, I created a class as defined in my answert and Autowired an attribute of type "Bean" in another spring component and spring injected the 'public' Bean. – Ghurdyl Feb 04 '20 at 08:49
  • I was thinking of https://github.com/spring-projects/spring-framework/issues/11829 and the fact that most documentation I see on the net regarding that feature is on Spring 1.0, but they must be outdated – Whimusical Feb 04 '20 at 14:32
0

We can do this by using the @Qualifier annotations with name mentioned in the @Component annotations Bean classes -

@Component("fooFormatter")
public class FooFormatter implements Formatter {
    public String format() {
        return "foo";
    }
}
@Component("barFormatter")
public class BarFormatter implements Formatter {
    public String format() {
        return "bar";
    }
}

Injecting bean in service class -

public class FooService {
    @Autowired
    @Qualifier("fooFormatter")
    private Formatter formatter;
}

For more details please refer - https://www.baeldung.com/spring-autowire#disambiguation. Above example taken from this link.

A D
  • 466
  • 2
  • 8
0

Use Object type to create the Bean you want to hide

@Configuration
public class MyConfiguration {

    @Bean
    public MyInterface publicBean() {
        return new MyInterfaceImpl1();
    }

    @Bean
    protected Object hiddenBean() {
       return new MyInterfaceImpl2();
    }
}

Then you can use a simple @Autowired to inject publicBean

@Component
public class MyService {

    @Autowired
    MyInterface publicBean;

}

And even if you wanted to inject also hiddenBean in other place, then you could using @Qualifier

@Component
public class OtherComponent {

    @Autowired
    @Qualifier("hiddenBean")
    MyInterface hiddenBean;

}
cfillol
  • 540
  • 4
  • 8