简体   繁体   中英

How do I specify which component to use while creating the bean using applicationContext.getBean() in spring?

I have the following classes and interfaces:

public interface GamingSoftware {
    public void up();
    public void down();
    public void left();
    public void right();
}

@Component
public class SuperMario implements GamingSoftware {
    public void up() { System.out.println("Super Mario: up"); }
    public void down() { System.out.println("Super Mario: down"); }
    public void left() {  System.out.println("Super Mario: left"); }
    public void right() { System.out.println("Super Mario: right"); }
}

@Component
public class SuperContra implements GamingSoftware {
    public void up() { System.out.println("Super Contra: up"); }
    public void down() { System.out.println("Super Contra: down"); }
    public void left() {  System.out.println("Super Contra: left"); }
    public void right() { System.out.println("Super Contra: right"); }
}

@Component
public class GameRunner {
    @Autowired
    private GamingSoftware game;
    public GameRunner(GamingSoftware game) {
        this.game = game;
    }
    public void run() {
        game.up();
        game.down();
        game.left();
        game.right();
    }
}

@SpringBootApplication
public class GamingDevice {

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(GamingDevice.class, args);
        GameRunner gameRunner = applicationContext.getBean(GameRunner.class);
        gameRunner.run();
    }

}

While getting the bean applicationContext.getBean(GameRunner.class) , I want to be able to specify the game for instantiating the GamingSoftware variable in the GameRunner class.

When I run the above code it gives me an error like, Constructor for game runner required a single bean but 2 found SuperMario and SuperContra .

How do I specify which component to use in my applicationContext.getBean() method?

In springboot the context is not loaded while applicationContext.getBean(). The context is loaded in SpringApplication.run(GamingDevice.class, args), so in that line is when the exception is throw.

For runnig you must eliminate the @Autowired on GamingSoftware and load it using a set property:

    @Component
    public class GameRunner {
    
        private GamingSoftware game;
        
        public void run() {
            game.up();
            game.down();
            game.left();
            game.right();
        }
    
        public GamingSoftware getGame() {
            return game;
        }
    
        public void setGame(GamingSoftware game) {
            this.game = game;
        }
        
    }

@SpringBootApplication
public class GamingDevice {

    public static void main(String[] args) {
         ConfigurableApplicationContext applicationContext = SpringApplication.run(GamingDevice.class, args);
         GameRunner gameRunner = applicationContext.getBean(GameRunner.class);
         gameRunner.setGame(applicationContext.getBean("superContra",GamingSoftware.class));
         gameRunner.run();
    }

}

The function getBean() supports parameters to supplier bean constructors. You can pass the proper GamingSoftware instance when you calling the getBean(Class, Args...)

Read more about get beans here

You can create a property in application.properties (or application.yml) for example

myapp.gametype=mario

Then add to your @Component annotation @ConditionalOnProperty

@Component
@ConditionalOnProperty(name = "myapp.gametype", havingValue = "mario")
public class SuperMario implements GamingSoftware {
    public void up() { System.out.println("Super Mario: up"); }
    public void down() { System.out.println("Super Mario: down"); }
    public void left() {  System.out.println("Super Mario: left"); }
    public void right() { System.out.println("Super Mario: right"); }
}

@Component
@ConditionalOnProperty(name = "myapp.gametype", havingValue = "contra")
public class SuperContra implements GamingSoftware {
    public void up() { System.out.println("Super Contra: up"); }
    public void down() { System.out.println("Super Contra: down"); }
    public void left() {  System.out.println("Super Contra: left"); }
    public void right() { System.out.println("Super Contra: right"); }
}

Next time Spring will create only one Bean of GamingSoftware interface depends on what value has your property.

Beans are created with a name based on the concrete class name (with first letter made lowercase). Try

applicationContext.getBean(“superMario”)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM