Reputation: 21883
Even after turning on lots of debug this one has me mystified. I have a spring bean defined like this:
@Component
public class GraphHistoryLoader {
...
}
And I an injecting it into another bean like this:
@Component
public class StartupPostProcessor {
@Autowired
GraphHistoryLoader historyLoader;
}
This works fine with GraphHistoryLoader being instantiated and injected into StartupPostProcessor. However, if I then add an interface to GraphHistoryLoader like this:
@Component
public class GraphHistoryLoader implements FXCommandLineAware {
...
}
I see GraphHistoryLoader being created by Spring and made available for injection, But then the injection into StartupPostProcessor fails with:
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
The weird thing is that I have other classes which also implement the FXCommandLineAware interface and they work just fine. Happily being injected based on their class into other beans. It's something about this particular definition and injection that is causing the failure.
Does anyone have any ideas what to look at?
Upvotes: 5
Views: 4372
Reputation: 18000
Spring AOP defaults to using standard JDK dynamic proxies for AOP proxies. This enables any interface (or set of interfaces) to be proxied. See AOP Proxies docs. So, when your bean implement any interfaces, for proxing JDK Proxy.getProxyClass
is used and only interfaces methods will be available in created proxy bean.
In order to force class byte-code proxing globally, use AOP configuration in @Andrés answer. Or you can declare this proxy type specially on problem bean:
@Component
@Scope( proxyMode = ScopedProxyMode.TARGET_CLASS )
public class GraphHistoryLoader implements FXCommandLineAware {
....
}
Another option - include in implemented interfaces (could be several) missed method
Upvotes: 1
Reputation: 1428
If you debug the code, the spring class ClassUtils.java#isAssignableValue(Class,Class) is comparing the actual type of the class versus a "proxy" class (of type com.sun.proxy.$Proxy47). That's why it doesn't work:
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());
}
So far there is 2 options:
Example:
<tx:annotation-driven proxy-target-class="true"/>
Upvotes: 1
Reputation: 7275
I got same problem but additionally I used Spring AOP. This means that GraphHistoryLoader
from your example is proxied by Spring to achieve AOP handling. Spring uses proxies in two ways. See spring docs
BeanCreationException
To switch between these two options, when enabling spring-aop, specify flag proxy-target-class
in xml.
<aop:config proxy-target-class="true">
<!-- other beans defined here... -->
</aop:config>
Or in Java Spring Config class via annotation
@EnableAspectJAutoProxy(proxyTargetClass = true)
Note that proxies are used in Spring in other modules, like transactions and caches. Then you need to set flag proxyTargetClass
in corresponding place of module in subject.
Upvotes: 1
Reputation: 580
Have you defined compoent-scan in the applicationContext xml file. The component-scan scans the package you've declared and if it finds the annotations @Component, @Service, @Repository, @Controller, or @Configuration will create a bean instance for you.
Please make sure the packages you defined in the component-scan (include the GraphHistoryLoader class package too).
<context:component-scan base-package="com.mycompany.*"/>
Possible cause is: The context in which GraphHistoryLoader is declared is neither same context as StartupPostProcessor one, nor a parent context
Upvotes: 0