Spring中带有接口的依赖注入

时间:2020-06-14 09:51:30

标签: java spring spring-boot

我有一个 MainHandler 类:

@Component
class MainHandler {

    //inject this
    private Handler handler;

    @Autowired
    public MainHandler(Handler handler){
       this.handler = handler;
    }

    public void action(String message){
        //watch photo
        if (message.equals("photo")){
            handler.handle();
        }
        if(message.equals("audio")){
            //play music
            handler.handle();
        }
        if(message.equals("video")){
            //play video
            handler.handle();
        }
    }

并使用接口跟随其他处理程序。

我可以仅通过接口类型处理程序注入Spring Boot的依赖项吗?

@Component
public interface Handler {
    void handle();
}

@Component
class PhotoHandler implements Handler {
    public void handle(){
        System.out.println("Featuring photo...");
    }
}

@Component
class VideoHandler implements Handler {
    public void handle(){
        System.out.println("Playing video...");
    }
}

@Component
class AudioHandler implements Handler {
    public void handle(){
        System.out.println("Playing music...");
    }
}

或者我想在下面尝试类似的方法。有可能吗?

class MainHandler {

    private VideoHandler videoHandler;
    private AudioHandler audioHandler;
    private PhotoHandler photoHandler;

    @Autowired
    public MainHandler(VideoHandler videoHandler,
                       AudioHandler audioHandler,
                       PhotoHandler photoHandler) {
        this.videoHandler = videoHandler;
        this.audioHandler = audioHandler;
        this.photoHandler = photoHandler;
    }

    public void action(String message){
        //watch photo
        if (message.equals("photo")){
            photoHandler.handle();
        }
        if(message.equals("audio")){
            //play music
            audioHandler.handle();
        }
        if(message.equals("video")){
            //play video
            videoHandler.handle();
        }
    }
}

因此,处理程序的类型取决于用户的消息。我不知道Spring如何选择将在这种情况下使用的处理程序。有解决办法吗?

2 个答案:

答案 0 :(得分:3)

您可以通过两种简单的方法进行操作:

  1. 推荐:您可以使用@Qualifier注入所需的特定bean。

例如

@Component
class MainHandler {

    @Autowired
    @Qualifier("videoHandler") // example
    private Handler handler;

    public void action(){
        handler.message(); // this will print playing video...
    }
}
  1. 您可以注入ApplicationContext

例如:

@Component
class MainHandler {

    @Autowired
    private ApplicationContext context;

    public void action(String message){
        //watch photo
        if (message.equals("photo")){
           ((PhotoHandler) context.getBean(PhotoHandler.class)).handle();
        }
        if(message.equals("audio")){
            //play music
            ((AudioHandler) context.getBean(AudioHandler.class)).handle();
        }
        if(message.equals("video")){
            //play video
            ((VideoHandler) context.getBean(VideoHandler.class)).handle();
        }
    }
}

答案 1 :(得分:1)

这种情况可以有多种解决方案。

选项1

您可以稍微调整处理程序的设计。

例如,您可以介绍一种方法

boolean canHandle(String message);

因此每个处理程序都可以回答是否可以处理传递的消息。

然后,您可以将所有处理程序的列表注入到MainHandler中。

private List<Handler> handlers;

现在有了该列表,您可以通过消息调用每个处理程序:

public void action(String message) {
   handlers.stream()
           .filter(h -> h.canHandle(message))
           .forEach(handler -> handler.handle());
}

完整示例:

@SpringBootApplication
public class SO62370917 {

    public static void main(String[] args) {
        SpringApplication.run(SO62370917.class, args);
    }


    @Component
    static class MainHandler {
        private final List<Handler> handlers;

        MainHandler(List<Handler> handlers) {
            this.handlers = handlers;
        }

        public void action(String message) {
            handlers.stream()
                    .filter(h -> h.canHandle(message))
                    .forEach(Handler::handle);
        }
    }

    @Bean
    CommandLineRunner cmd(MainHandler mainHandler) {
        return args -> {
            mainHandler.action("video");
            mainHandler.action("audio");
            mainHandler.action("photo");
        };
    }

    interface Handler {
        void handle();

        boolean canHandle(String message);
    }

    @Component
    class PhotoHandler implements Handler {
        public void handle(){
            System.out.println("Featuring photo...");
        }

        @Override
        public boolean canHandle(String message) {
            return "photo".equals(message);
        }
    }

    @Component
    class VideoHandler implements Handler {
        public void handle(){
            System.out.println("Playing video...");
        }

        @Override
        public boolean canHandle(String message) {
            return "video".equals(message);
        }
    }

    @Component
    class AudioHandler implements Handler {
        public void handle(){
            System.out.println("Playing music...");
        }

        @Override
        public boolean canHandle(String message) {
            return "audio".equals(message);
        }
    }
}

选项#2

使用限定词。

您可以根据自己的喜好命名处理程序,然后将Map<String, Handler>注入mainHandler中。关键字将是Bean名称和值-实际的处理程序。 Spring会自动处理这个问题。

@SpringBootApplication
public class SO62370917 {

    public static void main(String[] args) {
        SpringApplication.run(SO62370917.class, args);
    }


    @Component
    static class MainHandler {
        private final Map<String, Handler> handlers;

        MainHandler(Map<String, Handler> handlers) {
            this.handlers = handlers;
        }

        public void action(String message) {
            if (handlers.containsKey(message)) {
                handlers.get(message).handle();
            }
        }
    }

    @Bean
    CommandLineRunner cmd(MainHandler mainHandler) {
        return args -> {
            mainHandler.action("video");
            mainHandler.action("audio");
            mainHandler.action("photo");
        };
    }

    interface Handler {
        void handle();
    }

    @Component("photo")
    class PhotoHandler implements Handler {
        public void handle() {
            System.out.println("Featuring photo...");
        }
    }

    @Component("video")
    class VideoHandler implements Handler {
        public void handle() {
            System.out.println("Playing video...");
        }

    }

    @Component("audio")
    class AudioHandler implements Handler {
        public void handle() {
            System.out.println("Playing music...");
        }
    }
}

输出:

2020-06-14 13:06:47.140  INFO 29447 --- [           main] com.example.demo.SO62370917              : Started SO62370917 in 1.356 seconds (JVM running for 1.795)
Playing video...
Playing music...
Featuring photo...