アプリケーションコンテキストからSpring Beanをプルする際に問題があります。
やってみると
InnerThread instance = (InnerThread) SpringContextFactory.getApplicationContext().getBean("innerThread", InnerThread.class);
私が得る;
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'innerThread' must be of type [com.generic.InnerThread], but was actually of type [$Proxy26]
GetBean()呼び出しで指定されたクラスがないと、ClassCastExceptionが発生します(詳細は以下で確認できます)。
複数のインスタンスが必要なため、InnerThread Beanは非シングルトンとして初期化されています。 InnerThreadクラスはThreadも拡張します。興味深いのは、このエラーが、InnerThreadとまったく同じ方法で設定されるOuterThread内に表示されることです。
以下の関連するすべてのコードリスト/スタックトレースを含めようとしました。より多くの春の経験を持つ誰かが私にここで何が起こっているのか教えてもらえますか?
OuterThread.Javaスニペット:
public class OuterThread extends Thread {
private Queue<InnerThread> createInnerThreads() {
Queue<InnerThread> threads = new ArrayBlockingQueue();
ApplicationContext ctx = SpringContextFactory.getApplicationContext();
int i = 0;
for (SearchRule search : searches) {
logger.debug("Number of times looped " + i++);
//Seprated lines to get a better sense of what is going on
Object proxy = ctx.getBean("innerThread", InnerThread.class);
logger.debug(ReflectionToStringBuilder.toString(proxy));
logger.debug("proxy.getClass(): " + proxy.getClass());
logger.debug("proxy.getClass().getClassLoader(): " + proxy.getClass().getClassLoader());
logger.debug("proxy.getClass().getDeclaringClass(): " + proxy.getClass().getDeclaringClass());
logger.debug("InnerThread.class.getClassLoader(): " + InnerThread.class.getClassLoader());
//---Exception here---
InnerThread cst = (InnerThread) proxy;
threads.add(cst);
}
return threads;
}
public static void main(String[] args) throws Exception {
try {
OuterThread instance = (OuterThread) SpringContextFactory.getApplicationContext().getBean("outerThread", OuterThread.class);
instance.run();
} catch (Exception ex) {
logger.error("Fatal exception.", ex);
throw ex;
}
}
}
SpringContextFactory.Java:
public class SpringContextFactory {
static final Logger logger = LoggerFactory.getLogger(SpringContextFactory.class);
private static ApplicationContext ctx;
private static final String DEFAULT_PATH = "META-INF/app-context.xml";
public static ApplicationContext getApplicationContext() {
return getApplicationContext(DEFAULT_PATH);
}
public static synchronized ApplicationContext getApplicationContext(String path) {
if (ctx == null) return createApplicationContext(path);
else return ctx;
}
private static ApplicationContext createApplicationContext(String path) {
if (logger.isDebugEnabled()) logger.debug("Loading Spring Context...");
ctx = new ClassPathXmlApplicationContext(path);
if (logger.isDebugEnabled()) logger.debug("Spring Context Loaded");
return ctx;
}
}
app-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!-- persistence context from separate jar -->
<import resource="persistence-context.xml"/>
<bean id="outerThread" class="com.generic.OuterThread" scope="prototype"/>
<bean id="innerThread" class="com.generic.InnerThread" scope="prototype"/>
</beans>
2009-05-08 14:34:37,341 [main] DEBUG com.generic.OuterThread.init(OuterThread.Java:59) - Initializing OuterThread object, com.generic.OuterThread@1c8fb4b[em=org.hibernate.ejb.EntityManagerImpl@e2892b,currentTime=Java.util.GregorianCalendar[time=1241634874841,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=Sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=Java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2009,MONTH=4,WEEK_OF_YEAR=19,WEEK_OF_MONTH=2,DAY_OF_MONTH=6,DAY_OF_YEAR=126,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=2,HOUR_OF_DAY=14,MINUTE=34,SECOND=34,MILLISECOND=841,ZONE_OFFSET=-18000000,DST_OFFSET=3600000],maxConcurrentThreads=5,reconId=3,reportUsername=TEST,useOffset=false,username=removed,uuid=bf61494d-ff96-431c-a41f-1e292d0c9fbe,name={T,h,r,e,a,d,-,1},priority=5,threadQ=<null>,eetop=0,single_step=false,daemon=false,stillborn=false,target=<null>,group=Java.lang.ThreadGroup[name=main,maxpri=10],contextClassLoader=Sun.misc.Launcher$AppClassLoader@11b86e7,inheritedAccessControlContext=Java.security.AccessControlContext@1524d43,threadLocals=<null>,inheritableThreadLocals=Java.lang.ThreadLocal$ThreadLocalMap@2cbc86,stackSize=0,nativeParkEventPointer=0,tid=9,threadStatus=0,parkBlocker=<null>,blocker=<null>,blockerLock=Java.lang.Object@a68fd8,stopBeforeStart=false,throwableFromStop=<null>,uncaughtExceptionHandler=<null>]
2009-05-08 14:34:37,341 [main] DEBUG org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.doJoinTransaction(ExtendedEntityManagerCreator.Java:385) - No local transaction to join
2009-05-08 14:34:37,529 [main] DEBUG com.generic.OuterThread.createInnerThreads(OuterThread.Java:139) - Number of times looped 0
2009-05-08 14:34:37,529 [main] DEBUG org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.Java:458) - Creating instance of bean 'searchThread' with merged definition [Root bean: class [com.generic.InnerThread]; scope=prototype; abstract=false; lazyInit=false; autowireCandidate=true; autowireMode=0; dependencyCheck=0; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [META-INF/app-context.xml]]
2009-05-08 14:34:37,545 [main] DEBUG com.generic.InnerThread.<init>(InnerThread.Java:50) - Constructing InnerThread object, com.generic.InnerThread@1080876[em=<null>,coolScheme=<null>,coolUrl=<null>,date=<null>,error=<null>,millisecondsTaken=0,thresholdMet=false,reconId=0,result=-2,searchId=0,username=<null>,uuid=<null>,name={T,h,r,e,a,d,-,2},priority=5,threadQ=<null>,eetop=0,single_step=false,daemon=false,stillborn=false,target=<null>,group=Java.lang.ThreadGroup[name=main,maxpri=10],contextClassLoader=Sun.misc.Launcher$AppClassLoader@11b86e7,inheritedAccessControlContext=Java.security.AccessControlContext@1524d43,threadLocals=<null>,inheritableThreadLocals=Java.lang.ThreadLocal$ThreadLocalMap@3aef16,stackSize=0,nativeParkEventPointer=0,tid=10,threadStatus=0,parkBlocker=<null>,blocker=<null>,blockerLock=Java.lang.Object@126c6ea,stopBeforeStart=false,throwableFromStop=<null>,uncaughtExceptionHandler=<null>]
2009-05-08 14:34:37,545 [main] DEBUG org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.Java:203) - Returning cached instance of singleton bean 'entityManagerFactory'
2009-05-08 14:34:37,545 [main] DEBUG org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.Java:203) - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
2009-05-08 14:34:37,560 [main] DEBUG org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource.getTransactionAttribute(AbstractFallbackTransactionAttributeSource.Java:108) - Adding transactional method [report] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT]
2009-05-08 14:34:37,560 [main] DEBUG org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.buildAdvisors(AbstractAutoProxyCreator.Java:494) - Creating implicit proxy for bean 'searchThread' with 0 common interceptors and 1 specific interceptors
2009-05-08 14:34:37,560 [main] DEBUG org.springframework.aop.framework.JdkDynamicAopProxy.getProxy(JdkDynamicAopProxy.Java:113) - Creating JDK dynamic proxy: target source is SingletonTargetSource for target object [com.generic.InnerThread@1080876]
2009-05-08 14:34:37,591 [main] DEBUG com.generic.OuterThread.createInnerThreads(OuterThread.Java:141) - $Proxy26@1594a88[h=org.springframework.aop.framework.JdkDynamicAopProxy@1f0cf51]
2009-05-08 14:34:37,591 [main] DEBUG com.generic.OuterThread.createInnerThreads(OuterThread.Java:142) - proxy.getClass(): class $Proxy26
2009-05-08 14:34:37,591 [main] DEBUG com.generic.OuterThread.createInnerThreads(OuterThread.Java:143) - proxy.getClass().getClassLoader(): Sun.misc.Launcher$AppClassLoader@11b86e7
2009-05-08 14:34:37,591 [main] DEBUG com.generic.OuterThread.createInnerThreads(OuterThread.Java:144) - proxy.getClass().getDeclaringClass(): null
2009-05-08 14:34:37,591 [main] DEBUG com.generic.OuterThread.createInnerThreads(OuterThread.Java:145) - InnerThread.class.getClassLoader(): Sun.misc.Launcher$AppClassLoader@11b86e7
2009-05-08 14:34:37,591 [main] ERROR com.generic.OuterThread.run(OuterThread.Java:101) - Exception in OuterThread, ending reconciliation.
Java.lang.ClassCastException: $Proxy26 cannot be cast to com.generic.InnerThread
at com.generic.OuterThread.createInnerThreads(OuterThread.Java:148)
at com.generic.OuterThread.run(OuterThread.Java:65)
at com.generic.OuterThread.main(OuterThread.Java:170)
もう一度、これをデバッグしようと何時間も費やした後、StackOverflowに投稿した直後に答えを見つけました。
私の質問から省いた重要な点は、InnerThreadにトランザクションメソッドがあることです(申し訳ありませんが、これは無関係でした)。これは、OuterThreadとInnerThreadの重要な違いです。
Springのドキュメント から:
注意
複数のセクションは、実行時に単一の統合された自動プロキシクリエーターに折りたたまれ、どのセクション(通常は異なるXML Bean定義ファイルから)が指定した最も強力なプロキシ設定が適用されます。これはおよび要素にも適用されます。
明確にするために:on 'proxy-target-class = "true"'on、または要素は の使用を強制します3つすべてのCGLIBプロキシ 。
上記を私の構成に追加すると(persistance-context.xmlに基づいており、上記でロードされていることがわかります)、行が問題を修正しているようです。しかし、これは実際の解決策とは対照的に、迅速な修正の回避策になると思います。
私はここでいくつかのより深い問題を抱えていると思います、1つ目は、Springが完全に削除されたのと同じように混乱していることです。次に、スレッドを開始するために SpringのTaskExecutor を使用する必要があります。 3番目に、私のスレッドはThreadを拡張する代わりにRunnableを実装する必要があります(SO質問を参照)。
関連項目
@Configuration
クラスに注釈を付ける
@EnableAspectJAutoProxy(proxyTargetClass = true)
次の依存関係も追加する必要があります。
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.2</version>
</dependency>
この問題を解決する1つの方法は、実行可能なインターフェースを拡張して独自のインターフェースを作成することです。
public interface MyInterface extends Runnable {
// your own method declarations here
void doSomething();
...
}
次に、ランナブルの代わりにインターフェースを実装する必要があります:
@Component("myInterface")
@Scope("prototype")
public class MyInterfaceImpl implements MyInterface {
// your own method declarations here
public void doSomething(){
...
}
// implement run from Runnable Interface
@Transactional
public void run(){
.....
}
...
}
これはうまくいきます:
...
MyInterface mynterface = SpringApplicationContext.getBean("myInterface", MyInterface.class);
myInterface.doSomething();
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(myInterface);
...
これは単なる推測ですが、InnerThreadInterfaceインターフェースを作成してから、InnerThreadクラスにそれを拡張させてください。
その後、あなたはできるはずです:
InnerThreadInterface inner = ctx.getBean( "innerThread"、InnerThread.class);
私は同じ問題を抱えていました:
これは単なる推測ですが、InnerThreadInterfaceインターフェースを作成してから、InnerThreadクラスにそれを拡張させてください。その後、あなたはできるはずです:
私は上記に投稿されたものの代わりにこの方法を使用し、それはうまくいきました。 proxy-target-classをtrueに設定する必要はありませんでした。これには、クラスパスにないライブラリがさらに必要でした。
InnerThreadInterface inner = (InnerThreadInterface)ctx.getBean("innerThread");
CGLIBを参照し、proxy-target-class = "true"設定を使用したにもかかわらず、この問題が発生しました。私はehcache:annotationタグが原因であると判断しました...次の構成を削除すると、これが解決しました。幸い、ehcache宣言型キャッシュを使用する代わりに、休止状態のレベル2キャッシュを使用できました。
<ehcache:annotations>
<ehcache:caching id="myCacheModel" cacheName="myCache"/>
<ehcache:flushing id="myFlushModel" cacheNames="myCache" when="after"/>
</ehcache:annotations>
この問題を処理する別の方法は、インターフェイスを実装してSpringからインターフェイスを要求し、プロキシが完全にインターフェイスを実装し、キャストに問題がないことです。