![](/img/trans.png)
[英]Why is programmatically created bean not available in the application context
[英]Application context bean
我試圖從應用程序上下文中提取bean。
所以我定義了類:
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext(ApplicationContext _applicationContext) throws BeansException {
applicationContext = _applicationContext;
}
}
在我的applicationContext.xml中
<bean id="workflowService" class="com.mycompany.util.WorkflowService">
<bean id="applicationContextProvider" class="com.mycompany.util.ApplicationContextProvider"></bean>
<context:annotation-config />
但是,當我嘗試時,在我的代碼中:
WorkflowService service = (WorkflowService) ApplicationContextProvider.getApplicationContext().getBean("workflowService");
我明白了:
java.lang.ClassCastException:$ Proxy40無法強制轉換為com.mycompany.util.WorkflowService
編輯 :
WorkflowService代碼:
public class WorkflowService implements Serializable {
...
@PostConstruct
public void init() {
}
...
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public Collection<lData> findData(Integer contractId) {
}
}
你的問題是這樣的:
WorkflowService implements Serializable
Spring生成的任何代理都將實現您的類所做的所有接口 - 在本例中為Serializable
,這幾乎肯定不是您想要的。
你應該做的是從WorkflowService
提取一個新接口,它包含findData
方法(我們稱之為WorkflowOperations
)。 通過實現該接口,您將能夠轉換到該接口,例如
public interface WorkflowOperations {
Collection<lData> findData(Integer contractId);
}
public class WorkflowService implements WorkflowOperations {
...
@PostConstruct
public void init() {
}
...
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public Collection<lData> findData(Integer contractId) {
}
}
接着:
WorkflowOperations service = (WorkflowOperations) ApplicationContextProvider.getApplicationContext().getBean("workflowService");
您可能還應該從WorkflowService
刪除Serializable
。 你幾乎肯定不需要這個,像這樣序列化Spring bean是沒有意義的。 如果您剛剛添加了Serializable
的習慣,那么將其刪除(並擺脫這種特殊習慣)。
我想WorkflowService
是一個實現至少一個接口的類(你沒有提供足夠的代碼)。 您正在嘗試從Spring查找確切的類,而您應該要求其中一個接口。
這是因為Spring大部分時間都將bean包裝在幾個代理中(例如事務代理)。 如果類實現至少一個接口,則生成的代理實現所有接口,但不能轉換為原始類。 如果類沒有實現任何接口(通常被認為是重量級服務的不良做法,盡管有問題),Spring將使用原始類的CGLIB子類。 在這種情況下,您的代碼將是有效的。
您正在使用@Transactional
注釋您的服務,因此Spring使用事務JDK動態代理來包裝您的服務bean,該代理實現與您的bean相同的接口,但不是WorkflowService
。 這就是當您嘗試將其分配給WorkflowService
變量時獲得ClassCastException
原因。 我看到兩種可能的解決方案
使用業務方法指定WorkflowService
接口,並在WorkflowServiceImpl
類中實現它。 然后在Spring上下文中將bean定義從WorkflowService
更改為WorkflowServiceImpl
。 這是我推薦的,作為一般設計原則,特別是在Spring環境中工作:Spring喜歡接口。
在Spring上下文中,將proxy-target-class="true"
到<tx:annotation-driven/>
元素中,以強制Spring通過子類化實現代理,以便proxy instanceof WorkFlowService
為true。 我覺得這個解決方案比較臟。 另請注意,您通過這種方式添加CGLIB依賴項。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.