Spring IoC:序列化方面有什么需要注意的吗?

4

我正在开发一个涉及Spring框架的新软件组件。我很喜欢它,但现在我有一个关于IoC和序列化的问题。

假设我有这个类(省略了导入和包声明):

public class EMailNotificationEndpoint implements NotificationEndpoint {
    private List<String> notficationEmailAdresses = new ArrayList<String>();
    transient private MailSender mailSender;

    public EMailNotificationEndpoint(MailSender mailSender) {
        this.mailSender = mailSender;
    }

    @Override
    public void notify(Notification notification) {
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        simpleMailMessage.setTo(notficationEmailAdresses.toArray(new String[notficationEmailAdresses.size()]));
        simpleMailMessage.setSubject(notification.getType().toString());
        simpleMailMessage.setText(notification.getMessage());

        mailSender.send(simpleMailMessage);
    }
}

NotificationEndpoint扩展了Serializable接口,以确保所有实现都是可序列化的。关键在于我无法将MailSender(它是org.springframework.mail.MailSender)序列化,并希望在反序列化时注入它。现在我的问题很明显:我能做到吗?如果答案是肯定的:怎么做?
我可以自由更改接口和实现,因此应该有一种方法来实现这样的事情,即使这意味着我必须重构相关的类。
非常感谢任何想法或提示!
2个回答

2

你关于将其设为短暂的做法是正确的。

当需要反序列化时,您只需要根据需要进行恢复即可。

您可以实现适当的 readObject 方法来执行该初始化操作:

     /**
      * Always treat de-serialization as a full-blown constructor, by
      * initializing or validating the final state of the de-serialized object.
      */
      private void readObject(ObjectInputStream aInputStream) 
          throws ClassNotFoundException, IOException {
        //always perform the default de-serialization first
        aInputStream.defaultReadObject();
        //do your other stuff, like initialization
        this.mailSender = ...
      }

注意:这里的对象本身必须获得MailSender实现,这不是非常依赖注入。你可以接受这个,或者找到另一种方式(通常在反序列化后涉及另一个对象,并设置正确的依赖项)。
如果您真的喜欢进行依赖注入,我找到了一个关于Spring和实体的链接,其中包含适用于此情况的一般知识:
http://chris-richardson.blog-city.com/migrating_to_spring_2_part_3__injecting_dependencies_into_en.htm

你的笔记正好涉及到我的问题。我正在寻找一种以依赖注入的方式来实现这个功能。也许Spring框架支持这方面的功能? - Malax
@Malax 我知道Spring支持在Spring之外实例化的对象,但是可以通过Spring进行后处理。我现在记不清怎么做了。 - KLE
@KLE - 你代码示例中的...位是难点。当对象通常被注入时,你该如何获取mailSender - Nick Holt

1

您需要实现自定义readObjectwriteObject方法,以序列化/反序列化MailSender类的状态和类,类似于以下内容:

private void writeObject(ObjectOutputStream out) throws ClassNotFoundException, IOException 
{
  try
  {
    out.defaultWriteObject();
    out.writeObject(mailSender.getClass().getName());

    for (Field field : mailSender.getClass().getDeclaredFields()) 
    {
      if (!(Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())))
      {  
        Object value = field.get(mailSender);
        if (value instanceof Serializable) 
        {
          out.writeObject(field.getName());
          out.writeObject(value);
        }
      }
    }  
  }
  catch (IllegalAccessException e) 
  {
    throw new IOException(e.getMessage(), e);
  }
}

private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException 
{
  try 
  {
    in.defaultReadObject();     
    mailSender = (MailSender)Class.forName((String)in.readObject()).newInstance();

    Map<String, Field> fields = new HashMap<String, Field>();
    for (Field field : mailSender.getClass().getDeclaredFields()) 
    {
      fields.put(field.getName(), field);
    }  

    int remainingFields = mailSender.getClass().getDeclaredFields().length;  
    while (remainingFields > 0) 
    {   
      String fieldName = (String)in.readObject();
      Object value = in.readObject();
    fields.get(fieldName).set(mailSender, value);
      remainingFields--;
    }
  }
  catch (IllegalAccessException e)
  {
    throw new IOException(e.getMessage(), e);
  }
  catch (InstantiationException e)
  {
    throw new IOException(e.getMessage(), e);
  }
}

你可能需要优化反射代码,如果所需状态不可序列化,可以考虑使用递归,但你已经掌握了需要做的要点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接