Spring Bean Wiring

I am learning the basics of Spring and I am going through Beans / wiring right now. This question may not make sense, this is what I am thinking after reading / trying out some examples from Spring book at Action Craig Walls. Let's say there is this interface.

public interface CompactDisc {
    void play()
}

      

And I have two classes that implement this interface.

public class HybridTheory implements CompactDisc { }
public class Meteora implements CompactDisc { }

      

My config class uses component scanning and creates beans from these two classes. Now if I had a test class that has a CD instance and is connected using autodevice

public class myTest {
    @Autowired
    private CompactDisc cd;
}  

      

would the problem be correct? My question is, how do you wire it up so that it uses one bean on top of the other? Or is this not a real situation / should I be creating a property of a specific class and not an interface? I guess I'm just having difficulty wrapping my head around the wiring.

+3


source to share


2 answers


A simple and graceful approach is to use by type whenever possible. If it is not , you can use the byName method.

One way to use this is to call beans manually - then the bean names won't be different after the class name is changed. Note that naming beans should only be used if you have multiple implementations of the same type, otherwise no naming is required. In the example below, the naming is part of the annotation eg @Component("hybridTheory")

. This means you can change the class name HybridTheory

to whatever you want and the bean name will remain the same HybridTheory

.

When you type something by name, you can use annotation @Qualifier

to indicate which named bean you want. I personally prefer it @Resource

since you can use it @Qualifier

in constructors (I prefer to inject the injectable constructor with set and margin).



You should NOT inject specific types - that's what dependency injection is. Someone else (i.e. Spring) will handle object creation for you;)

public interface CompactDisc {
    void play();
}

@Component
class CompactDiscPlayer {
    @Autowired
    CompactDiscPlayer(@Qualifier("hybridTheory") final CompactDisc compactDisc) {
        // The bean of type HybridTheory will be used
        compactDisc.play();
    }
}

@Component("hybridTheory")
class HybridTheory implements CompactDisc {
    public void play() {
        System.out.println(getClass().getSimpleName());
    }
}

@Component("meteora")
class Meteora implements CompactDisc {
    public void play() {
        System.out.println(getClass().getSimpleName());
    }
}

      

The Spring docs describe various options here .

+2


source


Whenever you are faced with a situation where you have more than one implementing the same interface, there are several approaches you can take.

1. Use @mark annotation

If you are using class scanning your classes might look like this:

@Component
public class HybridTheory implements CompactDisc { }

@Component
public class Meteora implements CompactDisc { }

      

Each Spring bean gets an ID assigned by the container and by default its class name starts with a lower letter. In the case of these two components, which will be:

  • hybridTheory

  • meteora

You can also choose your own name, to pass parameters name

to @Component annotation, such as: @Component("myFavLinkinParkAlbum")

.

Then whenever you autowire a CompactDisc

bean, you can pass the @Qualifier annotation and tell Spring which bean you mean exactly.

@Service
class Player {
    private final CompactDisc compactDisc;

    // note that starting from Spring 4.3 
    // you can omit @Autowired annotation from constructor
    Player(@Qualifier("hybridTheory") CompactDisc compactDisc) {
        this.compactDisc = compactDisc;
    }
}

      



2. Mark one of your beans as @Primary

If at most injection points you always inject the same bean and the other is rarely used, you might consider marking the first one with @Primary .

@Component
@Primary
public class HybridTheory implements CompactDisc { }

      

Whenever Spring detects that there is more than one bean that matches the injection point, it will inject one annotated with @Primary.Note that if there is more than one bean annotated with @Primary and implementing the interface used at the injection point, the problem remains.

3. Use Java Configuration

While @Qualifier and @Primary solve the problem, sometimes you may find that you have to travel a lot through the source code to find out which implementation is in place. Sometimes a cleaner approach is to ditch @Component (or other stereotype annotations) from your classes and declare beans using Java config:

public class HybridTheory implements CompactDisc { }

public class Meteora implements CompactDisc { }

@Configuration
class RecordsConfiguration {

    @Bean
    CompactDisc hybridTheory() {
        return new HybridTheory();
    }

    @Bean
    CompactDisc meteora() {
        return new Meteora();
    }

    @Bean
    Player player() {
        return new Player(meteora());
    }
}

      

Choose the one that works best for your use case!

+2


source







All Articles