bean无法作为'Type'注入,因为它是一个JDK动态代理,它实现了:reactor.fn.Consumer

Jan*_*sen 10 java spring project-reactor

使用Reactor 2的My 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.
Run Code Online (Sandbox Code Playgroud)

OrderHandlerConsumer很简单:

@Service
@Order(Ordered.HIGHEST_PRECEDENCE)
public class OrderHandlerConsumer implements Consumer<Event<OrderEnvelope>> {
    @Override
    public void accept(Event<OrderEnvelope> event) {
        event.getData().getLatch().countDown();
    }
}
Run Code Online (Sandbox Code Playgroud)

什么想法可能会出错?

Mik*_*048 27

虽然其他答案可以解决这个问题,但我认为我更适合解释为什么申请proxyTargetClass = true可以解决这个问题。

首先,Spring作为一个框架,利用代理来为bean提供一些扩展功能,例如通过声明式事务@Transactional,或者通过缓存@Cacheable等。一般来说,有两种方式(*)Spring可以在你的bean之上创建代理:

  1. JDK动态代理
  2. CGLib 代理

如果您有兴趣,可以查看有关此内容的官方文档。

如果 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();
}
Run Code Online (Sandbox Code Playgroud)

行不通的。为什么?嗯,因为@Transactional告诉 Spring 它需要SomeService在运行时创建代理,并且在内部@EnableTransactionManagement我特意要求 Spring 通过 JDK 动态代理的方式来实现 - Spring 会成功,因为 JDK 动态代理可以创建,但问题是在运行时没有 type 的 bean SomeService,只有一个 type 的 bean SomeInterface(顺便说一下,如果你不是通过类而是通过接口在这里注入服务 - 它会起作用,我假设你通过阅读上面的解释理解了原因)。

解决方案:通过应用@EnableTransactionManagement(proxyTargetClass = true)(注意此处的真实值),您强制 spring 创建 CGLIB 代理(此规则仅适用于利用声明式事务管理的 bean,即通过注释)。在 CGLIB 代理的情况下,Spring 将尝试扩展原始类,并在运行时在生成的子类中添加附加功能。在这种情况下,按类注入将起作用- 因为 bean 扩展了类SomeService,所以

@Autowired
private SomeService someService;
Run Code Online (Sandbox Code Playgroud)

会工作得很好。但是,一般来说,如果可能的话,通过接口注入 bean,而不是通过类注入。在这种情况下,CGLIB 和 JDK 动态代理都可以工作。因此,请注意 spring 可以使用的代理机制。希望它有帮助,祝你有美好的一天。


Roh*_*han 19

在您将其定义为 Spring 应用程序的应用程序类文件中,在其下方添加。

@SpringBootApplication
@EnableCaching(proxyTargetClass = true)
Run Code Online (Sandbox Code Playgroud)

  • @Rohan 你能解释一下你的答案吗? (6认同)