简体   繁体   English

com.sun.proxy。$ Proxy219无法使用Java Config进行强制转换,但可以与xml一起正常使用

[英]com.sun.proxy.$Proxy219 cannot be cast using Java Config but it's working fine with xml

I'm migrating a Couchbase cache manager configuration from our legacy xml to a Java Config. 我正在将Couchbase缓存管理器配置从我们的旧xml迁移到Java Config。

But I'm getting a java.lang.ClassCastException: com.sun.proxy.$Proxy219 cannot be cast to atorrico.cache.CouchbaseCache. 但是我得到了一个java.lang.ClassCastException:com.sun.proxy。$ Proxy219无法转换为atorrico.cache.CouchbaseCache。

This is the XML file 这是XML文件

<context:annotation-config />

<cache:annotation-driven />

<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
    <property name="caches">
        <set>
            <ref local="mainCache" />
        </set>
    </property>
</bean>

<bean id="mainCache" class="atorrico.cache.CouchbaseCache" destroy-method="shutdown">
    <constructor-arg index="0" value="${cache.main.name}" />
    <constructor-arg index="1" value="${cache.servers}" />
    <constructor-arg index="2" value="${cache.main.bucket.name}" />
    <constructor-arg index="3" value="${cache.main.bucket.password}" />
    <constructor-arg index="4" ref="couchbaseJaxb2Transcoder" />
    <constructor-arg index="5" value="${cache.main.ttl}" />
    <property name="operationTimeoutMillis" value="${cache.main.operationTimeoutMillis}" />
    <property name="clientResetIntervalSeconds" value="${cache.main.clientResetIntervalSeconds}" />
    <property name="enabled" value="${cache.main.enabled}" />
</bean>

<bean id="couchbaseJaxb2Transcoder" class="atorrico.couchbase.CouchbaseJaxb2Transcoder">
   <property name="marshaller" ref="cacheJaxb2Marshaller" />
</bean>

<bean id="cacheJaxb2Marshaller" class="atorrico.couchbase.TweakedJaxb2Marshaller">
    <property name="contextPath"
        value="${cache.main.contextPath}" />
</bean>

This is the Java Config file 这是Java Config文件

@Configuration
@EnableCaching
@EnableMBeanExport
public class CacheConfiguration {
    @Value("${cache.main.name}")
    private String mainCacheName;

    @Value("${cache.servers}")
    private String mainCacheServers;

    @Value("${cache.main.bucket.name}")
    private String mainCacheBucketName;

    @Value("${cache.main.bucket.password}")
    private String mainCacheBucketPassword;

    @Value("${cache.main.ttl}")
    private Integer mainCacheTtl;

    @Value("${cache.main.operationTimeoutMillis}")
    private Integer mainCacheOperationTimeoutMillis;

    @Value("${cache.main.clientResetIntervalSeconds : -1}")
    private Integer mainClientResetIntervalSeconds;

    @Value("${cache.main.enabled}")
    private Boolean mainCacheEnabled;

    @Value("${cache.main.operation.queue.length : -1}")
    private Integer mainCacheOperationQueueLength;

    @Value("${cache.main.contextPath}")
    private Integer mainCacheContextPath;

    @Bean
    public CacheManager cacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        cacheManager.setCaches(Arrays.asList(mainCouchbaseCache()));
        return cacheManager;
    }

    @Bean(name = "mainCache", destroyMethod = "shutdown")
    @Qualifier("mainCache")
    public CouchbaseCache mainCouchbaseCache() {
        CouchbaseCache couchbaseClient = new CouchbaseCache(mainCacheName, mainCacheServers, mainCacheBucketName, mainCacheBucketPassword,
                mainCouchbaseJaxb2Transcoder(), mainCacheTtl);

        couchbaseClient.setOperationTimeoutMillis(mainCacheOperationTimeoutMillis);
        couchbaseClient.setClientResetIntervalSeconds(mainClientResetIntervalSeconds);
        couchbaseClient.setEnabled(mainCacheEnabled);
        couchbaseClient.setOperationQueueLength(mainCacheOperationQueueLength);
        return couchbaseClient;
    }

    @Bean(name = "mainCouchbaseJaxb2Transcoder")
    public CouchbaseJaxb2Transcoder mainCouchbaseJaxb2Transcoder() {

        CouchbaseJaxb2Transcoder couchbaseJaxb2Transcoder = new CouchbaseJaxb2Transcoder();
        couchbaseJaxb2Transcoder.setMarshaller(mainJaxb2Marshaller());
        return couchbaseJaxb2Transcoder;
    }

    @Bean(name = "mainJaxb2Marshaller")
    public TweakedJaxb2Marshaller mainJaxb2Marshaller() {

        TweakedJaxb2Marshaller txStoreJaxb2Marshaller = new TweakedJaxb2Marshaller();
        txStoreJaxb2Marshaller.setContextPath(mainCacheContextPath);
        return txStoreJaxb2Marshaller;
    }

