如何获取指定接口的所有bean,它也实现了其他接口
How to get all beans of specified interface which also implements other interfaces
这里我有 3 个接口:InterfaceA
和 InterfaceB
和 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");
}
}
ImplementA1
和ImplementA2
是同一种运算,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
但是我只能获得bean实现InterfaceA
或者InterfaceB
但不是全部。我想,不崩溃的情况可能是我在其他项目中的一些依赖造成的。
任何人都可以帮助我如何让所有 SharedInterface
更优雅?非常感谢!
问题出在你的配置上。
@Bean
public InterfaceA registerInterfaceA1(){
return new ImplementA1();
}
问题是 Spring 将使用 return 类型的方法来查看它是否填满注入点(在本例中为您的列表)。由于 InterfaceA
不是 SharedInterface
最终它会失败,因为没有根据您的配置实现 SharedInterface
的 bean!
你应该对你自己的bean做的是在return类型中尽可能具体。因此,将 InterfaceA
改为 return 实际的 class ImplementA1
和 ImplementA2
。这样 Spring,在配置时,可以确定那些实现 SharedInterface
并使用它们来填充列表。
@Bean
public ImplementA1 registerInterfaceA1(){
return new ImplementA1();
}
这里我有 3 个接口:InterfaceA
和 InterfaceB
和 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");
}
}
ImplementA1
和ImplementA2
是同一种运算,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
但是我只能获得bean实现InterfaceA
或者InterfaceB
但不是全部。我想,不崩溃的情况可能是我在其他项目中的一些依赖造成的。
任何人都可以帮助我如何让所有 SharedInterface
更优雅?非常感谢!
问题出在你的配置上。
@Bean
public InterfaceA registerInterfaceA1(){
return new ImplementA1();
}
问题是 Spring 将使用 return 类型的方法来查看它是否填满注入点(在本例中为您的列表)。由于 InterfaceA
不是 SharedInterface
最终它会失败,因为没有根据您的配置实现 SharedInterface
的 bean!
你应该对你自己的bean做的是在return类型中尽可能具体。因此,将 InterfaceA
改为 return 实际的 class ImplementA1
和 ImplementA2
。这样 Spring,在配置时,可以确定那些实现 SharedInterface
并使用它们来填充列表。
@Bean
public ImplementA1 registerInterfaceA1(){
return new ImplementA1();
}