【问题标题】:How to inject a Bean in xml from a method (@Bean) which returns an Interface (com.typesafe.config.Config)?如何从返回接口(com.typesafe.config.Config)的方法(@Bean)注入xml中的Bean?
【发布时间】:2017-02-15 18:28:14
【问题描述】:

我有一个基于 xml-config 的 spring 应用程序,其中我的一个 bean 需要一个 com.typesafe.config.Config 参数作为构造函数参数。 为此,我们有一个@Configuration 类,其中一个方法(注释为@Bean)返回一个com.typesafe.config.Config 对象。

但是当spring启动时它会抱怨“无法实例化[com.typesafe.config.Config]:指定的类是一个接口”

如何通过 xml 将 getconfig 返回对象注入到构造函数中?

这里是为了摆脱应用逻辑而简化的sn-p代码:

import com.typesafe.config.Config;
...
public class myFilter implements Filter {
  public myFilter(Config aconfig) {
        ...
  }
}

然后我有一个如下的 JavaConfig 类,它创建了我需要在 myFilter 构造函数中注入的 bean:

@org.springframework.context.annotation.Configuration
public class TSConfiguration {
   ...
   @Bean(name = "app-config")
   public Config getConfig() {
     ...
   }
}

我在 spring.xml 文件中添加了以下内容:

<beans:bean class="TSConfiguration" />
<beans:bean id="app-config" class="com.typesafe.config.Config"/>
<beans:bean id="theFilter" class="myFilter">
   <beans:constructor-arg index="0" ref="app-config"/>
 </beans:bean>

这是 Spring 的例外情况:

15-Feb-2017 13:19:55.463 SEVERE [localhost-startStop-1] org.springframework.web.context.ContextLoader.initWebApplicationContext Context initialization failed
 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'app-config' defined in ServletContext resource [/WEB-INF/spring-security.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.typesafe.config.Config]: Specified class is an interface

谢谢。

