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之上创建代理:
如果您有兴趣,可以查看有关此内容的官方文档。
如果 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)
| 归档时间: |
|
| 查看次数: |
7910 次 |
| 最近记录: |