2016-08-16 63 views
0

我正在將我們的webapp中使用的spring framework版本從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類:

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

這就是:

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; 
}  
} 

的測試與此異常失敗數學應用環境文件:

<?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> 

我也嘗試使用應用程序上下文加載豆,但失敗,出現以下異常:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'mathematicalKernelPool' is defined 

如果我刪除了自動裝配Autowired場,測試失敗了NoSuchBeanDefinitionException爲另一個通過應用程序上下文在超類中加載的bean(mathService)。因此,出於某種原因,數學應用程序上下文中的應用程序上下文似乎未加載。想知道這裏會發生什麼?謝謝。

UPDATE:

我看了一下在應用程序上下文中定義的豆類和證實,沒有在數學應用上下文定義的豆子都存在。應用程序上下文僅包含由超類加載的另一個上下文文件中定義的Bean。爲什麼它無法加載數學應用程序上下文?

+0

你可以發佈KernelLinkPool類嗎?您可能還需要添加KernelLinkPool類的依賴項。 – Ogma

+0

@Autowired工作得很好,因爲它試圖注入bean。你會得到在類路徑中找不到這些bean的錯誤。檢查'base-package'是否包含所需的bean類。 – 11thdimension

+0

加入KernelLinkPool.class – MatH

回答

0

這是一個配置文件問題。超一流的試驗使用:

@ProfileValueSourceConfiguration(TestProfileValueSource.class)

將情景模式設置,但它不能正常工作。刪除註釋後,我補充說:

@ActiveProfiles(resolver = TestProfileValueSource.class),現在它再次工作。

0

在這一點上,我會誠實地擺脫XML配置,並去基於總註釋/代碼。創建一個Config類並讓它創建需要自動裝配的任何bean。

+0

作爲評論比答案更好。 – chrylis

相關問題