Multiple Bean Configurations with Spring Annotations
In my example here, I have a "Hero" bean that can be injected with the "Weapon" bean. Both Hero and Weapons are prototypes (we can have multiple heroes and they won't share weapons).
What I want to have is a hero configuration called "Warrior" which introduces the "Sword" weapon and a hero configuration called "Archer" which introduces the weapon "Bow". Then in my application I would call
context.getBean("Warrior");
every time i want to get a new warrior.
I know how to do this with XML, but I was wondering if it could be done with annotations? If so, how do I do it? I am using Spring 4.
source to share
Example of LuiggiMendoza comment (auto-install and setter detection)
Sticking with script programming to interfaces, we have an interface Hero
public interface Hero {
void killOrBeKilled();
}
We will also have an abstract class AbstractHero
to collect some common functionality. Please note that we are not implementing the method setWeapon
. We'll leave this in a specific 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 be using. Please note, you don't need to create your own qualifiers. You can just use @Qualifer("qualifierName")
for your mappings. I only did it 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 Warrior
we will use the qualifier@SwordType
@Component
public class Warrior extends AbstractHero {
@SwordType
@Autowired
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
}
And for Archer
we will use the qualifier@BowType
@Component
public class Archer extends AbstractHero {
@BowType
@Autowired
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
}
In our Weapons
concrete classes, we will 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 launch the application, the weapon types will be entered correctly 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
The sword goes Slassshhh!
The bow goes Slinnnggggg!
PS I forgot the annotation @Scope("prototype")
.
- See Fine-tuning Annotation-Based Auto-Tuning with Qualifiers for more information on using qualifiers
source to share