Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何基于另一个bean的属性注入一个bean?_Java_Spring_Java 8_Strategy Pattern - Fatal编程技术网

Java 如何基于另一个bean的属性注入一个bean?

Java 如何基于另一个bean的属性注入一个bean?,java,spring,java-8,strategy-pattern,Java,Spring,Java 8,Strategy Pattern,我试图使用Spring应用策略模式(我想我弄错了),如下所示 我的主课看起来像 @Component public class DirectoryUserImportWorkflow { private List<DirectoryUserDataSource> dataSources = Arrays.asList(new ActiveDirectoryDataSource(), new CsvDataSource()); @Autowired priva

我试图使用Spring应用
策略
模式(我想我弄错了),如下所示

我的主课看起来像

@Component
public class DirectoryUserImportWorkflow {
    private List<DirectoryUserDataSource> dataSources = Arrays.asList(new ActiveDirectoryDataSource(), new CsvDataSource());

    @Autowired
    private DirectoryUsersFetcher directoryUsersFetcher;

    public void run() {
        dataSources.forEach(dataSource -> directoryUsersFetcher.importUsers(dataSource));
    }
}
以2个实现为例

@Component
public class ActiveDirectoryUsersFetcher implements DirectoryUsersFetcher {
    public Iterator<String> importUsers(DirectoryUserDataSource dataSource) {
        System.out.println("Returning data from Active Directory");
        return Arrays.asList("ActiveDirectoryUser1", "ActiveDirectoryUser2", "ActiveDirectoryUser3").iterator();
    }
}
public class ActiveDirectoryDataSource implements DirectoryUserDataSource {
    public DataSourceType getType() {
        return DataSourceType.DirectoryServer;
    }
}
数据源
本身是一个界面,看起来像

public interface DirectoryUserDataSource {
    DataSourceType getType();
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {DirectoryUserImportWorkflow.class, ActiveDirectoryUsersFetcher.class, CsvUsersFetcher.class})
public class DirectoryUserImportWorkflowTest {

    @Autowired
    private DirectoryUserImportWorkflow workflow;

    @Test
    public void runStrategy() throws Exception {
        workflow.run();
    }
}
以2个实现为例

@Component
public class ActiveDirectoryUsersFetcher implements DirectoryUsersFetcher {
    public Iterator<String> importUsers(DirectoryUserDataSource dataSource) {
        System.out.println("Returning data from Active Directory");
        return Arrays.asList("ActiveDirectoryUser1", "ActiveDirectoryUser2", "ActiveDirectoryUser3").iterator();
    }
}
public class ActiveDirectoryDataSource implements DirectoryUserDataSource {
    public DataSourceType getType() {
        return DataSourceType.DirectoryServer;
    }
}

我的
测试
看起来像

public interface DirectoryUserDataSource {
    DataSourceType getType();
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {DirectoryUserImportWorkflow.class, ActiveDirectoryUsersFetcher.class, CsvUsersFetcher.class})
public class DirectoryUserImportWorkflowTest {

    @Autowired
    private DirectoryUserImportWorkflow workflow;

    @Test
    public void runStrategy() throws Exception {
        workflow.run();
    }
}
我看到的是

        at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'directoryUserImportWorkflow': Unsatisfied dependency expressed through field 'directoryUsersFetcher': No qualifying bean of type [com.learner.datafetcher.DirectoryUsersFetcher] is defined: expected single matching bean but found 2: activeDirectoryUsersFetcher,csvUsersFetcher; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.learner.datafetcher.DirectoryUsersFetcher] is defined: expected single matching bean but found 2: activeDirectoryUsersFetcher,csvUsersFetcher
我怎样才能解决这个问题

我需要什么?

根据
DataSource
ActiveDirectory
还是
Csv
,特定的获取程序应该调用
ActiveDirectoryUsersFetcher
或者
CsvUsersFetcher

我在哪里失去了理解


提前感谢

所以,您有两个bean,具有相同的接口,但有两个不同的名称,但您已经知道了。现在你有多种选择

您可以按照@crm86的建议,简单地将
@Qualifie
r添加到
@Autowired
,给出bean的名称。当然,这将使您的实现与您使用它的地方紧密结合,并且除了更改代码之外,您将无法使用其他实现。您也可以不自动连接接口,而是自动连接实现类,但当然,出于同样的原因,这也是一个坏主意-为什么在删除容器的任何选项时,首先尝试使用依赖项注入

另一种方法是首先使用
@Configuration
和以下方法仅创建一个
DirectoryUsersFetcher
实例

@Bean
public DirectoryUsersFetcher directoryUsersFetcher () {
// decide, create, return
}
当然,这将限制您的应用程序在每个运行时只有一个抓取程序(如果您不声明它们为原型,但这将要求您将类型保留在某个位置,我想这很麻烦)。无论如何,您都需要在某个地方定义类型

另一种方法是不直接创建bean,而是使用工厂模式,例如

@Component
public class DirectoryUsersFetcherFactory {

