我正在尝试从应用程序上下文中提取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) {
}
}
答案 0 :(得分:4)
你的问题是:
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");
您可能还应从Serializable
删除WorkflowService
。你几乎肯定不需要这个,像这样序列化Spring bean是没有意义的。如果您刚刚添加Serializable
习惯,那么将其删除(并摆脱这种特殊习惯)。
答案 1 :(得分:3)
我猜WorkflowService
是一个实现至少一个接口的类(你没有提供足够的代码)。您正在尝试从Spring查找确切的类,而您应该要求其中一个接口。
这是因为Spring大部分时间都将bean包装在几个代理中(例如事务代理)。如果类实现至少一个接口,则生成的代理实现所有接口,但不能转换为原始类。如果该类没有实现任何接口(通常被认为是重量级服务的不良做法,尽管有问题),Spring将使用原始类的CGLIB子类。在这种情况下,您的代码将是有效的。
答案 2 :(得分:2)
您使用@Transactional
注释您的服务,因此Spring使用事务JDK动态代理来包装您的服务bean,该代理实现与您的bean相同的接口,但不是WorkflowService
。这就是为什么当您尝试将其分配给ClassCastException
变量时获得WorkflowService
的原因。我看到两种可能的解决方案:
使用您的业务方法指定接口WorkflowService
并在WorkflowServiceImpl
类中实现它。然后在Spring上下文中将bean定义从WorkflowService
更改为WorkflowServiceImpl
。这是我推荐的,作为一般设计原则,特别是在Spring环境中工作:Spring喜欢接口。
在Spring上下文中,将proxy-target-class="true"
添加到<tx:annotation-driven/>
元素,以强制Spring通过子类化实现代理,以便proxy instanceof WorkFlowService
为真。我觉得这个解决方案比较脏。另请注意,您可以通过这种方式添加对CGLIB的依赖。