6

更新:现在使用地图。想要向其他实例发送内容的类发送对象,即路由字符串。

使用对象流,使用 Java 可序列化将对象写入 servlet。

先写字符串,再写对象。

接收 servlet 将输入流包装在 ObjectInputStream 周围。首先读取字符串,然后读取对象。路由字符串决定它是否进行。

一种更通用的方法可能是发送一个类名及其声明的方法或一个 Spring bean 名,但这对我们来说已经足够了。


原始问题

了解基本方法,但需要详细步骤。也知道我可以使用 Jaxb 或 RMI 或 EJB ...但想使用纯序列化到字节数组来执行此操作,然后将其从 jvm 1 中的 servlet 1 发送到 jvm 2 中的 servlet 2(两个应用程序服务器实例在同一个LAN,在两个 J2EE 应用程序中设置相同的 Java 版本和 jars)

基本步骤是(Appprocah 1):-

  1. 将任何 Serializable 对象序列化为字节数组并创建一个字符串。具体代码见下

  2. 1 的 Base64 输出。是否需要以 64 为基数或可以跳过第 2 步?

  3. 使用 java.util.URLEncode.encode 对字符串进行编码

  4. 在命名参数后使用 apache http 组件或 URL 类从 servlet 1 发送到 2

  5. 在 Servlet 2 J2EE 框架上已经对它进行了 URLDecoced,现在只需执行相反的步骤并根据参数名称强制转换为对象。由于两者都是我们的应用程序,我们将知道类型/类映射的参数名称。基本上是在寻找在 JVM 之间发送对象的最快和最方便的方式。

示例:要发送的 POJO 类

package tst.ser;

import java.io.Serializable;

public class Bean1 implements Serializable {
    /**
     * make it 2 if add something without default handling
     */
    private static final long serialVersionUID = 1L;
    private String s;

    public String getS() {
        return s;
    }

    public void setS(String s) {
        this.s = s;
    }   

}

* 效用 *

package tst.ser;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URLEncoder;

public class SerUtl {

    public static String serialize(Object o) {
        String s = null;
        ObjectOutputStream os = null;
        try {
            os = new ObjectOutputStream(new ByteArrayOutputStream());
            os.writeObject(o);
            s = BAse64.encode(os.toByeArray());


            //s = URLEncoder.encode(s, "UTF-8");//keep this for sending part

        } catch (Exception e) {
            // TODO: logger
            e.printStackTrace();
            return null;
        } finally {
            // close OS but is in RAM
            try {
                os.close();// not required in RAM
            } catch (Exception e2) {// TODO: handle exception logger
            }
            os = null;
        }
        return s;
    }

    public static Object deserialize(String s) {
        Object o = null;
        ObjectInputStream is = null;

        try {
            // do base 64 decode if done in serialize
            is = new ObjectInputStream(new ByteArrayInputStream(
                    Base64.decode(s)));
            o = is.readObject();
        } catch (Exception e) {
            // TODO: logger
            e.printStackTrace();
            return null;
        } finally {
            // close OS but is in RAM
            try {
                is.close();// not required in RAM
            } catch (Exception e2) {// TODO: handle exception logger
            }
            is = null;
        }
        return o;
    }

}

**** 样本发送 servlet ***

    Bean1 b = new Bean1(); b.setS("asdd");
    String s = SerUtl.serialize(b);
            //do UrlEncode.encode here if sending lib does not.
    HttpParam p = new HttpParam ("bean1", s);
    //http components send obj

**** 样本接收 servlet ***

    String s = request.getParameter("bean1");
    Bean1 b1 = (Beean1)SerUtl.deserialize(s);
4

4 回答 4

7

将任何可序列化的对象序列化为字节数组

是的。

并制作一个字符串。

不。

确切的陈述见下文

os = new ObjectOutputStream(new ByteArrayOutputStream());
os.writeObject(o);
s = os.toString();

// s = Base64.encode(s);//Need this some base 64 impl like Apache ?
s = URLEncoder.encode(s, "UTF-8");

这些陈述甚至没有做你所描述的,这在任何情况下都是不正确的。OutputStream.toString()不会将任何字节转换为字符串,它只是返回一个唯一的对象标识符。

Base64 输出为 1。

base64 输出应使用字节数组作为输入,而不是字符串。字符串不是二进制数据的容器。请参阅下面的更正代码。

ByteArrayOutputStream baos = new ByteArrayOutputStream();
os = new ObjectOutputStream(baos);
os.writeObject(o);
os.close();
s = Base64.encode(baos.toByeArray()); // adjust to suit your API
s = URLEncoder.encode(s, "UTF-8");

这至少实现了你的目标。

