首页 > 解决方案 > Spring中的接口依赖注入

问题描述

我有一个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 如何选择在这种情况下使用哪个处理程序。有什么解决办法吗?

标签: javaspringspring-boot

解决方案


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

选项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

使用限定符。

您可以随意命名您的处理程序,然后将 a 注入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...

推荐阅读