I think the only difference between both version is that in the xml I have a 我认为两个版本之间的唯一区别是在xml中,

<ref local="mainCache" />

Note the use of local instead bean. 注意使用本地而不是bean。

This is the hierarchy of java classes for the Couchbase client. 这是Couchbase客户端的Java类的层次结构。

public interface CouchbaseClient {

....

}

public interface CouchbaseClientManagement {

....

}

public class CouchbaseClientImpl implements CouchbaseClient, CouchbaseClientManagement {

.....

}

public class CouchbaseCache extends CouchbaseClientImpl implements Cache, CouchbaseClientManagement {

....

}

This is the trace 这是痕迹

Caused by: java.lang.ClassCastException: com.sun.proxy.$Proxy219 cannot be cast to atorrico.cache.CouchbaseCache
at atorrico.cache.configuration.CacheConfiguration$$EnhancerBySpringCGLIB$$dd4e20b8.mainCouchbaseCache(<generated>)
at atorrico.cache.configuration.CacheConfiguration.cacheManager(CacheConfiguration.java:76)
at atorrico.cache.configuration.CacheConfiguration$$EnhancerBySpringCGLIB$$dd4e20b8.CGLIB$cacheManager$0(<generated>)
at atorrico.cache.configuration.CacheConfiguration$$EnhancerBySpringCGLIB$$dd4e20b8$$FastClassBySpringCGLIB$$a8a6f2da.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:309)
at atorrico.cache.configuration.CacheConfiguration$$EnhancerBySpringCGLIB$$dd4e20b8.cacheManager(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
... 67 more

Why is this failing with Java Config but working fine with the XML config? 为什么这在Java Config上失败了,但是在XML Config上却可以正常工作?

Can anyone find out what's going on here? 谁能知道这是怎么回事?

Thanks! 谢谢!

Spring has enhanced your CacheConfiguration class with some extra byte code. Spring通过一些额外的字节码增强了CacheConfiguration类。 It's probably done this by creating a proxy that is a subclass of CacheConfiguration. 可以通过创建作为CacheConfiguration子类的代理来完成此操作。 You can see this in your stack trace as the class CacheConfiguration$$EnhancerBySpringCGLIB$$dd4e20b8. 您可以在堆栈跟踪中将此作为类CacheConfiguration $$ EnhancerBySpringCGLIB $$ dd4e20b8看到。

When Spring instantiates the CacheManager, it first calls down through the cacheManager method it generated in the subclass, then calls your original cacheManager method, which calls the mainCouchbaseCache method. 当Spring实例化CacheManager时,它首先通过在子类中生成的cacheManager方法进行调用,然后调用原始的cacheManager方法,该方法调用mainCouchbaseCache方法。

Here's where it starts to get interesting. 这就是开始变得有趣的地方。 Your cacheManager method invokes not your mainCouchbaseCache method, but rather the generated one in the subclass. 您的cacheManager方法不是调用mainCouchbaseCache方法,而是调用子类中生成的方法。 The generated method calls your mainCouchbaseCache, and your method generates the CouchbaseCache object and returns it. 生成的方法调用mainCouchbaseCache,您的方法生成CouchbaseCache对象并返回它。 After your method returns, control returns to the generated subclass, which then wraps the returned CouchbaseCache in a generated proxy . 方法返回后,控制权返回到生成的子类,然后子类将返回的CouchbaseCache包装在生成的proxy中

I'm not sure why Spring is generating the proxy, but for some reason it's decided that it needs to intercept calls to the methods of CouchbaseCache. 我不确定为什么Spring会生成代理,但是由于某种原因,它决定需要拦截对CouchbaseCache方法的调用。

The problem is that because CouchbaseCache implements some interfaces, Spring creates a JDK dynamic proxy, and a limitation of JDK dynamic proxies is that they can only implement interfaces, not extend classes. 问题在于,因为CouchbaseCache实现了某些接口,所以Spring创建了JDK动态代理,而JDK动态代理的局限性在于它们只能实现接口,而不能扩展类。 (They extend java.lang.reflect.Proxy.) So the value that your cacheManager method sees returned from the mainCouchbaseCache method is not an instance of CouchbaseCache but rather an instance of some subclass of java.lang.reflect.Proxy that implements the Cache and CouchbaseClientManagement interfaces. (它们扩展了java.lang.reflect.Proxy。)因此,您的cacheManager方法看到的是从mainCouchbaseCache方法返回的值不是CouchbaseCache的实例,而是实现了Cache的java.lang.reflect.Proxy的某些子类的实例。和CouchbaseClientManagement接口。

This works with the XML bean file because there is no Spring-generated proxy messing with the return value of the mainCouchbaseCache method. 这适用于XML bean文件,因为没有Spring生成的代理与mainCouchbaseCache方法的返回值混淆。

I think you can fix this just by making mainCouchbaseCache return Cache instead of CouchbaseCache. 我认为您可以通过使mainCouchbaseCache返回Cache而不是CouchbaseCache来解决此问题。 Then at compile time Arrays.asList will expect a Cache array instead of a CouchbaseCache array, and since the returned proxy will implement Cache, everything will work. 然后,在编译时,Arrays.asList将期待一个Cache数组而不是CouchbaseCache数组,并且由于返回的代理将实现Cache,所以一切都会正常。

Or you can tell Spring to not use a JDK dynamic proxy; 或者,您可以告诉Spring不要使用JDK动态代理。 see the Spring documentation on how it generates proxies . 有关如何生成代理的信息,请参见Spring文档 I think you want to use proxy-target-class=true, which will tell Spring to use CGLIB to generate an actual subclass CouchbaseCache. 我认为您想使用proxy-target-class = true,它将告诉Spring使用CGLIB生成实际的子类CouchbaseCache。

暂无
暂无

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

相关问题 java.lang.ClassCastException:com.sun.proxy。$ Proxy219无法转换为org.springframework.data.redis.connection.StringRedisConnection - java.lang.ClassCastException: com.sun.proxy.$Proxy219 cannot be cast to org.springframework.data.redis.connection.StringRedisConnection com.sun.proxy.$Proxy439 无法强制转换为 DDLRecordSetLocalService - com.sun.proxy.$Proxy439 cannot be cast to DDLRecordSetLocalService com.sun.proxy。$ Proxy1无法转换为 - com.sun.proxy.$Proxy1 cannot be cast to com.sun.proxy。$ Proxy0无法转换为 - com.sun.proxy.$Proxy0 cannot be cast to com.sun.proxy.$proxy0 无法转换为 XXX - com.sun.proxy.$proxy0 cannot be cast to XXX java.lang.ClassCastException:com.sun.proxy。$ Proxy1无法转换为 - java.lang.ClassCastException: com.sun.proxy.$Proxy1 cannot be cast to java.lang.ClassCastException:com.sun.proxy。$ Proxy47无法转换为 - java.lang.ClassCastException: com.sun.proxy.$Proxy47 cannot be cast to RMI:java.lang.ClassCastException:com.sun.proxy。$ Proxy1无法转换为Funktion - RMI: java.lang.ClassCastException: com.sun.proxy.$Proxy1 cannot be cast to Funktion ClassCastException:com.sun.proxy.$ProxyX 无法转换为类 - ClassCastException: com.sun.proxy.$ProxyX cannot be cast to a class java.lang.ClassCastException:com.sun.proxy。$ Proxy29无法转换为com.frodo.questionbank.service.impl.QuestionService - java.lang.ClassCastException: com.sun.proxy.$Proxy29 cannot be cast to com.frodo.questionbank.service.impl.QuestionService
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM