【问题标题】:Application context not loading after Spring 4 upgradeSpring 4 升级后未加载应用程序上下文
【发布时间】:2016-12-23 08:12:17
【问题描述】:

我正在将我们的 webapp 中使用的 spring 框架版本从 3.1.4 升级到 4.1.8。在新的 Spring 版本中,我们的一些单元测试失败了,因为 @Autowired 不再工作。这是失败的测试之一:

@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,但失败并出现以下异常:

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

如果我删除自动装配字段,则测试会失败,并显示另一个 bean (mathService) 的 NoSuchBeanDefinitionException,该 bean (mathService) 通过超类中的应用程序上下文加载。因此,由于某种原因,math-application-context 中的应用程序上下文似乎没有加载。知道这里会发生什么吗?谢谢。

更新:

我查看了应用程序上下文中定义的 bean,并确认 math-application-context 中定义的 bean 都不存在。应用程序上下文仅包含由超类加载的另一个上下文文件中定义的 bean。为什么会加载数学应用上下文失败?

【问题讨论】:

  • 你能发布课程 KernelLinkPool 吗?您可能还需要添加 KernelLinkPool 类的依赖项。
  • @Autowired 工作得非常好,因为它正在尝试注入 bean。您收到在类路径中找不到这些 bean 的错误。检查base-package 是否包含所需的bean 类。
  • 添加了 KernelLinkPool.class
  • 我认为它是这篇文章的副本stackoverflow.com/questions/20333147/…
  • 是的,我看到了那个帖子。这与春季迁移有关,所以我认为它需要自己的线程。它适用于弹簧 3

标签: java spring


【解决方案1】:

这是个人资料问题。测试的超类正在使用:

@ProfileValueSourceConfiguration(TestProfileValueSource.class)

设置配置文件,但它不起作用。删除该注释后,我添加了:

@ActiveProfiles(resolver=TestProfileValueSource.class) 现在它又可以工作了。

【讨论】:

    【解决方案2】:

    在这一点上,我会诚实地摆脱 XML 配置并完全基于注释/代码。创建一个 Config 类并让它创建您需要自动装配的任何 bean。

    【讨论】:

    • 作为评论比作为答案更好。
    猜你喜欢
    • 2017-12-08
    • 1970-01-01
    • 1970-01-01
    • 2011-05-13
    • 1970-01-01
    • 2015-02-19
    • 2021-06-23
    • 2023-04-09
    • 1970-01-01
    相关资源
    最近更新 更多