Spring 引导注释配置的计时问题

Timing Issue with Spring Boot Annotation Configuration

我们的 spring 引导应用程序中的 bean、存储库和控制器的计时有一个奇怪的问题。

我们有一个由地图支持的 NodeRepository。这个 Map 对象应该是我们使用 @Bean 注释创建的 Map,但似乎 Spring 正在创建自己的 Map 并将其注入我们的 NodeRepository。这是一个问题,因为地图中的键是错误的,因为 Spring 对我们的键值进行了假设。

这是所有需要的代码:

org.xxx.Application

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {

        return application.sources(Application.class);
    }

    @Bean
    public Map<String, RemoteNode> getRemoteNodeMap() {

        HashMap<String, RemoteNode> remoteNodeMap = new HashMap<>();
        remoteNodeMap.put("NODE1", this.getRemoteNode1());
        remoteNodeMap.put("NODE2", this.getRemoteNode2());

        return remoteNodeMap;
    }

    @Bean(name = "remoteNode1")
    public RemoteNode getRemoteNode1() {

        return new DefaultRemoteNode("NODE1");
    }

    @Bean(name = "remoteNode2")
    public RemoteNode getRemoteNode2() {

        return new DefaultRemoteNode("NODE2");
    }
}

org.xxx.repository.RemoteNodeRepository

@Repository
public class RemoteNodeRepositoryImpl implements RemoteNodeRepository {

    private Map<String, RemoteNode> remoteNodeMap;

    @Autowired
    public RemoteNodeRepository(Map<String, RemoteNode> remoteNodeMap) {
        this.remoteNodeMap = remoteNodeMap;
    }
}

我期望注入 RemoteNodeRepsoitory 的是一个如下所示的 Map:

"NODE1",RemoteNode("NODE1")

"NODE2",RemoteNode("NODE2")

然而,这是被注入 RemoteNodeRepository 的地图:

"remoteNode1",RemoteNode("NODE1")

"remoteNode2",RemoteNode("NODE2")

注意,键的名称基于应用程序中@Bean 注释的名称class。如果我们删除 @Bean 的 'name' 限定符,则键将以方法命名。

如果我们将 @Qualifier 注释添加到 RemoteNodeRepsoitory 的 Map 属性,我们会得到以下异常:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.chronopolis.remote.node.RemoteNode] found for dependency [map with value type org.chronopolis.remote.node.RemoteNode]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=remoteNodeMap)}

最后,当在调试器中设置断点时,我们可以清楚地看到 RemoteNodeRepository 在我们的应用程序中调用 getRemoteNodeMap() 方法之前被实例化 class。

我们可以做些什么来解决这个计时问题?我很困惑。

我认为这不是时间问题。您 "in conflict" 拥有此 spring 功能(来自 http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/

Even typed Maps can be autowired as long as the expected key type is String. The Map values will contain all beans of the expected type, and the keys will contain the corresponding bean names:

@Autowired
public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
    this.movieCatalogs = movieCatalogs;
}

老实说,我不确定你是否可以 "override" 这很容易,但是简单的解决方法应该可行 - 只需使用一些包装器 class 使你的类型特殊 - 类似于(伪代码):

class NodeMap {
   Map<String, RemoteNode> map;
}

然后在您的 @Bean 定义和自动装配时使用它。或者只是不创建地图并使用 spring 功能(并且可能重命名您的节点 bean)。