如何在不杀死 VM 的情况下关闭和重新打开 Spring Data Neo4J 上下文

Posted

技术标签:

【中文标题】如何在不杀死 VM 的情况下关闭和重新打开 Spring Data Neo4J 上下文【英文标题】:How to close and re-open Spring Data Neo4J contexts without killing the VM 【发布时间】:2013-01-20 06:57:49 【问题描述】:

我正在运行一个 spring data neo-4j 应用程序(不是基于 Web 的),它在正常运行期间运行良好。

如果我关闭 Spring Context 'ctx.close()',neo 4J 数据库上的锁定就会消失。

然后,从应用程序的同一个实例中,如果我获取另一个上下文,我会看到锁回来了,但是如果我尝试从该上下文中读取/写入该数据库,则会收到错误:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.data.neo4j.config.Neo4jConfiguration#0': Unsatisfied dependency expressed through bean property 'conversionService': : Error creating bean with name 'mappingInfrastructure' defined in class org.springframework.data.neo4j.config.Neo4jConfiguration: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public final org.springframework.data.neo4j.support.MappingInfrastructureFactoryBean org.springframework.data.neo4j.config.Neo4jConfiguration$$EnhancerByCGLIB$$64cefd6f.mappingInfrastructure() throws java.lang.Exception] threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'typeRepresentationStrategyFactory' defined in class org.springframework.data.neo4j.config.Neo4jConfiguration: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public final org.springframework.data.neo4j.support.typerepresentation.TypeRepresentationStrategyFactory org.springframework.data.neo4j.config.Neo4jConfiguration$$EnhancerByCGLIB$$64cefd6f.typeRepresentationStrategyFactory() throws java.lang.Exception] threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'graphDatabaseService': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.neo4j.kernel.EmbeddedGraphDatabase]: Constructor threw exception; nested exception is java.lang.IllegalStateException: Unable to lock store [C:\app_data\gelato\data\neostore], this is usually a result of some other Neo4j kernel running using the same store.; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mappingInfrastructure' defined in class org.springframework.data.neo4j.config.Neo4jConfiguration: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public final org.springframework.data.neo4j.support.MappingInfrastructureFactoryBean org.springframework.data.neo4j.config.Neo4jConfiguration$$EnhancerByCGLIB$$64cefd6f.mappingInfrastructure() throws java.lang.Exception] threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'typeRepresentationStrategyFactory' defined in class org.springframework.data.neo4j.config.Neo4jConfiguration: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public final org.springframework.data.neo4j.support.typerepresentation.TypeRepresentationStrategyFactory org.springframework.data.neo4j.config.Neo4jConfiguration$$EnhancerByCGLIB$$64cefd6f.typeRepresentationStrategyFactory() throws java.lang.Exception] threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'graphDatabaseService': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.neo4j.kernel.EmbeddedGraphDatabase]: Constructor threw exception; nested exception is java.lang.IllegalStateException: Unable to lock store [C:\app_data\gelato\data\neostore], this is usually a result of some other Neo4j kernel running using the same store.

有没有办法在应用程序的单个实例中成功关闭然后重新打开应用程序上下文(即不关闭虚拟机)?

我最初是在图形数据库上调用 shutdown(),但后来改变了这一点,因为 Michael Hunger 告诉我不要这样做。

我们的问题可以像这样在我们的域中重现。

AbstractApplicationContext ctx = new FileSystemXmlApplicationContext("neo4jconfig.xml");
OurDomainService domainService = (OurDomainService) ctx.getBean(OurDomainServiceImpl.class);
// This works
domainService.save(data);
// this releases the lock
ctx.close();
// this re-creates the lock and the context looks actvive
ctx = new FileSystemXmlApplicationContext("neo4jconfig.xml");
domainService = (OurDomainService) ctx.getBean(OurDomainServiceImpl.class);
// this errors out
domainService.save(data);

这是我们用来创建上下文的 XML 文件。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/data/neo4j
http://www.springframework.org/schema/data/neo4j/spring-neo4j.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">

<context:spring-configured/>
    <context:annotation-config/>
    <context:component-scan base-package="OurData" />

    <neo4j:config storeDirectory="c:/app_data/data"/>
    <neo4j:repositories base-package="OurData"/>

</beans>

【问题讨论】:

您是否也正确关闭了WrappingNeoServerBootstrapper 是否可以在 github 上分享一个显示该行为的测试项目以进行检查? 可以使用 Bootstrapper 工作,但是当我们停止服务器时,复制另一个数据库来替换活动的。当我们再次启动它并向它请求数据时,似乎我们正在从旧数据库中获取结果,就像缓存一样? 很高兴 WrappingNeoServerBootstrapper 开始工作。复制另一个数据库以替换活动数据库是什么意思? 我们关闭,从FS中删除数据库文件,然后重新启动。 【参考方案1】:

您不应该这样做,在您的情况下,spring-context 应该处理生命周期。

在您的情况下重新启动时会发生什么?

您使用

关闭应用程序上下文
ctx.close()

您可能应该使用 WebApplicationContext(Utils) 通过 web.xml 获取配置的 Spring 上下文。像这样:

