通过反序列化创建Spring bean

时间:2010-04-27 12:00:30

标签: java spring serialization javabeans

Spring有许多不同的创建bean的方法,但是可以通过反序列化资源来创建bean吗?

我的应用程序有许多组件,每个组件都操纵某种类型的数据。在测试期间,数据对象被直接实例化并直接设置在组件上,例如, component.setData(someDataObject)。在运行时,数据可作为序列化对象使用,并由组件从序列化流中读取(流作为Spring上下文中的资源传入。)

不是让每个组件从流中显式地反序列化它的数据,而是让Spring从资源反序列化数据对象并将其设置在目标组件上更加一致和灵活。这样,组件就会与数据的来源隔离开来。

是否有DeserializerFactoryBean或类似的东西?

编辑:

以下是一些希望澄清的示例代码:

public class ComponentData implements Externalizable
{
   // a complex data structure, behind a simpler interface       
}

public class Component
{
   private ComponenttData  componentData;

   public Component(ComponentData data)
   {
      componentData = data;
   }

   // other methods that operate using the data

   // factory method to create from serialized data
   static Component createFromResource(Resource resource)
   {
       return new Component(deserialize(resource));
   }
}

有许多类型的组件,每种组件类型使用不同的数据实例多次即时。

在测试中,组件及其ComponentData实例是用代码构造的。在生产中,具有“factory-method”属性的spring-bean用于调用静态Componnet.createFromResource方法,该方法对资源中的数据进行反序列化。有许多类型的组件,每个组件都有相同的静态方法来构建反序列化数据。由于重复,这本身似乎很糟糕。对我来说,测试和生产中的组件构造不一样,这似乎也很奇怪。如果可以将反序列化移动到Spring上下文中,则可以删除组件上的静态方法,然后由Spring完成所有依赖注入,而不必将其作为特殊情况进行编码。

E.g。我想像

这样的东西
<bean name="componentData" class="DeserializingFactoryBean">
    <constructor-arg value="/data/componentData1.dat"/> <!--  resource -->
</bean>

<bean name="component" class="Component">
    <constructor-arg ref="componentData"/>
</bean>

当我最初发布时,我认为这可能存在,但我可能在广阔的春天javadocs中错过了。从初始响应看来,Spring没有反序列化工厂bean。

如果DeserializingFactoryBean不是正确的方法,那么存在哪些替代方案?

3 个答案:

答案 0 :(得分:0)

  

是否有DeserializerBeanFactory或类似的东西?

从未听说过一个,坦率地说,我不希望我的初始化由不透明(仅仅是人类)序列化对象控制。

但如果你真的认为这是一个好主意(咳咳),创建一个以这种方式工作的自定义BeanFactory应该不难。

答案 1 :(得分:0)

是的,您可以为SimpleJndiBeanFactory实现自己的Beanfactory。但我不确定,这就是你想要的。您需要在应用程序上下文中使用其他bean。我会实现BeanFactoryPostProcessor加载来自流的bean以及autowireregister

答案 2 :(得分:0)

这是其他海报的评论。正如他们所指出的那样,Spring中没有反序列化工厂支持,所以我创建了一个。

下面是通过反序列化从资源创建bean的FactoryBean的代码。默认情况下,会创建一个实例,并为每次使用返回相同的实例。您可以将属性singleton设置为false,每次使用时都会反序列化一个新的实例。

像这样使用

<bean name="myBean" class="DeserializingFactoryBean">
    <property name="source" value="mybean.ser"/>
    <property name="objectType" value="org.acme.MyBean"/>
</bean>

代码

import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;

import java.io.BufferedInputStream;
import java.io.ObjectInputStream;

public class DeserializingFactoryBean extends AbstractFactoryBean
{
    private Resource    source;

    private Class<?>    objectType;

    private int         deserializationCount;

    public DeserializingFactoryBean()
    {
    }

    public DeserializingFactoryBean(Resource source, Class<?> objectType)
    {
        this.source = source;
        this.objectType = objectType;
    }

    public void afterPropertiesSet() throws Exception
    {
        Assert.notNull(objectType, "Property 'objectType' may not be null");
        Assert.notNull(source, "Property 'source' may not be null");
        super.afterPropertiesSet();
    }

    public Resource getSource()
    {
        return source;
    }

    public void setSource(Resource source)
    {
        this.source = source;
    }

    public void setObjectType(Class<?> objectType)
    {
        this.objectType = objectType;
    }

    public Class getObjectType()
    {
        return objectType;
    }

    @Override
    protected Object createInstance() throws Exception
    {
        ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(source.getInputStream()));
        Object result = oin.readObject();
        if (!objectType.isInstance(result))
            throw new ClassCastException(String.format("Deserialized object is not an instance of %s",objectType.getName()));
        oin.close();
        return result;
    }
}