Home > front end >  How does spring identity/autowires beans when they have multiple interfaces?
How does spring identity/autowires beans when they have multiple interfaces?

Time:10-28

Suppose I have interface foo and bar, then have multiple classes that implements both of them:

public interface InterfaceFoo{
int getFoo()
}

public interface InterfaceBar{
int getBar()
}

public class FooBarOne implements InterfaceFoo, InterfaceBar{

public int getFoo() { ... } 
public int getBar() { ... }
}


public class FooBarTwo implements InterfaceFoo, InterfaceBar{

public int getFoo() { ... }
public int getBar() { ... }
} 

Then I create beans for both of these classes:

@Configuration
@ComponentScan
public class Config {

@Bean
fooBarOne getFooBarOne() { return new FooBarOne(); }

@Bean
fooBarTwo getFooBarTwo() { return new FooBarTwo();}  
}

Finally another bean which @Autowries in a list of all implementations of foo

@Configuration
@ComponentScan
public class FooConfig {

    @Bean
    @Autowired
    public List<InterfaceFoo> fooFetcher(List<<InterfaceFoo>> listFoos) {
        return listFoos;
    }
}

My question is, how does Spring identify/autowire beans when they have multiple implementations of an interface? The above pseudo code seems to work, however, if I change the return type of the bean from the concrete class to an ibar, it is not picked up by the autowire:

@Configuration
@ComponentScan
public class Config {

@Bean
InterfaceBar getFooBarOne() { return new FooBarOne(); }

@Bean
InterfaceBar getFooBarTwo() { return new FooBarOne(); }  
}

From the example above, spring does not pick these beans up when autowiring for implementations of ifoo. Switching the return type to ifoo works, which implies to me that spring looks at the return type of the bean rather than that of the returned object? Even though fooBarOne and fooBarTwo both implement foo and bar, do I need to return either the concrete class or interface ifoo if I want the autowire for List to pick it up?

CodePudding user response:

Spring's default autowire mode is by type, so it makes sense that if you create two beans of type iBar, they will not be autowired as iFoo, even though the concrete classes are also instances of iFoo. Spring does not know about all of the interfaces that a class implements, it only knows of the type of beans that were created in its context.

When you attempt to autowire List<<iFoo>>, Spring will look in its context for all the beans of type iFoo to inject, which you have none.

Also, please read up on the Java naming conventions, you probably want your interfaces to just be Foo and Bar https://www.oracle.com/java/technologies/javase/codeconventions-namingconventions.html

CodePudding user response:

When declaring beans with @Bean-annotated methods, Spring assigns return type of the method as bean type, i.e. saves class name (ibar.class.getName()) to BeanDefinition, along with other object metadata. From now, spring does not care whether your class implements other interfaces, it just has your object and assigned type.

When autowiring, spring filters beans that match bean type and name constrains, provided by type of bean to be constructed

In this case, when trying to create List<iFoo>, spring can hook beans with type iFoo or types extending/implementing it, but not ibar, because ibar is not related to iFoo

If you need just List<iFoo>, and you are not using fooBarOne/fooBarTwo beans, practically it does not matter if you declare bean as iFoo or fooBarOne. But in general, you should prefer using interfaces over implementations, it will help to keep Dependency Inversion in your code.

And, always name your classes with capital letter.

  • Related