简体   繁体   English

应用上下文bean

[英]Application context bean

I am trying to extract the bean from application context. 我试图从应用程序上下文中提取bean。

so I defined class: 所以我定义了类:

public class ApplicationContextProvider implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
    public void setApplicationContext(ApplicationContext _applicationContext) throws BeansException {
        applicationContext = _applicationContext;

    }

}

and in my applicationContext.xml 在我的applicationContext.xml中

<bean id="workflowService" class="com.mycompany.util.WorkflowService">
    <bean id="applicationContextProvider" class="com.mycompany.util.ApplicationContextProvider"></bean>
   <context:annotation-config />

However in my code when I try: 但是,当我尝试时,在我的代码中:

WorkflowService service  = (WorkflowService) ApplicationContextProvider.getApplicationContext().getBean("workflowService");

I get: 我明白了:

java.lang.ClassCastException: $Proxy40 cannot be cast to com.mycompany.util.WorkflowService java.lang.ClassCastException:$ Proxy40无法强制转换为com.mycompany.util.WorkflowService

EDITED : 编辑

WorkflowService code: WorkflowService代码:

public class WorkflowService implements Serializable {
   ...
   @PostConstruct
       public void init() {
   }
   ...
   @Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
       public Collection<lData> findData(Integer contractId) {
   }    
}

Your problem is this bit: 你的问题是这样的:

WorkflowService implements Serializable

Any proxies that Spring generates will implement all of the interfaces that your class does - in this case, Serializable , which is almost certainly not what you want. Spring生成的任何代理都将实现您的类所做的所有接口 - 在本例中为Serializable ,这几乎肯定不是您想要的。

What you should do is extract a new interface from WorkflowService , which includes the findData method (let's call it WorkflowOperations ). 你应该做的是从WorkflowService提取一个新接口,它包含findData方法(我们称之为WorkflowOperations )。 By implementing that interface, you'll then be able to cast to that interface, eg 通过实现该接口,您将能够转换到该接口,例如

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) {
    }

}

and then: 接着:

 WorkflowOperations service  = (WorkflowOperations) ApplicationContextProvider.getApplicationContext().getBean("workflowService");

You should probably also remove Serializable from WorkflowService . 您可能还应该从WorkflowService删除Serializable You almost certainly don't need this, it makes no sense to serialize Spring beans like this. 你几乎肯定不需要这个,像这样序列化Spring bean是没有意义的。 If you just added Serializable out of habit, then remove it (and get out of that particular habit). 如果您刚刚添加了Serializable的习惯,那么将其删除(并摆脱这种特殊习惯)。

I guess WorkflowService is a class implementing at least one interface (you haven't provided enough code). 我想WorkflowService是一个实现至少一个接口的类(你没有提供足够的代码)。 You are trying to lookup the exact class from Spring, while you should ask for one of the interfaces. 您正在尝试从Spring查找确切的类,而您应该要求其中一个接口。

This is because Spring most of the time wraps beans in several proxies (eg transactional ones). 这是因为Spring大部分时间都将bean包装在几个代理中(例如事务代理)。 If the class implements at least one interface, resulting proxy implements all of them, but cannot be cast into original class. 如果类实现至少一个接口,则生成的代理实现所有接口,但不能转换为原始类。 If the class does not implement any interfaces (commonly considered a bad practice for heavyweight services, questionable though), Spring will use CGLIB subclassing from original class. 如果类没有实现任何接口(通常被认为是重量级服务的不良做法,尽管有问题),Spring将使用原始类的CGLIB子类。 In this case you code would be valid. 在这种情况下,您的代码将是有效的。

You are annotating your service with @Transactional , so Spring is wrapping your service bean with a transactional JDK dynamic proxy that implements the same interfaces as your bean, but is not a WorkflowService . 您正在使用@Transactional注释您的服务,因此Spring使用事务JDK动态代理来包装您的服务bean,该代理实现与您的bean相同的接口,但不是WorkflowService That is why you get a ClassCastException when you try to assign it to a WorkflowService variable. 这就是当您尝试将其分配给WorkflowService变量时获得ClassCastException原因。 I see two possible solutions: 我看到两种可能的解决方案

  • Specify an interface WorkflowService with your business methods and implement it in a WorkflowServiceImpl class. 使用业务方法指定WorkflowService接口,并在WorkflowServiceImpl类中实现它。 Then in the Spring context change the bean definition from WorkflowService to WorkflowServiceImpl . 然后在Spring上下文中将bean定义从WorkflowService更改为WorkflowServiceImpl This is what I recommend, both as a general design principle and specially to work in a Spring environment: Spring likes interfaces. 这是我推荐的,作为一般设计原则,特别是在Spring环境中工作:Spring喜欢接口。

  • In your Spring context, add proxy-target-class="true" to your <tx:annotation-driven/> element in order to force Spring to implement proxies by subclassing, so that proxy instanceof WorkFlowService is true. 在Spring上下文中,将proxy-target-class="true"<tx:annotation-driven/>元素中,以强制Spring通过子类化实现代理,以便proxy instanceof WorkFlowService为true。 I find this solution dirtier. 我觉得这个解决方案比较脏。 Also note that you add a dependency on CGLIB this way. 另请注意,您通过这种方式添加CGLIB依赖项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM