如何将bean保存(持久化、序列化)到磁盘并在Spring中恢复(反序列化)它们



我希望我的应用程序记住它在磁盘上的状态。因此,我的一些bean是有状态的,我希望保存并加载它们的状态。

假设我用这样的方法创建bean

@Bean
    MyBean myBean() {
        MyBean ans;
        if( /* bean is already written to disk */ ) {
            ans = readMyBean();
        }
        else {
            ans = new MyBean();
            ans.property1 = defaultValue1;
            // ...
        }
        return ans;
    }

这种方法正确吗?或者我需要考虑一些现有的Spring API?

在哪里调用保存方法?

更新

目前我做以下方式

我正在使用AnnotationConfigApplicationContext创建我的应用程序。我给它提供了java配置类,为bean提供了合适的创建者。

序列化是在业务逻辑中调用的,而反序列化是在创建代码中进行的:

public class MyConfig {
    protected String getConfigName() {
        String name = getClass().getSimpleName();
        name = name.split("\$\$")[0];
        return name;
    }
    @Bean
    MyDirectoryBean myDirectoryBean() {
        MyDirectoryBean ans = new MyDirectoryBean (new File("data/" + getConfigName()));
        return ans;
    }
    @Bean(name="mybean")
    MyBean myBean() {
        MyBean ans = (MyBean) myDirectoryBean().deserialize("mybean");
        if( ans == null ) {
            ans =new MyBean();
            ans.setMyParameter1(100); // etc
        }
        return ans;
    }
}

我的类MyDirectoryBean能够序列化和反序列化bean。

不幸的是,这种方式需要我对bean名称进行两次编码:在bean创建者注释中和发生反序列化的行中。

我在想象一些界面来截取创作过程。可能是BeanPreProcessor级?没有这样的阶级。也许我可以在自定义上下文中重写getBean()方法,以便它首先尝试反序列化bean?

简单的答案是序列化,您可以找到许多关于如何序列化对象和反序列化对象的示例,例如:

http://www.javapractices.com/topic/TopicAction.do?Id=45http://www.tutorialspoint.com/java/java_serialization.htm

并且您可以在@Bean方法中生成反序列化代码。

但我有两个争论,都是基于用数据和getter/setter在javabean中提取数据,以及基于这个javabean 使您的bean可配置

  1. 使用jpa将这个javabean持久化到DB上,您可以使用类似H2数据库的jdbc:H2:~/test或jdbc:H2:file:/data/sample
  2. 使用Spring资源并将数据放入属性文件中以读取数据,然后使用@Value

我对Spring Integration bean做了类似的操作基本思想是有一个主要的spring上下文,有时您可以加载一个子上下文。

儿童上下文示例;

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration" xmlns:int-file="http://www.springframework.org/schema/integration/file" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd http://www.springframework.org/schema/integration/file http://www.springframework.org/schema/integration/file/spring-integration-file.xsd 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">
   <context:property-placeholder/>
   <int:channel id="ch.file.in"/>
   <int-file:inbound-channel-adapter directory="${file.dir}" channel="ch.file.in">
      <int:poller fixed-rate="${file.pollInterval}"/>
   </int-file:inbound-channel-adapter>
   <bean id="fileBatchRunner" class="com.nevexis.dcard.integration.serviceactivator.FileBatchRunner">
      <property name="jobLauncher" ref="jobLauncher"/>
      <property name="job" ref="fileImportJob"/>
   </bean>
   <int:service-activator input-channel="ch.file.in" ref="fileBatchRunner" method="transform"/>
</beans>

然后您可以将其作为子项加载到根上下文:

public class ContextRegisterImpl implements ContextRegister, ApplicationContextAware{
    private ApplicationContext parentCtx;
    private Map<String, ConfigurableApplicationContext> contexts;
    public ContextRegisterImpl() {
        contexts = new HashMap<String, ConfigurableApplicationContext>();
    }
    public void loadContext(String name, String path, Properties props) throws ContextAlreadyLoadedException {
        ConfigurableApplicationContext ctx = 
                new ClassPathXmlApplicationContext(new String[] { path }, false, parentCtx);
        setEnvironment(ctx, props);
        ctx.refresh();
        contexts.put(name, ctx);
    }
    public void shutdownContext(String name) throws ContextNotOpenException {
        ConfigurableApplicationContext context = contexts.get(name);
        if(context != null){
            context.close();
            contexts.remove(name);
        }
    }
    private void setEnvironment(ConfigurableApplicationContext ctx, Properties props) {
        StandardEnvironment env = new StandardEnvironment();
        PropertiesPropertySource pps = new PropertiesPropertySource("childCtxProps", props);
        env.getPropertySources().addLast(pps);
        ctx.setEnvironment(env);
    }
    //getters and setters
}

从磁盘/数据库加载的是属性。您必须为每个占位符(${...})提供一个道具。然后setEnvironment将它们放在上下文的环境中,当您加载它时,property-placeholder将用实际值替换占位符。

请注意,子上下文可以从父上下文中查看和使用bean,但父上下文不能从其子上下文中查看bean。这个例子与Spring集成有关,但与普通bean相同。

我的想法来自:https://github.com/spring-projects/spring-integration-samples/tree/master/advanced/dynamic-ftp

另一种选择是直接在根上下文中加载bean定义:

if(beanExists(beanName, rootCtx)){ throw new BeanExitstException(beanName+" already exists!"); }
        AutowireCapableBeanFactory factory = rootCtx.getAutowireCapableBeanFactory();
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) factory;
        registry.registerBeanDefinition(beanName, beanDef);

请参阅BeanDefinition界面:http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/config/BeanDefinition.html

您可以简单地通过实现Serializable来实现它。这里有一个示例代码:当第一次运行时,Object被保存。第二次,它被加载。

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class SerializeTest implements Serializable{
    private static SerializeTest p;
    private static String fileName;
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        fileName = "test.data";
        File f = new File(fileName);

        if(f.exists() && !f.isDirectory()) {
            FileInputStream fIn = new FileInputStream(fileName);
            ObjectInputStream oIn = new ObjectInputStream (fIn);
            Object object = oIn.readObject();
            if(object instanceof SerializeTest) {
                p = (SerializeTest) object;
                System.out.println("Successfully loaded!");
            }
            else
                System.err.println("Invalid object in " + fileName);
            fIn.close();
            oIn.close();
        }
        else {
            p = new SerializeTest();
            System.out.println("Successfully created!");
        }
        save(p);
    }
    public static void save(SerializeTest p) throws IOException {
        FileOutputStream fOut = new FileOutputStream(fileName);
        ObjectOutputStream oOut = new ObjectOutputStream(fOut);
        oOut.writeObject(p);
        fOut.close();
        oOut.close();
    }
}

相关内容

  • 没有找到相关文章

最新更新