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