![](/img/trans.png)
[英]Spring MVC to SpringBoot 2: The bean 'xyz' could not be injected as a 'com..Abc' because it is a JDK dynamic proxy that implements:
[英]The bean could not be injected as a 'Type' because it is a JDK dynamic proxy that implements: reactor.fn.Consumer
我使用 Reactor 2 的 Spring 4 应用程序无法启动:
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'orderHandlerConsumer' could not be injected as a 'fm.data.repository.OrderHandlerConsumer' because it is a JDK dynamic proxy that implements:
reactor.fn.Consumer
Action:
Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on @EnableAsync and/or @EnableCaching.
OrderHandlerConsumer
非常简单:
@Service
@Order(Ordered.HIGHEST_PRECEDENCE)
public class OrderHandlerConsumer implements Consumer<Event<OrderEnvelope>> {
@Override
public void accept(Event<OrderEnvelope> event) {
event.getData().getLatch().countDown();
}
}
有什么想法可能会出错吗?
在您将其定义为 Spring 应用程序的应用程序类文件中,在其下方添加。
@SpringBootApplication
@EnableCaching(proxyTargetClass = true)
虽然接受的答案将解决这个问题,但我认为解释为什么应用proxyTargetClass = true
会解决这个问题对我来说更合适。
首先,Spring 作为一个框架,利用代理来为 bean 提供一些扩展功能,例如通过@Transactional
进行声明性事务,或者通过@Cacheable
等方式进行缓存。一般来说,有两种方式( *) Spring 可以在你的 bean 之上创建代理:
如果您有兴趣,请提供有关此的官方文档。
如果 bean 的原始类实现了至少一个接口,Spring 可以创建 bean 的 jdk 动态代理(当然,如果这个 bean 需要代理)。 所以spring基本上在运行时创建了这个接口的另一个实现,在原始类之上有一些额外的逻辑。
问题是什么:如果 bean 是通过 jdk 动态代理代理的,那么你不能通过它的原始类注入这个 bean 。 所以是这样的:
@SpringBootApplication
@EnableTransactionManagement(proxyTargetClass = false)
public class StackoverflowApplication {
@Autowired private SomeService service;
public static void main(String[] args) {
SpringApplication.run(StackoverflowApplication.class, args);
}
}
@Service
class SomeService implements SomeInterface {
@Override
@Transactional
public void handle() { }
}
interface SomeInterface {
void handle();
}
不会工作。 为什么? 好吧,因为@Transactional
告诉Spring它需要在运行时创建SomeService
的代理,并且在@EnableTransactionManagement
我特别要求Spring通过jdk动态代理的方式来制作它-spring会成功,因为可以创建jdk动态代理,但是问题是在运行时没有SomeService
类型的 bean,只有SomeInterface
类型的 bean(顺便说一下,如果你在这里注入服务不是通过类,而是通过接口 - 它会起作用,我假设你理解原因通过阅读上面的解释)。
解决方案:通过应用@EnableTransactionManagement(proxyTargetClass = true)
(注意这里的真值)你强制spring创建CGlib代理(这个规则只适用于使用声明性事务管理的bean,即通过注释)。 在 CgLib 代理的情况下,Spring 将尝试扩展原始类,并在运行时在生成的子类中添加额外的功能。 在这种情况下,按类注入将起作用- 因为 bean 扩展了类SomeService
,所以
@Autowired
private SomeService someService;
会很好地工作。 但是,一般来说,如果可能的话,按接口注入 bean,而不是按类。 在这种情况下,Cglib 和 jdk 动态代理都可以工作。 因此,请注意 spring 可以使用的代理机制。 希望对您有所帮助,祝您有美好的一天。
您可以为 OrderHandlerConsumer 类分配一个 bean 名称,这样 Autowire 解析会更容易,此外,尝试使用接口自动连接,而不是使用具体类进行自动连接。 这样您就可以将 @Service 注释更改为,
@Service(value="orderHandlerConsumer")
并尝试使用接口类型自动装配,
@Autowire
reactor.fn.Consumer orderHandlerConsumer;
请尝试如下自动装配
class Test{
@Autowired
private Consumer orderHandlerConsumer;
}
如果要代理的目标对象至少实现一个接口,则将使用 JDK 动态代理。 目标类型实现的所有接口都将被代理。 如果目标对象没有实现任何接口,那么将创建一个 CGLIB 代理。
https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch08s06.html
你可以用两种方式称呼它。
第一种方法是不提及代理 [with default proxy] ,您可以通过如下界面自动装配它。
@Autowired
private Consumer orderHandlerConsumer;
Spring AOP 将为OrderHandlerConsumer
创建一个实例。
第二种方法是,将 bean 中的代理称为ScopedProxyMode.TARGET_CLASS
。 那么你可以自动装配一个没有接口的实例[基于类]。
@Service
@Order(Ordered.HIGHEST_PRECEDENCE)
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class OrderHandlerConsumer implements Consumer<Event<OrderEnvelope>> {
@Override
public void accept(Event<OrderEnvelope> event) {
event.getData().getLatch().countDown();
}
}
和 Autowire 的类,如下所示。
@Autowired
private OrderHandlerConsumer orderHandlerConsumer;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.