![](/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.