当前位置: 首页 > 知识库问答 >
问题:

如何在@Bean注释方法或任何类似方法中创建多个Spring bean?

蔚丰
2023-03-14

在使用HTTP远程处理的Spring应用程序中,我有一个服务façade模块,配置如下(我将代码设置为通用代码以提高清晰度):

@Configuration
public class MyFacadeConfig {

  private HttpInvokerServiceExporter facade(Class<?> cls) {
    HttpInvokerServiceExporter bean = new HttpInvokerServiceExporter();
    // The service referred to by this exporter is already instantiated as another Spring bean with all its dependencies.
    bean.setService(appContext.getBean(cls));
    bean.setServiceInterface(cls);
    return bean;
  }

  @Bean("/first.service")
  public HttpInvokerServiceExporter firstServiceFacade() {
    return facade(FirstService.class);
  }

  @Bean("/second.service")
  public HttpInvokerServiceExporter secondServiceFacade() {
    return facade(SecondService.class);
  }

  // ... and so on for the 37 other services

}

其中,FirstService和SecondService是与现有实现的接口,此处不需要这些实现的详细信息。

我有另一个模块,它定义了39个代理(HTTPInvokerProxy工厂bean的实例),对应于通过façade公开的每个服务。

到目前为止,一切正常。

但我希望使代码更加通用、优雅和健壮,同时降低错误风险(例如,未来服务与其代理之间的映射不好)。我希望这样做的方式如下:

首先,我将façade/proxy元数据移动到枚举中:

public enum ConfigBeansFacade {

  FIRST("/first", FirstService.class),
  SECOND("/second", SecondService.class)
  // ... and so on for the 37 other services
  ;

  private String beanName;
  private Class<?> serviceInterface;

  // Constructor and getters

  public String getCompleteBeanName() {
    return beanName + ".service";
  }

}

然后,将立面的配置简化为类似以下的样式:

@Configuration
public class MyFacadeConfig {

  @Autowired
  private ConfigurableBeanFactory beanFactory;

  @Autowired
  public void configExporters() {
    for (ConfigBeansFacade bean : ConfigBeansFacade.values()) {
      HttpInvokerServiceExporter exp = new HttpInvokerServiceExporter();
      exp.setService(beanFactory.getBean(bean.getServiceInterface()));
      exp.setServiceInterface(bean.getServiceInterface());
      beanFactory.registerSingleton(bean.getCompleteBeanName(), exp);
    }
  }

}

我尝试了在在线论坛上找到的每一个菜谱,包括StackOverflow,但有两个限制条件在其他地方没有得到满足:

  1. 定义导出器时,底层服务是其他Springbean,通过标准Spring机制实例化、初始化并注册它们自己的配置和依赖项。除了导出器本身之外,没有直接的类实例

考虑到这些限制,当我尝试检索要封装到导出器中的底层服务时,出现了(1)中的问题:它们不一定已经准备好,这会导致未满足的依赖异常(UnsatifiedDependencyException)。

我尝试了带有@PostContruct-annotated方法的解决方案,带有BeanPostProcess的解决方案,带有@Autow的方法(如上所示),没有任何东西按要求工作。

有人知道在我上面描述的约束下,在一个方法中初始化和注册多个bean的方法或技术吗?这种方法不需要用Bean、Autowired或任何其他特定的注释进行注释,这只是我尝试的一个示例。

幸运的是,在客户机模块中,HttpInvokerProxyFactoryBean实例只需要接口和bean名称,因此上述约束(1)不应适用。

提前感谢您提供的任何帮助。。。

共有1个答案

鲜于高明
2023-03-14

我不是百分之百地理解您的意图,但我想知道您是否可以尝试自动连接实现接口的bean列表?

例如

public interface MyService {
  String getKey();
  void doStuff();
}

然后根据需要实现尽可能多的这些

例如

@Component
public class FirstService implements MyService {
  public String getKey() {
    return "/first";
  }
  public void doStuff() {
    ...
  }
}

然后有一个带有自动连线列表的工厂bean

@Component
public class MyServiceFactory {

  private final List<MyService> services;

  @Autowired
  public MyServiceFactory(List<MyService> services) {
      this.services = services;
  }
}

要添加更多MyService的实现,只需将它们添加为@Component,Spring就会神奇地拾取它们并将它们添加到列表中。

有时,我发现通过映射访问我的实现很有用

@Component
public class MyServiceFactory {

  private final Map<String, MyService> services;

  @Autowired
  public MyServiceFactory(List<MyService> services) {
      this.services = services
        .stream()
        .collect(toMap(MyService::getKey, Function.identity()));
  }

  public MyService getServiceByKey(String key) {
    return services.get(key);
  }
}

我发现这样可以使每个实现都很好、自包含(并且易于测试)。Spring自动拾取实现我的界面的所有组件,而工厂没有大量的导入。通过模拟实现列表,我可以轻松地测试工厂。

 类似资料:
  • 我有一个类似于下面的类: 问题是,有太多@bean注释的方法,它们只是在名称、返回类型和方法调用的参数上有所不同。我想让这堂课类似于以下内容: Spring有可能吗?

  • 对于用@X注释的类中的方法或用@X注释的方法,我需要一个切入点。我还需要注释对象。如果类和方法都被注释,我更喜欢将方法注释作为参数。 我尝试了以下操作,这会产生“绑定不一致”的警告。(为什么不直接将其设置为null?) 以下内容创建了“穿过切入点中的“||”的参数x的不明确绑定”警告。(在我看来,这不一定有意义:为什么不绑定第一个短路评估?) 如果存在类和方法注释,则将前面的尝试拆分为两个,自然会

  • 我有以下问题: 我已经为安全性创建了注释: 在我具有类之间的继承性的情况下,是否也有可能所有类都具有@Security注释来获得最具体的定义? 约西

  • 是否允许在一个方法中使用多个@scheduled注释?

  • 请指导我如何将所有这些转换为asynctask方法。我必须在asynctask中生成这段代码,因为在uithread中调用它时,它给出了一个null值。请告诉我如何实现这一点的正确方法。我看到了很多关于stackoverflow的问题,但我无法做到这一点。 我看到了以下问题: 如何修复android.os.NetworkOnMainThreadException? android.os.Netwo

  • spring应用程序无法启动,因为它无法在配置类中找到一个带有@Service注释的类的bean。但只有在我使用@Transactional注释特定服务类中的方法时才会出现这种情况。为什么会这样?