在为其声明添加接口后找不到Spring Bean

时间:2015-02-25 02:05:48

标签: spring javabeans

即使打开了大量的调试,这个让我神秘化了。我有一个像这样定义的spring bean:

@Component
public class GraphHistoryLoader {
...
}

我将它注入另一个这样的bean:

@Component
public class StartupPostProcessor {
    @Autowired
    GraphHistoryLoader historyLoader;
}

这适用于实例化GraphHistoryLoader并注入StartupPostProcessor。但是,如果我然后向GraphHistoryLoader添加一个接口,如下所示:

@Component
public class GraphHistoryLoader implements FXCommandLineAware {
...
}

我看到Spring创建的GraphHistoryLoader可用于注入,但是注入StartupPostProcessor失败了:

Error creating bean with name 'startupPostProcessor':
Injection of auto wired dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: 
Could not autowire field: au.com.anz.fx.process.GraphHistoryLoader
au.com.anz.fx.process.StartupPostProcessor.historyLoader

奇怪的是我有其他类也实现了FXCommandLineAware接口,它们工作得很好。很高兴基于他们的课程注入其他豆类。关于这个特定定义和注入导致失败的一些事情。

有没有人有什么想法可以看?

4 个答案:

答案 0 :(得分:1)

我遇到了同样的问题,但另外我使用了Spring AOP。这意味着您的示例中的GraphHistoryLoader由Spring代理以实现AOP处理。 Spring以两种方式使用代理。见spring docs

  • JDK动态代理。它需要您的bean实现一个接口。基于此接口创建代理,该接口“包装”您的实际bean实例。因为你松散具体的类型信息,所有剩下的只是界面。这就是春天抛出BeanCreationException
  • 的原因
  • CGLIB。我不知道这个库如何工作的确切细节,但它允许您代理不实现任何接口的类。它不能代理最终方法或最终类。

要在这两个选项之间切换,启用spring-aop时,请在xml中指定标记proxy-target-class

<aop:config proxy-target-class="true">
    <!-- other beans defined here... -->
</aop:config>

或者在Java Spring Config类中通过注释

@EnableAspectJAutoProxy(proxyTargetClass = true)

请注意,代理在Spring中用于其他模块,如事务和缓存。然后你需要在主题的模块的相应位置设置标志proxyTargetClass

答案 1 :(得分:0)

您是否在applicationContext xml文件中定义了compoent-scan。组件扫描会扫描您声明的包,如果找到注释@ Component,@ Service,@ Repository,@ Controller或@Configuration将为您创建一个bean实例。

请确保您在组件扫描中定义的包(也包括GraphHistoryLoader类包)。

<context:component-scan base-package="com.mycompany.*"/>

可能的原因是: 声明GraphHistoryLoader的上下文既不是与StartupPostProcessor相同的上下文,也不是父上下文

答案 2 :(得分:0)

如果调试代码,spring类ClassUtils.java#isAssignableValue(Class,Class)正在比较类的实际类型与“proxy”类(类型为com.sun.proxy。$ Proxy47)。这就是为什么它不起作用的原因:

public static boolean isAssignableValue(Class<?> type, Object value) {
    Assert.notNull(type, "Type must not be null");
    return (value != null ? isAssignable(type, value.getClass()) : !type.isPrimitive());
}

目前有两种选择:

  1. 使用界面而不是类(推荐方法
  2. 将AOP和/或transactionManager配置为代理类
  3. 示例:

    <tx:annotation-driven proxy-target-class="true"/>
    

答案 3 :(得分:0)

Spring AOP默认将标准JDK动态代理用于AOP代理。这使得可以代理任何接口(或一组接口)。参见AOP Proxies docs。因此,当您的bean实现任何接口时,都会使用JDK Proxy.getProxyClass进行复制,并且在创建的代理bean中只有接口方法可用。

为了在全局范围内强制类字节码生成,请在@Andrés答案中使用AOP配置。或者,您可以专门在问题Bean上声明此代理类型:

@Component
@Scope( proxyMode = ScopedProxyMode.TARGET_CLASS )
public class GraphHistoryLoader implements FXCommandLineAware {
    ....
}