WebApplicationContext springContext = 
    WebApplicationContextUtils.getWebApplicationContext(getServletContext()); 

【讨论】:

我们没有将它托管在 Web 服务器中,只是单独运行,我使用 FileApplicationContext 并指向命令行提供的外部 xml。是一样的吗? ApplicationContext接口好像没有close()方法? 忽略我刚刚将 ctx 声明为“FileSystemXmlApplicationContext”,现在调用了 close ,但是当我尝试获取另一个上下文时,它给了我尝试开始时遇到的错误一台已经在运行的服务器。 从头开始,我抓取另一个上下文,当我尝试保存一个节点时,我得到:通过 bean 属性表达的不满足的依赖关系【参考方案2】:

查看我的最后一条评论和您的回复已经编辑了我的完整答案。

下面的两个主要文件。

第一个使用WrappingNeoServerBootstrapper

Neo4j 服务器的引导程序,它采用已经实例化的 @link org.neo4j.kernel.GraphDatabaseAPI 和可选配置,并启动一个 服务器使用该数据库。 使用它从应用程序中启动完整的 Neo4j 服务器 已经使用 @link EmbeddedGraphDatabase 或 @link HighAvailableGraphDatabase。这为您的应用程序提供了完整的 服务器的 REST API、Web 管理界面和 统计跟踪。

package sandbox;

import org.neo4j.server.WrappingNeoServerBootstrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.support.Neo4jTemplate;

public class GalaxyServiceTest 

    private final static Logger slf4jLogger = LoggerFactory.getLogger(GalaxyServiceTest.class);
    @Autowired
    private GalaxyService galaxyService;
    @Autowired
    private Neo4jTemplate template;

    public static void main(String args[]) throws InterruptedException 
        GalaxyServiceTest main = new GalaxyServiceTest();
        ApplicationContextLoader loader = new ApplicationContextLoader();
        loader.load(main, "/spring/helloWorldContext.xml");
        // The server starts with loading of above Context.xml
        WrappingNeoServerBootstrapper neoServer = loader.getApplicationContext().getBean("serverWrapper", WrappingNeoServerBootstrapper.class);
        //process something in repository 
        main.doSomething();
        // do a graceful stop
        int stop = neoServer.stop(0);
        slf4jLogger.info("stopping Server status code  ", stop);
        //Restart the server 
        neoServer.start();
        slf4jLogger.info("Restarting Server ");
        // Process something in Repository
        main.doSomething();

    

    public void doSomething() 
        galaxyService.makeSomeWorlds();
        Iterable<World> allWorlds = galaxyService.getAllWorlds();
        for (World world : allWorlds) 
            slf4jLogger.info("World Name is ", world.toString());
        
    

应用上下文定义xml

   <context:annotation-config />
    <context:spring-configured/>
    <context:component-scan base-package="sandbox" />

    <bean id="transactionManager" 
          class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="transactionManager">
            <bean id="jotm" class="org.springframework.data.neo4j.transaction.JotmFactoryBean"/>
        </property>
    </bean>
    <neo4j:config graphDatabaseService="graphDatabaseService" />
    <bean id="serverWrapper" class="org.neo4j.server.WrappingNeoServerBootstrapper"
          init-method="start" destroy-method="stop">
        <constructor-arg ref="graphDatabaseService" />
    </bean>

    <bean id="graphDatabaseService" class="org.neo4j.kernel.EmbeddedGraphDatabase" 
          destroy-method="shutdown">
        <constructor-arg value="target/test-db"/>
    </bean>
    <tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>

    <neo4j:repositories base-package="sandbox"></neo4j:repositories>

</beans>

我希望这会有所帮助。

【讨论】:

谢谢,我们已经添加了这些东西,当我们关闭应用程序上下文时,数据库上的锁消失了,当我们获得另一个上下文时它又回来了。然后,当我们尝试持久化新节点时,我们会得到“通过 bean 属性表示的不满足的依赖关系”错误。 当我们尝试从中读取时,我们得到:“Lucene 索引提供程序已关闭” 我不认为对 shutdown() 的调用是正确的,方法文档说:关闭 Neo4j。调用此方法后,调用 Neo4j API 中的任何方法均无效,所有对 GraphDatabaseService 实例的引用都应丢弃。 您在使用 HA 模式吗?你能分享你是如何创建索引的吗?那么这可能是代码问题......您对关机的理解是正确的。 什么是 HA 模式?我相信索引是在我们的实体中使用 @Index 注释创建的。

以上是关于如何在不杀死 VM 的情况下关闭和重新打开 Spring Data Neo4J 上下文的主要内容,如果未能解决你的问题,请参考以下文章

iOS:在不访问其父 ViewController 的情况下关闭和呈现 ModalViewController

Windows7下关闭和打开IPV6隧道

如何在不杀死未完成的芹菜任务的情况下重新启动heroku应用程序

Google Maps API:在不重新加载地图的情况下关注并居中我的观察位置

使用C#和Xamarin表单 - 如何在不设置闭包链的情况下关闭一个模态

如何在不离开当前视图的情况下关闭 modalViewController?