Webアプリケーションで使用されているSpringフレームワークのバージョンを3.1.4から4.1.8にアップグレードしています。新しいSpringバージョンでは、@Autowiredが動作しなくなったため、単体テストのいくつかが失敗しています。これは、失敗テストの一つである:Spring 4のアップグレード後にアプリケーションコンテキストがロードされない
@ContextConfiguration(locations={"/math-application-context.xml"})
public class MathematicaMathServiceTest extends JavaMathServiceTest{
@Autowired
private KernelLinkPool mathematicalKernelPool;
protected static String originalServiceType = System.getProperty("calculation.math.service.type");
@AfterClass
public static void unsetMathServiceType(){
System.clearProperty("calculation.math.service.type");
}
@BeforeClass
public static void setMathServiceType(){
System.setProperty("calculation.math.service.type","Mathematica");
}
@Test
public void testMathematicaService() throws Exception{
try {
acquireKernelAndExecute(0);
Assert.assertEquals(0, mathematicalKernelPool.getBorrowingThreadsCount());
} catch(UnsatisfiedLinkError e) {
System.out.println("Mathematica not installed. Skipping test");
}catch(Exception ex){
if (!ExceptionFormatter.hasCause(ex, MathServiceNotConfiguredException.class)){throw ex;}
if (System.getProperty(MathService.SERVICE_CONFIGURED_SYSTEM_VARIABLE) != null){
throw ex;
}
logger.error("Cannot execute test. Math service is not configured");
}
}
}
これはKernelLinkPoolクラスである:
public class KernelLinkPool extends GenericObjectPool implements InitializingBean{
private static final int RETRY_TIMEOUT_MS = 5000;
private static final long STARTUP_WAIT_TIME_MS = 10000;
private boolean mathematicaConfigured = true;
private PoolableObjectFactory factory;
// ensures that multiple requests from the same thread will be given the same KernelLink object
private static ThreadLocal<KernelLink> threadBoundKernel = new ThreadLocal<KernelLink>();
// holds the number of requests issued on each thread
private static ThreadLocal<Integer> callDepth = new ThreadLocal<Integer>();
private long maxBorrowWait;
private Integer maxKernels;
private boolean releaseLicenseOnReturn;
private Logger logger = LoggerFactory.getLogger(this.getClass());
// (used only for unit testing at this point)
private Map<String,Integer> borrowingThreads = new ConcurrentHashMap<String,Integer>();
public KernelLinkPool(PoolableObjectFactory factory) {
super(factory);
this.factory = factory;
this.setMaxWait(maxBorrowWait);
}
@Override
public Object borrowObject() throws Exception{
return borrowObject(this.maxBorrowWait);
}
public Object borrowObject(long waitTime) throws Exception {
long starttime = System.currentTimeMillis();
if (!mathematicaConfigured){
throw new MathServiceNotConfiguredException();
}
try{
if (callDepth.get() == null){
callDepth.set(1);
}else{
callDepth.set(callDepth.get()+1);
}
KernelLink link = null;
if (threadBoundKernel.get() != null){
link = threadBoundKernel.get();
}else{
//obtain kernelLink from object pool
//retry when borrowObject fail until
//maxBorrowWait is reached
while(true){
try{
logger.debug("Borrowing MathKernel from object pool");
link = (KernelLink) super.borrowObject();
break;
}catch(KernelLinkCreationException ex){
long timeElapsed = System.currentTimeMillis() - starttime;
logger.info("Failed to borrow MathKernel. Time elapsed [" + timeElapsed + "] ms", ex);
if(timeElapsed >= waitTime){
logger.info("Retry timeout reached");
throw ex;
}
Thread.sleep(RETRY_TIMEOUT_MS);
}
}
logger.debug("borrowed [" + link + "]");
threadBoundKernel.set(link);
}
borrowingThreads.put(Thread.currentThread().getName(),callDepth.get());
return link;
}catch(Exception ex){
logger.error("Failed to acquire Mathematica kernel. Borrowing threads [" + borrowingThreads + "]");
throw ex;
}
}
public void returnObject(Object obj) throws Exception {
callDepth.set(callDepth.get()-1);
if (callDepth.get() <= 0){
threadBoundKernel.set(null);
borrowingThreads.remove(Thread.currentThread().getName());
if (releaseLicenseOnReturn){
// will destroy obj
super.invalidateObject(obj);
}
else{
// will park obj in the pool of idle objects
super.returnObject(obj);
}
}else{
borrowingThreads.put(Thread.currentThread().getName(),callDepth.get());
}
}
@Override
public void afterPropertiesSet() throws Exception {
try{
if (maxKernels == 0){
List<KernelLink> links = new ArrayList<KernelLink>();
while (true){
try{
links.add((KernelLink)factory.makeObject());
}catch(KernelLinkCreationException ex){
break;
}
}
if(links.isEmpty()){
logger.warn("No available Mathematica license!");
mathematicaConfigured = false;
return;
}
for (KernelLink link : links){
factory.destroyObject(link);
}
logger.info("Detected number of available Mathematica license = [" + links.size() + "]");
setMaxActive(links.size());
setMaxIdle(links.size());
}else{
if(maxKernels < 0){
logger.info("Set number of Mathematica license to no limit");
}else{
logger.info("Set number of Mathematica license to [" + maxKernels + "]");
}
setMaxActive(maxKernels);
setMaxIdle(maxKernels);
}
Object ob = borrowObject(STARTUP_WAIT_TIME_MS);
returnObject(ob);
mathematicaConfigured = true;
}catch(Throwable ex){
logger.warn("Mathematica kernel pool could not be configured: ", ex.getMessage());
mathematicaConfigured = false;
}
}
public int getBorrowingThreadsCount() {
return borrowingThreads.size();
}
public Integer getMaxKernels() {
return maxKernels;
}
public void setMaxKernels(Integer maxKernels) {
this.maxKernels = maxKernels;
}
public boolean isMathematicaConfigured(){
return mathematicaConfigured;
}
public boolean isReleaseLicenseOnReturn() {
return releaseLicenseOnReturn;
}
public void setReleaseLicenseOnReturn(boolean releaseLicenseOnReturn) {
this.releaseLicenseOnReturn = releaseLicenseOnReturn;
}
public long getMaxBorrowWait() {
return maxBorrowWait;
}
public void setMaxBorrowWait(long maxBorrowWait) {
this.maxBorrowWait = maxBorrowWait;
}
}
試験はこの例外で失敗している:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.etse.math.wolfram.KernelLinkPool] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
であります数学アプリケーションコンテキストファイル:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<beans profile="unitTest,integratedTest,activeServer">
<bean class="org.springframework.jmx.export.MBeanExporter"
lazy-init="false">
<property name="registrationBehaviorName" value="REGISTRATION_IGNORE_EXISTING" />
<property name="beans">
<map>
<entry key="etse.math:name=MathematicalKernelFactory"
value-ref="mathematicalKernelFactory" />
<entry key="etse.math:name=MathematicalKernelPool" value-ref="mathematicalKernelPool" />
</map>
</property>
</bean>
<bean id="mathService" class="com.etse.math.MathServiceFactoryBean">
<property name="mathServiceType" value="${calculation.math.service.type}"/>
<property name="mathematicaService" ref="mathematicaService"/>
</bean>
<bean id="mathematicaService" class="com.etse.math.wolfram.MathematicaService">
<property name="kernelPool" ref="mathematicalKernelPool" />
<property name="minParallelizationSize" value="${calculation.mathematica.kernel.parallel.batch.size}" />
</bean>
<bean id="mathematicalKernelPool" class="com.etse.math.wolfram.KernelLinkPool"
destroy-method="close">
<constructor-arg ref="mathematicalKernelFactory" />
<property name="maxKernels" value="${calculation.mathematica.max.kernels}" />
<property name="maxBorrowWait"
value="${calculation.mathematica.kernel.borrow.max.wait}" />
<property name="releaseLicenseOnReturn"
value="${calculation.mathematica.kernel.release.license.on.return}" />
</bean>
<bean id="mathematicalKernelFactory" class="com.etse.math.wolfram.KernelLinkFactory">
<property name="debugPackets" value="false" />
<property name="linkMode" value="launch" />
<property name="mathematicaKernelLocation" value="${calculation.mathematica.kernel.location}" />
<property name="mathematicaLibraryLocation" value="${calculation.mathematica.library.location}" />
<property name="mathematicaAddOnsDirectory" value="${calculation.mathematica.addons.directory}" />
<property name="linkProtocol" value="sharedMemory" />
</bean>
</beans>
<beans profile="passiveServer,thickClient,tools">
<bean id="mathService" class="com.etse.math.DummyMathService"/>
</beans>
私はまた、Beanをロードするために、アプリケーション・コンテキストを使用してみましたが、それは次の例外で失敗しました:私はautowiredフィールドを削除した場合
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'mathematicalKernelPool' is defined
、テストをするためにNoSuchBeanDefinitionExceptionで失敗スーパークラスのアプリケーションコンテキストを介してロードされる別のBean(mathService)。したがって、何らかの理由で、math-application-contextのアプリケーションコンテキストがロードされていないようです。ここで何が起こっているのだろうか?ありがとうございました。
UPDATE:
私は、アプリケーションコンテキストで定義された豆を見ていたし、数学・アプリケーション・コンテキストで定義された豆のいずれも存在しないことを確認しました。アプリケーション・コンテキストには、スーパー・クラスによってロードされた別のコンテキスト・ファイルで定義されたBeanのみが含まれます。数学アプリケーションのコンテキストを読み込めないのはなぜですか?
KernelLinkPoolクラスを投稿できますか? KernelLinkPoolクラスの依存関係も追加する必要があります。 – Ogma
@Autowiredは豆を注入しようとしているので、完璧に動作しています。これらのBeanがクラスパス上に見つからないというエラーが表示されます。 'base-package'に必要なBeanクラスが含まれているかどうか確認してください。 – 11thdimension
KernelLinkPool.classを追加しました – MatH