簡體   English   中英

如何獲取指定接口的所有bean,它也實現了其他接口

[英]How to get all beans of specified interface which also implements other interfaces

這里我有 3 個接口: InterfaceAInterfaceB以及SharedInterface

public interface InterfaceA {
    /**
     * print some message
     */
    void printMsg();
}
public interface InterfaceB {
    /**
     * print some message
     */
    void printMsg();
}
public interface SharedInterface {
    /**
     * print some message
     */
    void printSharedMsg();
}

這些接口有 3 個實現:

public class ImplementA1 implements InterfaceA, SharedInterface {
    @Override
    public void printMsg() {
        System.out.println("this is message of interfaceA1");
    }

    @Override
    public void printSharedMsg() {
        System.out.println("this is shared message from ImplementA1");
    }
}
public class ImplementA2 implements InterfaceA, SharedInterface {
    @Override
    public void printMsg() {
        System.out.println("this is message of interfaceA2");
    }

    @Override
    public void printSharedMsg() {
        System.out.println("this is shared message from ImplementA2");
    }
}
public class ImplementB implements InterfaceB, SharedInterface {
    @Override
    public void printMsg() {
        System.out.println("this is message of interfaceB");
    }

    @Override
    public void printSharedMsg() {
        System.out.println("this is shared message from ImplementB");
    }
}

ImplementA1ImplementA2是同一類型的操作, ImplementB是另一種類型的操作。 所以我決定開發 2 個配置 class 來注冊 ImplementA1、ImplementA2 和 ImplementB,如下所示。

@Configuration
public class InterfaceAConfig {
    @Bean
    public InterfaceA registerInterfaceA1(){
        return new ImplementA1();
    }

    @Bean
    public InterfaceA registerInterfaceA2(){
        return new ImplementA2();
    }
}
@Configuration
public class InterfaceBConfig {
    @Bean
    public InterfaceB registerInterfaceB(){
        return new ImplementB();
    }
}

現在我想讓所有實現SharedInterface的 bean 在組件中打印它們的消息。 它運作良好,這是代碼:

@Component
@AutoConfigureAfter(value = {
    InterfaceAConfig.class,
    InterfaceBConfig.class})
public class SharedInterfaceComponent implements ApplicationListener<ContextRefreshedEvent>, ApplicationContextAware {
    private ApplicationContext applicationContext;

    //print shared message after IOC container refreshed
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        usingContextGetBean();
    }

    private void usingContextGetBean() {
        Map<String, SharedInterface> beans = this.applicationContext.getBeansOfType(SharedInterface.class);
        System.out.println(beans.size());
        for (SharedInterface bean : beans.values()) {
            bean.printSharedMsg();
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

但是我找到了另一種將 bean 注入組件的方法,使用

@Autowired
List<TargetType> myListName

所以我決定將我的SharedInterfaceComponent更改為此以進行測試,並且它有效:

@Component
@AutoConfigureAfter(value = {
    InterfaceAConfig.class,
    InterfaceBConfig.class})
public class SharedInterfaceComponent  implements ApplicationListener<ContextRefreshedEvent>, ApplicationContextAware {
    private ApplicationContext applicationContext;

    //todo why do spring failed due to this autowire?
    @Autowired
    private List<InterfaceA> autowiredList;

    //print shared message after IOC container refreshed
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        usingAutowiredGerBean();
        //usingContextGetBean();
    }

    private void usingAutowiredGerBean() {
        for (InterfaceA interfaceA : autowiredList) {
            if (SharedInterface.class.isAssignableFrom(interfaceA.getClass())){
                ((SharedInterface) interfaceA).printSharedMsg();
            }
        }
    }

    private void usingContextGetBean() {
        Map<String, SharedInterface> beans = this.applicationContext.getBeansOfType(SharedInterface.class);
        System.out.println(beans.size());
        for (SharedInterface bean : beans.values()) {
            bean.printSharedMsg();
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }
}

但是當我嘗試使用SharedInterface而不是InerfaceA從 IOC 獲取 bean 時,它出錯了。 代碼如下所示:

@Component
@AutoConfigureAfter(value = {
    InterfaceAConfig.class,
    InterfaceBConfig.class})
public class SharedInterfaceComponent  implements ApplicationListener<ContextRefreshedEvent>, ApplicationContextAware {
    private ApplicationContext applicationContext;

    //todo why do spring failed due to this autowire?
    @Autowired
    private List<SharedInterface> autowiredList;

    //print shared message after IOC container refreshed
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        usingAutowiredGerBean();
        //usingContextGetBean();
    }

    private void usingAutowiredGerBean() {
        for (SharedInterface sharedInterface : autowiredList) {
            if (SharedInterface.class.isAssignableFrom(sharedInterface.getClass())){
                ((SharedInterface) sharedInterface).printSharedMsg();
            }
        }
    }

    private void usingContextGetBean() {
        Map<String, SharedInterface> beans = this.applicationContext.getBeansOfType(SharedInterface.class);
        System.out.println(beans.size());
        for (SharedInterface bean : beans.values()) {
            bean.printSharedMsg();
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }
}

在此演示中,應用程序將失敗並顯示

***************************
APPLICATION FAILED TO START
***************************

Description:

Field autowiredList in com.wwstation.test.config.SharedInterfaceComponent required a bean of type 'java.util.List' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'java.util.List' in your configuration.


但是在我的其他項目中,同樣的情況不會導致迷戀,我可以通過使用@Autowired來獲取SharedInterface ,但是在那里我只能獲取實現InterfaceAInterfaceB的 beans,而不能全部實現。 我想,不崩潰的情況可能是我在其他項目中的一些依賴造成的。 誰能幫助我了解如何讓所有SharedInterface更優雅? 非常感謝!

問題是你的配置。

@Bean
public InterfaceA registerInterfaceA1(){
    return new ImplementA1();
}

這樣做的問題是 Spring 將使用該方法的返回類型來查看它是否填滿了注入點(在本例中為您的列表)。 由於InterfaceA不是SharedInterface最終它會失敗,因為沒有根據您的配置實現SharedInterface的 bean。

您應該對自己的 bean 做的是在返回類型中盡可能具體。 因此,而不是InterfaceA讓它返回實際的 class ImplementA1ImplementA2 這樣 Spring 在配置時可以確定那些實現SharedInterface並使用它們來填充列表。

@Bean
public ImplementA1 registerInterfaceA1(){
    return new ImplementA1();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM