Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple Configurations of a Bean with Spring Annotations

In my example here, I have a "Hero" bean which can be injected with a "Weapon" bean. Both Heros and Weapons are prototype-scoped (we can have multiple heroes, and they won't share weapons).

What I want to have is a Hero configuration called "Warrior" which is injected with a "Sword" weapon, and a Hero configuration called "Archer" which is injected with a "Bow" weapon. Then in my application I would call

context.getBean("Warrior");

each time I want to get a new warrior.

I know how to do this with XML, but I was wondering if it is possible to do this with annotations? If so, how do I do it? I am using Spring 4.

like image 949
John Avatar asked Feb 01 '26 21:02

John


1 Answers

Example of LuiggiMendoza's comment (autowiring and qualifying the setter)

Sticking to the script of programming to interfaces, we have the Hero interface

public interface Hero {
    void killOrBeKilled();
}

We'll also have an AbstractHero abstract class to put together some common functionality. Notice we don't implement the setWeapon method. We'll leave that to the concrete class.

public abstract class AbstractHero implements Hero {
    protected Weapon weapon;

    public void killOrBeKilled() {
        weapon.secretWeaponManeuver();
    }

    protected abstract void setWeapon(Weapon weapon);
}

And here are the Qualifiers we'll use. Note, you don't have to create your own qualifiers. You could simply use @Qualifer("qualifierName") for your matchings. I did it just because I could :P

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
public @interface BowType { }

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
public @interface SwordType { }

For the Warrior we'll use the @SwordType qualifier

@Component  
public class Warrior extends AbstractHero {
    @SwordType
    @Autowired
    public void setWeapon(Weapon weapon) {
        this.weapon = weapon;
    }
}

And for the Archer we'll use the @BowType qualifier

@Component
public class Archer extends AbstractHero {
    @BowType
    @Autowired
    public void setWeapon(Weapon weapon) {
        this.weapon = weapon;   
    }
}

In our Weapons concrete classes, we'll also need to annotate the classes with the appropriate qualifiers

public interface Weapon {
    void secretWeaponManeuver();
}

@BowType    
@Component
public class Bow implements Weapon {
    public void secretWeaponManeuver() {
        System.out.println("Bow goes Slinnnggggg!");    
    }
}

@SwordType
@Component
public class Sword implements Weapon {
    public void secretWeaponManeuver() {
        System.out.println("Sword goes Slassshhhh!");   
    }
}

When we run the application, the weapon types will be injected properly based on our qualifiers

@Configuration  
@ComponentScan(basePackages = {"com.stackoverflow.spring.hero"})
public class Config { }

public class Application {
    public static void main(String[] args) {
        AbstractApplicationContext context = 
                new AnnotationConfigApplicationContext(Config.class);

        Hero warrior = context.getBean(Warrior.class);
        warrior.killOrBeKilled();

        Hero archer = context.getBean(Archer.class);
        archer.killOrBeKilled();

        context.close();
    }
}

Result

Sword goes Slassshhhh!
Bow goes Slinnnggggg!

P.S. I forgot the @Scope("prototype") annotation.

  • See Fine-tuning annotation-based autowiring with qualifiers for more info on using qualifiers
like image 143
Paul Samsotha Avatar answered Feb 04 '26 13:02

Paul Samsotha