繁体   English   中英

Spring 中的接口依赖注入

[英]Dependency Injection with interface in Spring

我有一个MainHandler class:

@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 注入依赖项吗?

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

有两种简单的方法可以接近:

  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

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

例如你可以引入一个方法

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...");
        }
    }
}

output:

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...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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