    public DirectoryUsersFetcher createDirectoryUsersFetcher (ActiveDirectoryDataSource dataSource) {
          DataSourceType type = dataSource.getType();
          if(type == DataSourceType.DirectoryServer) 
              return new ActiveDirectoryUsersFetcher ();
          if(type == DataSourceType.Csv) 
              return new CsvUsersFetcher ();
          throw new IllegalArgumentException("Unknown type" + type);
    } 

}
这样,你就可以直接连接工厂而不是豆子。工厂还可以缓存对象等。我个人建议采用这种解决方案

@Autowired
private DirectoryUsersFetcherFactory factory;

public void run() {
    dataSources.forEach(dataSource -> directoryUsersFetcher.importUsers(factory.createDirectoryUsersFetcher(dataSource)));
}
当然,您的工厂也可以简单地自动连接工厂中的取数器,并将取数器作为bean返回

@Component
public class DirectoryUsersFetcherFactory {

    @Autowired
    private ActiveDirectoryUsersFetcher activeDirectoryUsersFetcher ;

    @Autowired
    private CsvUsersFetcher csvUsersFetcher ;

    public DirectoryUsersFetcher createDirectoryUsersFetcher (ActiveDirectoryDataSource dataSource) {
          DataSourceType type = dataSource.getType();
          if(type == DataSourceType.DirectoryServer) 
              return activeDirectoryUsersFetcher ;
          if(type == DataSourceType.Csv) 
              return csvUsersFetcher;
          throw new IllegalArgumentException("Unknown type" + type);
    } 

}

这么多选择;-)您甚至可以将抓取器与数据源关联,自动连接应用程序上下文,并查看所有现有的抓取器以找到合适的抓取器,这样,您的工厂甚至不需要知道实际的实现,但可以在运行时发现它们。。。但是我想你已经知道了基本的想法…

所以,你有两个bean,具有相同的接口,但有两个不同的名称,但是你已经知道了。现在你有多种选择

您可以按照@crm86的建议,简单地将
@Qualifie
r添加到
@Autowired
,给出bean的名称。当然,这将使您的实现与您使用它的地方紧密结合,并且除了更改代码之外,您将无法使用其他实现。您也可以不自动连接接口,而是自动连接实现类,但当然,出于同样的原因,这也是一个坏主意-为什么在删除容器的任何选项时,首先尝试使用依赖项注入

另一种方法是首先使用
@Configuration
和以下方法仅创建一个
DirectoryUsersFetcher
实例

@Bean
public DirectoryUsersFetcher directoryUsersFetcher () {
// decide, create, return
}
当然,这将限制您的应用程序在每个运行时只有一个抓取程序(如果您不声明它们为原型,但这将要求您将类型保留在某个位置,我想这很麻烦)。无论如何,您都需要在某个地方定义类型

另一种方法是不直接创建bean,而是使用工厂模式,例如

@Component
public class DirectoryUsersFetcherFactory {

    public DirectoryUsersFetcher createDirectoryUsersFetcher (ActiveDirectoryDataSource dataSource) {
          DataSourceType type = dataSource.getType();
          if(type == DataSourceType.DirectoryServer) 
              return new ActiveDirectoryUsersFetcher ();
          if(type == DataSourceType.Csv) 
              return new CsvUsersFetcher ();
          throw new IllegalArgumentException("Unknown type" + type);
    } 

}
这样,你就可以直接连接工厂而不是豆子。工厂还可以缓存对象等。我个人建议采用这种解决方案

@Autowired
private DirectoryUsersFetcherFactory factory;

public void run() {
    dataSources.forEach(dataSource -> directoryUsersFetcher.importUsers(factory.createDirectoryUsersFetcher(dataSource)));
}
当然,您的工厂也可以简单地自动连接工厂中的取数器,并将取数器作为bean返回

@Component
public class DirectoryUsersFetcherFactory {

    @Autowired
    private ActiveDirectoryUsersFetcher activeDirectoryUsersFetcher ;

    @Autowired
    private CsvUsersFetcher csvUsersFetcher ;

    public DirectoryUsersFetcher createDirectoryUsersFetcher (ActiveDirectoryDataSource dataSource) {
          DataSourceType type = dataSource.getType();
          if(type == DataSourceType.DirectoryServer) 
              return activeDirectoryUsersFetcher ;
          if(type == DataSourceType.Csv) 
              return csvUsersFetcher;
          throw new IllegalArgumentException("Unknown type" + type);
    } 

}

这么多选择;-)您甚至可以将抓取器与数据源关联,自动连接应用程序上下文,并查看所有现有的抓取器以找到合适的抓取器,这样,您的工厂甚至不需要知道实际的实现,但可以在运行时发现它们。。。但是我想你已经明白了基本的想法…

仍然困惑不解。我需要使用这两个bean,只需要根据
DataSourceType
使用工厂的内容进行选择。连接它而不是获取程序本身,然后将DataSourceType提供给factory方法,让该方法创建/返回适当的获取程序。嗯,你能告诉我一个我可以查找并理解的示例或参考吗?仍然困惑。我需要使用这两个bean,只需要根据
DataSourceType
使用工厂的内容进行选择。连接它而不是fetcher本身,然后将DataSourceType提供给factory方法,并让该方法创建/返回适当的fetcher.hmm,你能告诉我一个我可以查找并理解的示例或引用吗?为什么取回器不首先包含数据源?为什么取回器不首先包含数据源?