是否需要以 64 为基数或可以跳过第 2 步?

如果你想要一个字符串,你必须以某种方式对其进行编码。

使用 java.util.URLEncode.encode 对字符串进行编码

仅当您将其作为 GET 或 POST 参数发送时才需要这样做。

命名参数后使用 apache http 组件或 URL 类从 servlet 1 发送到 2

是的。

在 Servlet 2 J2EE 框架上已经对其进行了 URLDecoded,现在只需执行相反的步骤并根据参数名称强制转换为对象。

可以,但是记得直接从base64编码的字符串到字节数组,没有中间的String。

基本上是在寻找在 JVM 之间发送对象的最快和最方便的方式。

这些目标不一定是可调和的。这些天最方便的可能是 XML 或 JSON,但我怀疑它们是否比序列化更快。

操作系统=空;

设置即将超出范围的引用null是没有意义的。

HttpParam p = new HttpParam ("bean1", s);

可能HttpParam会为您执行 URLEncoding。检查这个。

于 2013-07-22T23:31:43.847 回答
3

您无需转换为字符串。您可以将二进制数据直接发布到 servlet,例如通过在HttpUrlConnection的输出流之上创建 ObjectOutputStream 。将请求方法设置为 POST。

处理 post 的 servlet 可以从 HttpServletRequest 的ServletInputStream创建的 ObjectStream 反序列化。

不过,我会在任何时候都推荐 JAXB,而不是二进制序列化。这些框架不仅具有很好的互操作性,还可以加快开发速度并创建更强大的解决方案。

我看到的优势是更好的工具、类型安全和代码生成,保持您的选项开放,以便您可以从另一个版本或另一种语言调用您的代码,并且更容易调试。不要低估由于意外向 servlet 发送错误类型或双重转义数据而导致的难以解决的错误的成本。我希望性能优势太小而无法弥补这一点。

于 2013-07-31T00:24:33.310 回答
2

发现这个 Base64 impl 为我做了很多繁重的工作:http: //iharder.net/base64

有实用方法:

 String encodeObject(java.io.Serializable serializableObject, int options )
Object decodeToObject(String encodedObject, int options, final ClassLoader loader )

使用 :

try {
            String dat = Base64.encodeObject(srlzblObj, options);
            StringBuilder data = new StringBuilder().append("type=");
            data.append(appObjTyp).append("&obj=").append(java.net.URLEncoder.encode(dat, "UTF-8"));

使用 type 参数告诉接收 JVM 我正在​​发送什么类型的对象。每个 servlet/jsps 最多接收 4 种类型,通常是 1 种。同样,因为它是我们自己的应用程序和我们发送的类,所以它很快(通过网络发送)和简单。

在另一端解压它:

        String objData = request.getParameter("obj");   
        Object obj = Base64.decodeToObject(objData, options, null);

处理它,编码结果,发回结果:

        reply = Base64.encodeObject(result, options);
        out.print("rsp=" + reply);

调用servlet/jsp得到结果:

            if (reply != null && reply.length() > 4) {
                String objDataFromServletParam = reply.substring(4);
                Object obj = Base64.decodeToObject(objDataFromServletParam, options, null);

选项可以是 0 或 Base64.GZIP

于 2013-07-30T16:34:36.823 回答
1

您也可以使用 JMS。Apache Active-MQ 是一种很好的解决方案。您不必为所有这些转换而烦恼。

  /**
 * @param objectToQueue
 * @throws JMSException
 */
public void sendMessage(Serializable objectToQueue) throws JMSException 
{
    ObjectMessage message = session.createObjectMessage();
    message.setObject(objectToQueue);
    producerForQueue.send(message);
}

/**
 * @param objectToQueue
 * @throws JMSException
 */
public Serializable receiveMessage() throws JMSException 
{
    Message message = consumerForQueue.receive(timeout);
    if (message instanceof ObjectMessage) 
          { 
              ObjectMessage objMsg = (ObjectMessage) message;
              Serializable sobject = objMsg.getObject();
              return sobject;
          }
    return null;
}

我的观点是do not write custom code for Serialization, iff it can be avoided

当您使用 AMQ 时,您需要做的就是让您的 POJO 可序列化。Active-MQ 函数负责序列化。

如果您希望 AMQ 快速响应,请使用vm-transport. 它将最小化 n/w 开销。您将自动获得 AMQ 功能的好处。

我建议这样做是因为

  • 您有自己的应用程序在网络上运行。
  • 您需要一种机制来传输对象。
  • 您还需要一种方法来监控它。

如果您选择自定义解决方案,您可能必须自己解决上述问题。

于 2013-07-30T10:16:37.420 回答