【问题讨论】:

    标签: spring dependency-injection spring-java-config spring-bean typesafe-config


    【解决方案1】:

    有问题的行是这样的:

    &lt;beans:bean id="app-config" class="com.typesafe.config.Config"/&gt;

    由于您已将其放入您的 spring.xml,因此 Spring 正在尝试从 Config 实例化一个名为 app-config 的 bean。但是Config 是一个接口,所以 Spring 无法实例化它,因此会报错。

    我认为,一旦您删除它,Spring 将选择您使用 getConfig 实例化的 @Bean。如果这不起作用,请查看TSConfiguration 是否正确导入到您的spring.xml中。

    【讨论】:

    • 我试图删除它,但仍然无法正常工作。删除我得到的 bean 定义行无法在设置构造函数参数时解析对 bean 'app-config' 的引用;嵌套异常是 org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'app-config' is defined
    • 我没有从 TSConfiguration bean 中得到任何错误。
    • 我没有从 TSConfiguration bean 中得到任何错误:删除 myFilter bean 定义需要 app-config,不会引发其他异常。我离开了 TSConfiguration 并没有给出错误。
    • 我认为您的原始问题已得到解答。下一个 - 这取决于您如何将一个配置导入另一个配置。你能更新一下吗?另外,为什么不能在 TSConfiguration 中实例化 myFilter?那会更简单
    • 问题是“如何通过 xml 将 getconfig 返回对象注入到构造函数中?”。我还没有找到解决方案。 TSConfiguration 是与其他 web 应用程序共享的模块的一部分,而我的过滤器需要从该 web 应用程序中的现有 xml 实例化以获得类型安全的配置。
    【解决方案2】:

    要添加到另一个答案,您要声明两次可能打算成为同一个 bean。

    在这里,您告诉 Spring 创建一个名为 app-config 的 Config 类型的 bean:

     @Bean(name = "app-config")
     public Config getConfig(){
    

    在这里,您正在尝试创建另一个类型为 Config 且 ID 为 app-config 的 bean。

     <beans:bean id="app-config" class="com.typesafe.config.Config"/>
    

    如果您在 JavaConfig 中声明一个 bean,则无需在 XML 中再次声明它,反之亦然(假设您的意图是拥有该类型的单个 bean)。

    而且,正如已经指出的那样,您不能实例化接口。


    更新:

    我将基本上中途忽略您发布的代码,因为似乎对注释的作用以及如何使用它们存在误解。

    首先,如果你想用纯 XML 做所有事情,你不能这样做:

    <beans:bean id="app-config" class="com.typesafe.config.Config"/>
    

    您需要对该接口进行具体实现。但是,根据您发布的内容,您有一个正在使用的配置类。让我们开始吧:

    package com.testpackage;
    
    @Configuration
    public class Config {
    
    
            @Bean
            public SomeInterface someImplementation(){
                return new SomeInterface() {
                    @Override
                    public String implementation() {
                        return "String";
                    }
                };
            }
        }
    

    这表示创建一个SomeInterface 类型的bean。该 bean 的名称将继承方法名称 someImplementation,因此手动为其命名是没有意义的。请注意,虽然这是返回一个接口,但我们正在创建一个匿名类并返回它。

    接下来,我们来看看上面的 XML:

    <beans>
            <context:component-scan base-package="com.testpackage"/>
    
            <bean class="com.testpackage.ConcreteClass">
                <constructor-arg index="0" ref="someImplementation"/>
            </bean>
    </beans>
    

    请注意,我们正在扫描 (context:component-scan) 包含其中配置的包。如果我们使用@Configuration 注释,我们可以进行组件扫描。

    下面的例子做同样的事情,只是手动声明了配置 bean:

    <beans>
            <bean class="com.testpackage.Config"/>
    
            <bean class="com.testpackage.ConcreteClass">
                <constructor-arg index="0" ref="someImplementation"/>
            </bean>
    </beans>
    

    如果你像上面一样手动声明 Config 类,你不需要用@Configuration注解它。该注释的重点是组件扫描以“查看” bean 并对其进行实例化。由于我们是手动完成的,因此不需要注释。

    并且,为了完整起见,这是一个单元测试,可以验证一切正常:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {"classpath:META-INF/appContextTest.xml"})
    public class SomeTester {
    
    
        @Autowired
        ConcreteClass concreteClass;
    
        @Test
        public void test(){
            assertEquals("String", concreteClass.impl.implementation());
        }
    }
    

    【讨论】:

    • 跟随 spring JavaConfig docs docs.spring.io/spring-javaconfig/docs/1.0.0.m3/reference/html/… bean 应该在 xml 中声明。此外,在组件扫描中,@Bean 不会被自动实例化检测。
    • 目的是在 xml bean 定义中使用一个用 JavaConfig 定义的 bean。遵循本指南docs.spring.io/spring-javaconfig/docs/1.0.0.m3/reference/html/…(与删除 ConfigurationPostProcessor 相关的更新很少)我遇到了问题。我正在尝试声明它,因为它不会自动注入并且需要传递给 myFilter 构造函数。
    • 该文档中没有任何内容表明它应该同时使用 XML 和 JavaConfig。它不应该在两个地方。你的问题在这一点上有点不清楚。你应该用一个你试图解决的问题的完整例子来制作一个新的。您现有的问题已得到正确回答。
    • 问题是“如何通过 xml 将 getconfig 返回对象注入到构造函数中?”我不认为它已经得到答复。有人建议删除先前答案中的违规行,我试过了,但它仍然不起作用。问题的答案是什么?
    • 我猜你是对的。说实话,您提供的代码中存在多个问题,因此无法保证您没有做错其他事情(主要是,您将 Java Config 和 XML 混合在一起,两次做同样的事情)。我将用一个基本示例更新我的答案。
    猜你喜欢
    • 2013-04-15
    • 1970-01-01
    • 1970-01-01
    • 2019-03-03
    • 1970-01-01
    • 2012-08-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-31
    相关资源
    最近更新 更多