应用上下文bean

时间:2011-03-07 20:52:41

标签: java spring

我正在尝试从应用程序上下文中提取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) {
   }    
}

3 个答案:

答案 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的依赖。