Spec-Zone .ru
спецификации, руководства, описания, API
Содержание документации
 

Часто Задаваемые Вопросы
Java™ RMI и Объектная Сериализация


Java RMI

Очень Частые Вопросы

Отладка Java программы RMI

Сети

Используя Java RMI, чтобы достигнуть X (для приблизительно X)

Как делает работу RMI с X (для приблизительно X)

Внутренности, ресурсы, и производительность

Разное

Объектная Сериализация

  1. Почему должен реализация классов Serializable чтобы быть записанным ObjectOutputStream?
  2. Который JDK v1.1 системные классы отмечаются сериализуемые?
  3. У меня есть проблемы, десериализовывая компоненты AWT. Как я могу сделать эту работу?
  4. Объектная сериализация поддерживает шифрование?
  5. Объектные классы сериализации являются потоковыми. Как я пишу объекты в файл произвольного доступа?
  6. Когда локальный объект сериализируется и передается в качестве параметра в Java вызов RMI, байт-коды для методов локального объекта, которые также передают? Что относительно объектной последовательности, если удаленная виртуальная машина (VM) приложение "сохраняет" объектный дескриптор?
  7. Как может я создавать ObjectInputStream от ObjectOutputStream без файла промежуточный?
  8. Я создаю объект и затем отправляю его через сеть, используя writeObject метод и получает это использующий readObject метод. Если я тогда изменяю значение поля в объекте и отправляю это как прежде, объект что readObject возвраты метода, кажется, то же самое как первый объект и не отражают новое значение поля. Я должен испытывать это поведение?
  9. Там какие-либо планы состоят в том, чтобы поддерживать сериализацию объектов потока?
  10. Я могу вычислить разность (последовательный (x), последовательный (y))?
  11. Я могу сжать последовательное представление своих объектов, используя мою собственную zip и разархивировать методы?
  12. Я могу выполнить методы на сжатых версиях моих объектов, например isempty (zip (последовательный (x)))?
  13. Если я пытаюсь сериализировать шрифт или объект изображения и затем попытаться воссоздать это в различном VM, мое приложение умирает. Почему?
  14. Как я сериализирую дерево объектов?
  15. Если класс A не реализует Serializable но подкласс B реализации Serializable, поля класса A будут сериализированы, когда B будет сериализирован?

Java RMI

1, Почему, я получаю исключение для неожиданного имени хоста и/или номера порта, когда я вызываю Naming.lookup?

Имя хоста и номер порта, который Вы видите в трассировке исключения, представляют адрес, на котором смотревший сервер полагает, что это слушает. В то время как Java Удаленный Вызов метода (Java RMI) сервер может теоретически быть на любом узле, это обычно - тот же самый узел как это, на котором реестр работает, и на различном порту.

Даже если сервер будет ошибочен о своем имени хоста или IP-адресе (или имеет имя хоста, которое просто не разрешимо клиентами), то это все еще экспортирует все свои объекты, используя, что ошибочное имя хоста, но Вы будете видеть исключение каждый раз, когда Вы пытаетесь получить один из тех объектов.

Имя хоста, в котором Вы определили Naming.lookup определять местоположение реестра не имеет никакого эффекта на имя хоста, которое уже встраивается в удаленную ссылку на сервер.

Обычно, таинственное имя хоста является неполным именем хоста сервера, или частным именем, неизвестным nameservice клиента, или (в случае платформ Windows) Сеть сервера-> Идентификация-> Машинное Имя.

Соответствующее обходное решение должно установить системное свойство java.rmi.server.hostname запуская сервер. Значение свойства должно быть внешне достижимым именем хоста (или IP-адрес) сервера - безотносительно работ когда определено как часть узла в Naming.lookup достаточно хорошо.

Для большего количества детали см. вопросы на обратных вызовах и полностью определенных доменных именах.

2 я должен установить _Stub файл в клиенте CLASSPATH? Я думал, что это могло быть загружено.

Тупиковый класс может быть загружен, если сервер, который экспортирует удаленный объект, аннотирует упорядоченный тупиковый экземпляр java.rmi.server.codebase свойство, которое указывает на расположение от того, где тупиковый класс может быть загружен. Следует установить java.rmi.server.codebase свойство на сервере, экспортирующем удаленный объект. В то время как удаленные клиенты могли установить это свойство, они будут тогда ограничены только получением удаленных объектов от указанной кодовой базы. Недопустимо предположить, что любой клиент, VM определит кодовую базу, которая решает к расположению Вашего объекта.

Когда удаленный объект упорядочивается по Java RMI (ли как параметр удаленному вызову или как возвращаемое значение), кодовая база для тупикового класса получается Java RMI и используется, чтобы аннотировать сериализированный тупик. Когда тупик неупорядочивается, кодовая база используется, чтобы загрузить тупик classfile использование RMIClassLoader, если класс не может уже быть найден в CLASSPATH или контекстом classloader для объекта получения, такого как кодовая база апплета.

Если _Stub класс был загружен RMIClassLoader, тогда Java RMI уже знает который кодовая база использовать для ее аннотации. Если _Stub класс был загружен из CLASSPATH, тогда нет никакой очевидной кодовой базы, и Java, с которым RMI консультируется java.rmi.server.codebase системное свойство, чтобы найти кодовую базу. Если системное свойство не устанавливается, то тупик упорядочивается с нулевой кодовой базой, что означает, что это не может использоваться, если у клиента нет соответствующей копии _Stub classfile в клиенте CLASSPATH.

Легко забыть определять свойство кодовой базы. Один способ обнаружить эту ошибку состоит в том, чтобы запуститься rmiregistry отдельно и без доступа к классам приложений. Это вызовет Naming.rebind перестать работать, если кодовая база опускается.

Для получения дополнительной информации по java.rmi.server.codebase свойство, пожалуйста, смотрите на наше учебное руководство, Динамическая загрузка кода, используя Java RMI (Используя java.rmi.server.codebase Свойство).

3 Делает Java, RMI требует, чтобы я использовал сервер HTTP?

Нет. Можно установить Ваш java.rmi.server.codebase свойство, чтобы использовать любой допустимый протокол URL, такой как file или ftp. Используя сервер HTTP только делает Вашу жизнь более простой, обеспечивая автоматизированный механизм для загрузки файла класса. Если у Вас нет доступа к серверу HTTP, ни наклону установить один, можно использовать наш маленький файловый сервер класса, найденный в http://java.sun.com/javase/technologies/core/basic/rmi/class-server.zip.

4, Почему я, добираясь a ClassNotFoundException?

Наиболее вероятно java.rmi.server.codebase свойство не было установлено (или не был установлен правильно) на VM, который экспортирует Ваш удаленный объект (ы). Пожалуйста, смотрите на наше учебное руководство, Динамическая загрузка кода, используя Java RMI (Используя java.rmi.server.codebase Свойство).

5, Почему делает Java, реализация RMI создает очень много сокетов, когда мое приложение использует пользовательские фабрики сокета; или почему тупики (использующий пользовательскую фабрику сокета), которые обращаются к тому же самому удаленному объекту, не равному; или почему делает Java реализация RMI не порты серверной стороны повторного использования, когда я использую пользовательскую фабрику сокета сервера?

Java реализация RMI пытается снова использовать открытые сокеты где только возможно для удаленных вызовов. Когда удаленный метод вызывается на тупик, который использует пользовательскую фабрику сокета, Java, реализация RMI снова использует открытое соединение (если кто-либо), пока тот сокет создавался эквивалентной фабрикой сокета. Так как клиентские фабрики сокета сериализируются клиентам, у единственного клиента может быть несколько отличных копий той же самой логической фабрики сокета. Чтобы гарантировать, что Java реализация RMI снова использует сокеты, создаваемые пользовательскими фабриками сокета, удостоверьтесь, что Ваши пользовательские клиентские классы фабрики сокета реализуют hashCode и equals методы соответственно. Если клиентская фабрика сокета не реализует эти методы правильно, другое разветвление - то, что тупики (использующий клиент снабжают фабрику сокетом), которые обращаются к тому же самому удаленному объекту, не будут равны.

Java реализация RMI пытается снова использовать порты серверной стороны также. Это только сделает так, если будет существующий сокет сервера для порта, создаваемого эквивалентной фабрикой сокета. Удостоверьтесь, что класс фабрики сокета сервера реализует hashCode и equals методы также.

Если у Вашей фабрики сокета нет никакого состояния экземпляра, тривиальной реализации hashCode и equals методы являются следующим:

    public int hashCode() { return 57; }
    public boolean equals(Object o) { return this.getClass() == o.getClass() }

B.1 будет там отлаживать механизмы, встроенные в Java RMI?

Java RMI поддерживает простое средство записи разговора клиента с оператором для того, чтобы отладить. Но нет никаких текущих планов поддерживать полнофункциональный, интерактивный, удаленный отладчик.

B.2 у меня есть проблема, отлаживая мою программу на Windows 95. Какие-либо предложения?

javaw команда выбрасывает вывод к stdout и stderr, так для того, чтобы отладить цели лучше работать java команда в отдельном окне так, чтобы можно было видеть, сообщила об ошибках. Чтобы сделать это, выполните команду как следующее:
        start java EchoImpl

Советуют не использовать javaw команда во время разработки. Чтобы наблюдать действие сервера, запустите сервер с -Djava.rmi.server.logCalls=true.

B.3, Почему, я получаю a java.lang.ClassMismatchError выполняя мою программу?

Вы, вероятно, изменили один или более классов, которые использовались Java программы RMI, в то время как Ваша программа работала. Попытайтесь перезапустить весь Java приложения RMI (включая java.rmi.registry.RegistryImpl). Это должно разрешить вещи.

B.4 я отправляю массив удаленных объектов и получаю ArrayStoreException. Что продолжается?

Java RMI заменяет удаленные объекты тупиком и поэтому типом массива, должен быть Java интерфейса. Код был бы похож:
   FooRemote[] f = new FooRemote[10];
   for (int i = 0; i < f.length; i++) {
      f[i] = new FooRemoteImpl();
   }

Теперь Java RMI может поместить тупик в каждую ячейку массива без исключения на удаленном вызове.

B.5 у меня есть локальные объекты, которые синхронизируются. Когда я заставляю их отдалить, мое приложение зависает. В чем проблема?

То, с чем Вы встретились, было распределенной мертвой блокировкой. В локальном случае VM VM может сказать, что вызов возражает, что "A" имеет блокировку и позволит вызову назад "A" продолжаться. В распределенном случае не может быть сделано никакое такое определение, таким образом, результатом является мертвая блокировка.

Распределенные объекты ведут себя по-другому чем локальные объекты. Если Вы просто снова используете локальную реализацию, не обрабатывая блокировку и отказ, то Вы, вероятно, получите непредсказуемые результаты.

B.6 я получаю a ClassNotFoundException для моего тупикового класса, когда я пытаюсь зарегистрировать удаленный объект в реестре. Что происходит?

Когда Вы делаете звонок в реестр, чтобы связать объект, реестр фактически связывает ссылку на тупик для удаленного объекта. Чтобы инстанцировать тупикового объекта, реестр, VM должен быть в состоянии загрузить свое определение класса. VM (в этом случае сервер VM), который отправляет сериализированные формы тупика в удаленном вызове метода реестра, ответственен за аннотирование тупика расположением, с которого могут быть загружены его классы. Если тупики не будут аннотироваться должным образом, Java, то RMI бросит a ClassNotFoundException когда это пытается инстанцировать тупика.

Чтобы аннотировать классы должным образом, сервер должен установить значение java.rmi.server.codebase значение свойства к расположению (ям) тупиковых классов. Java RMI автоматически аннотирует сериализированную форму исходящих объектных экземпляров со значением java.rmi.server.codebase свойство.

ОТМЕТЬТЕ: возможно (и в небольшом количестве соответствующих сред) позволить rmiregistry неупорядочить тупиковые объекты, помещая все соответствующие тупиковые файлы класса в ПУТЬ К КЛАССУ rmiregistry. Однако, rmiregistry не должен загрузить тупиковые классы. Если тупиковые классы будут доступны локально, то это будет использовать те классы. Используя ПУТЬ К КЛАССУ rmiregistry для тупикового развертывания требует, чтобы у всех VMs, которые ссылаются на тупиковый экземпляр, полученный из того реестра, был файл класса тупика, установленный локально (в ПУТИ К КЛАССУ VM).

Например, если реестр загрузит тупиковые классы из своего ПУТИ К КЛАССУ, когда реестр отправит сериализированные тупиковые объекты другому VMs, то те сериализированные объекты будут аннотироваться значением реестра java.rmi.server.codebase свойство (который почти всегда будет нулем). Если VMs, у получения сериализированных тупиковых объектов от реестра нет файлов класса для тех тупиков установленными локально тогда те VMs, вероятно, бросят a ClassNotFoundException.

Вместо этого если классы загружаются динамически с VM's сервера java.rmi.server.codebase аннотация, только сервер у VM должны быть тупиковые классы в его ПУТИ К КЛАССУ. С этим подходом развертывание приложения более просто, и возможно ввести новые тупиковые версии в рабочую распределенную систему.

Для получения дополнительной информации по динамической загрузке кода в Java RMI, пожалуйста, см. учебное руководство, Динамическая загрузка кода, используя Java RMI (Используя java.rmi.server.codebase).

B.7 Мой сервер умер. Я могу получить трассировку действия сервера?

Чтобы получить трассировку действия сервера, запустите сервер следующим образом:
    java -Djava.rmi.server.logCalls=true YourServerImpl
где YourServerImpl имя Вашего сервера. Если Ваш сервер завис, можно получить дамп монитора и распараллелить дамп, делая ctrl-\ на Операционной системе Solaris™ (Солярис ОС) и ctrl-break на платформах Windows.

B.8, Где я могу найти список системных свойств, которые могли бы быть полезными для реализации и отладки Java приложения RMI?

Свойства, которые начинаются"java.rmi."элементы общедоступной спецификации и документируются в Java Спецификация RMI.

Свойства, которые начинаются"sun.rmi."только поддерживаются определенными версиями Java Комплект разработчика SE (JDK) программное обеспечение от Sun Microsystems. В то время как они"sun.rmi.*"свойства могут быть довольно полезными для отладки и настройки во время выполнения, пожалуйста, отметьте, что их не считают частью общедоступного API, и их использование подвержено изменениям (или может быть удален полностью) в будущих версиях реализации.

C.1, Как делают Java клиенты RMI, связываются с удаленным Java серверы RMI?

Иллюстрирует средства, которым Java клиенты RMI связываются с удаленным Java серверы RMI, как обсуждено ниже.

Для Java клиент RMI, чтобы связаться с удаленным Java сервер RMI, клиент должен сначала содержать ссылку на сервер. Naming.lookup вызов метода является наиболее распространенным механизмом, которым клиенты первоначально получают ссылки на удаленные серверы. Удаленные ссылки могут быть получены другими средствами, например: все удаленные вызовы метода могут возвратить удаленные ссылки. Это что Naming.lookup делает; это использует известный тупик, чтобы сделать удаленный вызов метода rmiregistry, который отсылает удаленную ссылку назад на объект, который требуют lookup метод.

Каждая удаленная ссылка содержит имя хоста сервера и номер порта, которые позволяют клиентам определять местоположение VM, который служит определенному удаленному объекту. Однажды Java у клиента RMI есть удаленная ссылка, клиент будет использовать имя хоста и порт, обеспеченный в ссылке, чтобы открыть сокетное соединение с удаленным сервером.

Пожалуйста, отметьте, что с Java RMI клиент и сервер сроков может сослаться на ту же самую программу. Программа Java, которая действует как Java сервер RMI, содержит экспортируемый удаленный объект. Клиент RMI Java является программой, которая вызывает один или более методов на удаленный объект в другой виртуальной машине. Если VM выполняет обе из этих функций, он может упоминаться как клиент RMI и Java сервер RMI.

C.2, Почему делает мой удаленный метод или сбой подпрограммы "обратного вызова" с вложенным java.net.UnknownHostException?

Во многих версиях JDK (все версии JDK кроме в v1.1 и последних выпусках), Java RMI может принять значение по умолчанию к использованию неразрешимого имени хоста сервера (например: неполные имена, Windows Internet Naming Service (WINS) имена, или неполные имена DHCP). Когда Java, клиент RMI вызывает удаленный метод, используя ссылку, которая содержит неразрешимое имя хоста сервера, клиент, бросит UnknownHostException.

Чтобы генерировать функциональные удаленные ссылки, Java, серверы RMI должны быть в состоянии предоставить полностью определенное имя хоста или IP-адрес, который разрешим от всего Java клиенты RMI (пример полностью определенного имени хоста foo.bar.com). Если Java, программа RMI обеспечивает удаленную работу обратного вызова, то та программа служит Java объект RMI и следовательно, должен быть в состоянии определить разрешимое имя хоста, чтобы использовать в качестве его имени хоста сервера в удаленных ссылках, это передает к Java клиенты RMI. VMs, которые делают звонки в апплеты, которые служат удаленным объектам, могут бросить UnknownHostExceptions, потому что апплет был не в состоянии обеспечить применимое имя хоста сервера.

Если Ваш Java приложение RMI бросает UnknownHostException, можно смотреть на получающуюся трассировку стека, чтобы видеть, является ли имя хоста, которое клиент использует, чтобы связаться с его удаленным сервером, неправильным или не полностью определенное. В случае необходимости можно установить java.rmi.server.hostname свойство на сервере к корректному IP-адресу или имени хоста машины сервера и Java RMI будет использовать значение этого свойства, чтобы генерировать удаленные ссылки на сервер.

C.3 Мой сервер использует полностью определенное доменное имя или IP-адрес, итак, почему делают меня все еще, добираются UnknownHostException?

В зависимости от конфигурации службы имен Вашей сети полностью определенное имя хоста, которое распознается на одном Java узел RMI, возможно, не разрешимо от другого Java узел RMI. Некоторые примеры, где эта ситуация может возникнуть:

C.4 я использую последний выпуск JDK и у меня есть узел, у которого есть многократные IP-адреса. Java RMI выбирает неправильный IP-адрес для своего имени хоста сервера. Как я работаю вокруг этой проблемы?

Установите java.rmi.server.hostname свойство к корректному IP-адресу Java машина сервера RMI. Можно также определить, что Ваш сервер использует полностью определенное имя хоста, полученное из службы имен, устанавливая свойство:
    java.rmi.server.useLocalHostname=true

C.5, Как делает Java RMI, получают имя хоста сервера в каждой из версий JDK?

Методы, что Java использование RMI, чтобы получить имя хоста сервера в каждой из версий JDK:

JDK v1.1

На Java RMI полагаются java.net.InetAddress.getLocalHost() возвратить полностью определенное доменное имя. InetAddress объекты инициализированные локальные имена хоста в статическом блоке кода, выполняя обратный поиск на локальном IP-адресе, чтобы получить локальное имя хоста. Однако, на машинах, которые не были соединены с сетью, это поведение, вызванное программа, чтобы зависнуть в то время как InetAddress разыскиваемый имя хоста, которое не могло быть найдено.

JDK v1.1.1-1.1.6

Работать вокруг JDK v1.1 проблема на автономных системах, InetAddress был изменен в JDK v1.1.1, чтобы только получить [потенциально неполное] имя хоста, возвращенное из собственного системного вызова, который не пытался консультироваться со службой имен. Java RMI не был изменен, чтобы компенсировать это изменение начиная со свойства java.rmi.server.hostname разрешенные пользователи, чтобы переопределить неправильные имена хоста, обеспеченные InetAddress. Java RMI, предпринятый никакая попытка консультироваться со службой имен и, мог принять значение по умолчанию к использованию неполных имен хоста.

Более поздние версии

Компенсировать много проблем, которые были сгенерированы изменением v1.1.1 в функциональности InetAddress, следующее поведение было интегрировано в новые версии JDK:

RMI Java будет использовать IP-адрес или полностью определенное доменное имя, чтобы идентифицировать машину, которая служит удаленному объекту. Имена хоста сервера инициализируются к значению, полученному, выполняя следующие действия:

  1. По умолчанию Java RMI использует IP-адрес узла сервера как имя сервера для удаленных ссылок.
  2. Если свойство java.rmi.server.hostname устанавливается, Java RMI будет использовать свое значение в качестве имени хоста сервера, и не будет пытаться найти полностью определенное доменное имя через любой другой метод. Это свойство имеет приоритет по всем другим средствам по обнаружению Java имя сервера RMI.
  3. Если свойство java.rmi.server.useLocalHostname устанавливается в true (по умолчанию значение этого свойства false), Java RMI применяет следующую подпрограмму, чтобы получить имя хоста для Java сервер RMI:
    1. Если значение, возвращенное InetAddress.getLocalHost().getHostName() метод содержит "." символ, тогда Java, RMI предположит, что это значение является полностью определенным доменным именем сервера и будет использовать его в качестве имени хоста сервера.
    2. Иначе, Java RMI породит поток, чтобы запросить локальную службу имен для полностью определенного доменного имени Java сервер RMI. Если служба имен берет слишком долго, чтобы возвратиться, или возвраты службы имен, но ее ответ не содержат "." тогда Java, из которого RMI будет использовать IP-адрес сервера, полученный InetAddress.getLocalHost().getHostAddress().
    Пользователи могут переопределить время по умолчанию (10 секунд или 10000 миллисекунд), что Java RMI будет искать полностью определенное доменное имя, устанавливая следующее свойство:
    sun.rmi.transport.tcp.localHostnameTimeOut=timeOutMillis
    где timeOutMillis является временем, когда Java RMI будет ожидать в миллисекундах. Например:
                java -Dsun.rmi.transport.tcp.localHostnameTimeOut=2000 MyServerApp
            
    
При использовании activatable удаленных объектов рекомендуется что Java набор серверов RMI значение java.rmi.server.useLocalHostname свойство к true. Вообще, имена хоста более устойчивы чем IP-адреса. Удаленные объекты Activatable имеют тенденцию длиться дольше чем переходные удаленные объекты (например, переживая перезагрузку). Клиент RMI Java, более вероятно, определит местоположение удаленного объекта за длительный период времени, если это будет использовать квалифицированное имя хоста, а не явный IP-адрес.

C.6, Почему делают Naming.bind и Naming.lookup необычно потребуйтесь много времени на платформах Windows?

Наиболее вероятно сетевая установка Вашего узла является неправильной. Java RMI использует API Java сетевые классы в особенности java.net.InetAddress, который заставит поиски имени хоста TCP/IP - и узел адресовать отображение и адресоваться к отображению имени хоста ( InetAddress класс делает это для соображений безопасности). На платформах Windows функции поиска выполняются собственной библиотекой сокета, таким образом, задержки происходят не в Java RMI, а в библиотеках. Если Ваш узел устанавливается, чтобы использовать DNS, то это обычно - проблема с сервером DNS, не зная об узлах, включенных в передачу, и что Вы испытываете, тайм-ауты поиска DNS. Попытайтесь определить все включенные имена хоста/адреса в локальном файле \winnt\system32\drivers\etc\hosts или \windows\hosts. Формат типичного файла узла:
    IPAddress     Machine Name
например:
    192.0.2.61   homer
Это должно существенно сократить время, которое требуется, чтобы сделать первый поиск.

C.7, Как я использую Java RMI на Windows 95 автономная машина, не соединенная с сетью?

Чтобы получить Java RMI, работающий над машиной Windows 95, которая не находится в сети, TCP/IP должен быть сконфигурирован. Один способ выполнить это состоит в том, чтобы сконфигурировать неиспользованный COM-порт как выделенный PPP или SLIP соединение. Затем DHCP отключения и вручную конфигурирует IP-адрес (например. 192.168.1.1). Следует тогда найти, что от DOS Shell, можно проверить с помощью ping-запросов себя (например, проверить с помощью ping-запросов mymachine). Следует теперь быть в состоянии использовать Java RMI на машине.

C.8, Почему, я получаю исключение"java.net.SocketException: Address already in use"когда я пытаюсь выполнить реестр?

Это исключение означает что порт что RegistryImpl использование (значением по умолчанию 1099) уже находится в использовании. Вы можете иметь другой реестр, работающий на Вашей машине, и должны будете остановить это.

C.9, Как я могу использовать Java RMI через брандмауэр?

Это зависит от того, должны ли Вы пересечь брандмауэр для исходящих звонков или для входящих вызовов.

C.10, Как я могу сделать исходящий Java вызовами RMI через локальный брандмауэр?

Есть три основных метода: туннелирование HTTP, SOCKS, и загруженные фабрики сокета.

Туннелирование HTTP

Этот затасканный метод популярен, так как он не требует почти никакой установки, и работает вполне хорошо в firewalled средах, которые разрешают Вам обрабатывать HTTP через прокси, но отвергают регулярные исходящие соединения TCP.

Если Java, RMI не в состоянии сделать нормальное (или SOCKS) соединением с намеченным сервером, и это заметит, что прокси-сервер HTTP конфигурируется, то это попытается туннелировать Java запросы RMI через тот прокси-сервер по одному.

Есть две формы туннелирования HTTP, которое попробовали в порядке. Первым является http к порту; вторым является http-to-cgi.

В туннелировании http к порту Java RMI делает попытку запроса POST HTTP к a http: URL, направленный на точное имя хоста и номер порта целевого сервера. Запрос HTTP содержит единственный Java запрос RMI. Если прокси HTTP примет этот URL, то он передаст запрос POST к Java слушания сервер RMI, который распознает запрос и развернет его. Результат вызова обертывается в ответ HTTP, который возвращается через тот же самый прокси.

Часто, прокси HTTP откажутся проксировать запросы к необычным номерам портов. В этом случае Java RMI отступит к туннелированию http-to-cgi. Java запрос RMI инкапсулируется в запросе POST HTTP как прежде, но запросе URL, имеет форму http://hostname:80/cgi-bin/java-rmi.cgi?port=n (где имя хоста и n являются именем хоста и номером порта намеченного сервера). Должен быть сервер HTTP, слушающий на порту 80 на узле сервера, который будет работать java-rmi.cgi сценарий (предоставленный JDK), который поочередно передаст запрос к Java сервер RMI, слушающий на порту n. Java RMI может развернуть туннелированный HTTP запрос без справки от http сервера, сценария CGI, или любого другого внешнего объекта. Так, если прокси HTTP клиента может соединиться непосредственно с портом сервера, то Вы не нуждаетесь в a java-rmi.cgi сценарий вообще.

Инициировать использование туннелирования HTTP, стандартного системного свойства http.proxyHost должен быть установлен в имя хоста локального прокси HTTP. (Есть отчеты, что некоторые версии Навигатора не устанавливают это свойство.)

Главный недостаток туннелирования HTTP - то, что оно не разрешает входящие вызовы или мультиплексированные соединения. Вторичный недостаток - то, что http-to-cgi метод открывает драматическую дыру в системе безопасности на серверной стороне, с тех пор без модификации это перенаправит любой входящий запрос к любому порту.

SOCKS

Реализация по умолчанию сокетов в JDK будет использовать сервер SOCKS при наличии и сконфигурированный. Системное свойство socksProxyHost должно быть, был установлен в имя хоста сервера SOCKS; если номер порта сервера SOCKS не 1080, это должно быть определено в socksProxyPort свойство.

Этот подход, казалось бы, был бы самым обычно полезным решением. Пока еще, ServerSockets не используйте SOCKS, таким образом, входящие вызовы должны использовать другой механизм.

Загруженные фабрики сокета

Это - новшество в JDK, позволяя сервер определить фабрику сокета, которую должны использовать клиенты. Клиенты должны выполнять J2SE v1.2 или позже. См., что учебное руководство Использует Пользовательские Фабрики Сокета с Java RMI для деталей.

Недостаток этого подхода - то, что обход брандмауэра должен быть сделан кодом, обеспеченным Java серверная сторона RMI, которая не обязательно знает, как тот обход должен быть сделан, и при этом у этого автоматически нет достаточного полномочия пересечь брандмауэр.

C.11, Как я могу получить входящий Java вызовы RMI через локальный брандмауэр?

Есть три основных метода: известные порты, мосты на транспортном уровне, и прокси уровня приложения.

Известные Порты

Если экспортируемые объекты все экспортируются на известном порту на известном узле, то тот узел и порт могут быть явно разрешены в брандмауэре. Обычно, Java, который RMI просит порт 0 (который является кодом для "любого порта"). В JDK есть дополнительный параметр exportObject метод, чтобы определить точный номер порта. В JDK v1.1, сервер должен разделить на подклассы RMISocketFactory и прерывание запрашивает к createServerSocket(0), замена этого с запросом, чтобы связать с определенным номером порта.

У этого подхода есть недостаток, что это требует помощи администратора сети, ответственного за локальный брандмауэр. Если экспортируемый объект выполняется в различном расположении (потому что код был загружен на тот сайт), то локальный брандмауэр может быть выполнен администраторами сети, которые не знают, кто Вы.

Мосты на транспортном уровне

Мост на транспортном уровне является программой, которая читает байты из одного соединения TCP и пишет их другому (и наоборот), не зная или заботясь, что представляют байты.

Идея здесь состоит в том, чтобы экспортировать объекты таким способом, которым любой вне брандмауэра, кто хочет вызвать удаленные методы на том объекте вместо этого, связывается с различным портом (возможно, на различной машине). У того различного порта есть рабочая программа, которая делает второе соединение с реальным сервером и затем качает байты каждый путь.

Хитрая часть убеждает клиент соединяться с мостом. Загружаемая фабрика сокета (JDK, v1.2 или позже) может сделать это эффективно; иначе, возможно установить java.rmi.server.hostname свойство, чтобы назвать узел моста и принять меры, чтобы номера портов были тем же самым.

Прокси уровня приложения

Этот подход является довольно мало работы, но приводит к очень безопасному расположению. Программа прокси работает на узле брандмауэра (тот, к которому можно получить доступ снаружи так же как внутри). Когда внутренний сервер намеревается сделать экспортируемый объект доступным для мира, он связывается с прокси-сервером и дает этому удаленную ссылку. Прокси-сервер создает объект прокси (новый удаленный объект, находящийся в прокси-сервере), который реализует те же самые удаленные интерфейсы как оригинал. Прокси-сервер возвращает удаленную ссылку для нового объекта прокси к внутреннему серверу, который передает это к внешнему миру (так или иначе).

Когда посторонний делает запрос к прокси, прокси сразу вперед звонок в его исходный объект на внутреннем сервере. Использование прокси прозрачно постороннему (но не к внутреннему серверу, кто должен решить, передать ли исходную ссылку или ссылку прокси когда говорящий с кем-либо).

Само собой разумеется это требует значительной установки и сотрудничества локальных администраторов сети.

C.12 Так, что я должен сделать, чтобы заставить Java RMI работать через два брандмауэра?

Прежде всего, какое сотрудничество можно ожидать от брандмауэра клиентской стороны?

В самом пессимистическом случае брандмауэр клиентской стороны не позволяет прямых соединений TCP и имеет только прокси-сервер HTTP так, чтобы firewalled клиенты могли "бродить по сети". В этом случае Ваш узел сервера получит соединения в порту 80 содержащий Java запросы RMI, встроенные в запросы HTTP. Можно использовать сервер HTTP с java-rmi.cgi программа, или можно выполнить Java сервер RMI непосредственно на порту 80. Так или иначе сервер не может использовать объекты обратного вызова, экспортируемые клиентами..

Более оптимистический случай - то, что клиент может сделать прямые связи с сервером, но не может получить входящие соединения от сервера. В этом случае объекты обратного вызова не обычно возможны также.

Самый консервативный подход, не принимая справки от клиентских администраторов брандмауэра:

C.13 - это возможный заменить java-rmi.cgi сценарий, который идет с распределением JDK с сервлетом?

Мы обеспечили пример, который демонстрирует, как реализовать java-rmi.cgi сценарий используя сервлет. Пример также объясняет, как выполнить удаленный объект в сервлете VM.

Отметьте: Если Вы не понимаете роль это java-rmi.cgi игры в туннелирующих удаленных вызовах метода по HTTP, пожалуйста, см. вопрос о FAQ расценить HTTP, туннелирующий в Java RMI.

D.1 Является там способом получить автоматическое уведомление, как только удаленный VM перестал работать?

Не в это время.

D.2 Изнутри виртуальной машины, новая виртуальная машина может быть порождена на удаленной машине?

JDK включает активизацию объектов, и есть несколько учебных руководств, объясняющих, как использовать это.

D.3 для удаленного объекта возможно быть уведомленным, когда все клиенты разъединяются?

Да. Ваш удаленный объект должен будет реализовать java.rmi.server.Unreferenced интерфейс (в дополнение к любым другим необходимым интерфейсам). Java RMI обеспечит уведомление, вызывая unreferenced метод, когда все клиенты разъединяются. Ваша реализация unreferenced метод определит, какое действие Ваш удаленный объект должен брать получение такого уведомления. Однако, если есть ссылка в реестре, то Unreferenced.unreferenced метод никогда не будут вызывать.

D.4, Почему моя программа сервера не выходит, когда все клиенты разъединяются?

В Java RMI сервер должен выйти VM, если есть Однако, только потому что нет никаких локальных или удаленных ссылок на удаленный объект, не означает, что объект будет собран "мусор" своевременно. Это действительно означает, что память удаленного объекта может быть собрана, чтобы удовлетворить выделение памяти, которое иначе перестало бы работать (с OutOfMemoryError).

Хотя API Java не определяет своевременность набора так или иначе, есть определенная причина, какой может походить на неопределенно задержанный набор удаленных объектов в JDK v1.1 реализация. Под покрытиями Java время выполнения RMI содержит слабую ссылку на экспортируемые удаленные объекты в таблице (чтобы отследить локальные так же как удаленные ссылки на объект). Единственный механизм слабой ссылки, доступный в JDK v1.1 VM, использует неагрессивную, кэширующуюся политику набора (подходящий для браузера), таким образом, объекты, которые только "слабо достижимы", не будут собраны, пока локальный GC не решает, что это действительно нуждается в той памяти, чтобы удовлетворить другое выделение. Для неактивного сервера это никогда не могло происходить. Но если память будет необходима, то серверный объект, на который нессылаются, будет собран.

Платформа SE Java включает новую инфраструктуру, что Java, который RMI будет использовать, чтобы сократить значительно количество условий, при которых происходит эта проблема.

D.5, Как распределенный сборщик "мусора" обнаруживает клиент, который разъединяется? Это желательный, чтобы использовать System.exit для корректного клиентского завершения?

Когда Java, время выполнения RMI в клиенте, VM обнаруживает, что на удаленный объект больше не ссылаются локально, это асинхронно, уведомляет сервер относительно быстро так, чтобы сервер мог обновить набор объекта, на который ссылаются, соответственно. Распределенный сборщик "мусора" использует арендный договор, связанный с каждой сохраненной клиентом ссылкой удаленного объекта, и возобновляет арендные договоры удаленным объектам, в то время как клиент все еще содержит такие ссылки. Цель механизма возобновления арендного договора состоит в том, чтобы позволить серверу обнаруживать аварийное завершение клиентов, так, чтобы сервер не держался за удаленный объект навсегда из-за клиента, который не смог отправить соответствующее сообщение, на которое "нессылаются" прежде, чем это прекратило работать. В этом контексте, клиент, вызывающий System.exit() считается аварийным завершением, потому что оно не позволяет времени выполнения RMI отправлять соответствующие сообщения, на которые "нессылаются", серверу. Выполнение System.runFinalizersOnExit в клиенте прежде, чем завершение не достаточно, потому что не вся необходимая обработка обрабатывается в финализаторе; то есть сообщение, на которое "нессылаются", не будет отправлено серверу. (Используя "runFinalizersOnExit" является обычно опрометчивым и склонным к мертвой блокировке так или иначе.)

Если Вы должны использовать System.exit() завершать клиент VM, гарантировать, что удаленные ссылки, сохраненные, в котором VM очищаются более своевременным способом, следует удостовериться, что нет никаких удаленных ссылок, все еще достижимых. Явно нулевой любые локальные ссылки, чтобы сделать их недостижимый из выполнения потоков. Это также может помочь выполнить полную сборку "мусора" и выполнить финализаторы перед выходом:

    System.gc();
    System.runFinalization();

D.6, Как мой сервер может сказать, когда клиент отказывает?

Если Вы ожидаете арендного договора клиента, чтобы закончиться, и unreferenced() метод тогда вызовет Java реализацией RMI (помните, что реестр является также клиентом с этой целью, так как это содержит ссылки для всей своей привязки).

Если клиент содержит удаленную ссылку, она также содержит арендный договор для той ссылки, которая должна быть возобновлена (связываясь с сервером и делая a dirty() вызовите). Когда заключительный арендный договор для экспортируемого объекта истек или закрылся, объект считают нессылаемым, и (если это реализует java.rmi.Unreferenced) unreferenced() метод будет вызван.

Если у двух или больше клиентов есть ссылки на тот же самый удаленный объект, unreferenced() метод не вызовут, пока все они не истекли их арендные договоры о нем. Следовательно, если Вы используете этот метод, чтобы отследить отдельные клиенты, у каждого клиента должна быть ссылка на его собственное Unreferenced объект.

D.7 unreferenced() метод не становится вызванным до спустя десять минут после того, как я прекратил использовать удаленный объект! Как я могу сократить эту задержку?

Время истечения срока арендного договора определяется сервером, где это может быть установлено, используя системное свойство, java.rmi.dgc.leaseValue, чье значение находится в миллисекундах. Установить это в более короткое время (например: 30 секунд), запустите сервер как это:
    java -Djava.rmi.dgc.leaseValue=30000 ServerMain

Значение по умолчанию является 600000 миллисекунд (или 10 минутами).

Клиент возобновит каждый арендный договор, когда он на полпути истечется. Если интервал арендного договора будет слишком короток, то клиент потратит впустую много сетевой пропускной способности, напрасно возобновляющей ее арендный договор. Если интервал арендного договора будет слишком короток, то клиент будет неспособен возобновить арендный договор вовремя, и экспортируемый объект может быть удален в результате.

Будущие выпуски Java, RMI может лишить законной силы удаленные ссылки, если они не в состоянии возобновить свои арендные договоры (чтобы сохранить ссылочную целостность); недопустимо положиться на возможность использовать устарелые ссылки на удаленные объекты.

Отметьте, что необходимо только ожидать тайм-аута, если клиентская машина отказывает. Если клиент имеет некоторый контроль, когда разъединение происходит, это может отослать DGC чистый вызов быстро, делая использование Unreferenced довольно своевременный. Можно способствовать этому процессу, обнуляя любые ссылки, которые клиент может иметь к удаленному объекту и затем вызову System.gc(). (В v1.1.x Вам, вероятно, придется выполнить финализаторы синхронно и затем выполнить GC снова.)

D.8, Почему я не могу получить немедленное оповещение, когда клиент отказывает?

Поскольку ничто, что делает сервер, не может отличить разрушенный узел от сетевой задержки.

Если или когда разрушенный клиент более поздние перезапуски и контакты сервер, сервер может вывести, что клиент потерял его состояние. Если соединение TCP считается открытое между клиентом и сервером всюду по их взаимодействию, то сервер может обнаружить клиентскую перезагрузку когда более поздняя попытка записать в сбои соединения (включая почасовый TCP keepalive пакет, если включено). Однако, Java, RMI разрабатывается, чтобы не потребовать таких постоянных соединений, поскольку это повреждает масштабируемость и не помогает очень.

Учитывая, что абсолютно невозможно немедленно определить, когда сетевая коллега отказывает или становится иначе недоступной, следует решить, как Ваше приложение должно вести себя, когда коллега прекращает отвечать.

Главные инструменты, которые Вы имеете для этой задачи, являются тайм-аутами и сбросами. После тайм-аута можно прийти к заключению, что коллега недостижима, но коллега должна знать о тайм-ауте так, чтобы это бросило пытаться достигнуть Вас. Лизинговый механизм разрабатывается, чтобы сделать это полуавтоматически.

Сброс является чисткой существующего состояния, сохраненного для коллеги. Например, клиент может вызвать сброс, когда он сначала регистрируется в его сервере, заставляя сервер отбросить любое предыдущее состояние, сохраненное для того клиента (выводившего, что клиент перезапустил без памяти предыдущего, мертвого, сеанса).

Часто, цель состоит в том, чтобы иметь и поддержать категорический список клиентов в сервере, и сохранить это актуальным без ошибки или отказа. Так как отказ и задержка могут произойти в любое время в сетевой системе, определенная степень ошибки в списке должна ожидаться. Если арендный договор или другой механизм используются, чтобы осуществить тайм-аут, то проблема утечки ресурса решается. Если бы проблема устаревших данных более серьезна - то есть, если бы это вмешалось бы в корректную работу - тогда это должно быть явно очищено в случаях, где это иначе имело бы эффект.

Например, если бизнес-объект блокируется для того, чтобы отредактировать человеком, и сеанс умирает, то блокировка должна быть повреждена так или иначе. В этом случае блокировка нуждалась бы в тайм-ауте, но если тот же самый человек сразу входит в систему и ожидает не должным быть ожидать тайм-аута, чтобы истечь, новый сеанс должен или принять блокировку или утверждать, что пользователь не содержит блокировок (позволяющий сервер безопасно уничтожить блокировку).

D.9, Как, я работаю rmic команда в пакетном файле DOS?

В пакетном файле DOS необходимо вставить команду call перед исполнимой программой для управления, чтобы возвратиться к пакетному файлу. Например:
    call rmic ClientHandler
    call rmic Server
    call rmic ServerHandler
    call rmic Client

D.10 В реализации удаленного объекта, как я могу найти имя хоста вызывающей стороны удаленного метода?

java.rmi.server.RemoteServer.getClientHost метод возвращает хост клиента для текущего вызова на текущем потоке.

D.11 Убирает Java дескриптор RMI и "inout" параметры (как CORBA)?

Java RMI не поддерживает или "inout" параметры, точно так же как остальная часть базового языка программирования Java. Все удаленные вызовы являются методами удаленного объекта. Локальные объекты передает копия, и удаленные объекты передают в отношении тупика. Для получения дополнительной информации см. Передачу параметров в Удаленном Вызове метода в Java Спецификация RMI.

D.12 Обычно в языке программирования Java, возможно бросить интерфейсный экземпляр к экземпляру класса, из которого это создавалось, и используйте результат. Почему это не работает в Java RMI?

В Java RMI клиент видит только тупик для исходного объекта. Тупик реализует только удаленные интерфейсы и их удаленные методы и не может быть брошен назад к исходному классу реализации, потому что это - только тупик.

Так, невозможно передать ссылку удаленного объекта от сервера до клиента, и затем отослать это назад к серверу и быть в состоянии бросить это назад к исходному классу реализации. Можно, тем не менее, использовать ссылку удаленного объекта на сервере, чтобы сделать удаленный звонок в объект.

Если Вы должны найти класс реализации снова, Вы должны будете сохранить таблицу, которая отображает удаленную ссылку на класс реализации.

E.1, В чем, если мой браузер не поддерживает JDK или Java версия SE, я нуждаюсь?

Попытайтесь использовать Плагин Java для браузеров, которые не поддерживают JDK или Java версия SE, в которой Вы нуждаетесь.

E.2 я могу реализовать удаленного наблюдателя / заметные объекты в Java RMI?

То, что можно сделать, "перенестись" java.util.Observable и java.util.Observer с новыми интерфейсами (Вы могли вызвать их RemoteObservable и RemoteObserver). В этих новых интерфейсах сделайте каждый бросок методов java.rmi.RemoteException. Затем, Ваши удаленные объекты могут реализовать эти интерфейсы.

Отметьте, что начиная с "обернутого" неудаленного объекта не расширяется java.rmi.server.UnicastRemoteObject, Вы должны будете явно экспортировать объект, используя exportObject метод UnicastRemoteObject. В выполнении этого, хотя, Вы проигрываете java.rmi.server.RemoteObject реализации equals, hashCode, и toString методы.

F.1 В том, какая точка является там "живым" соединением между клиентом и сервером и как соединениями управляют?

Когда клиент делает работу "поиска", соединение делается к rmiregistry на указанном узле. Вообще, новое соединение может или не может быть создано для удаленного вызова. Соединения кэшируются Java транспорт RMI для будущего использования, так, если соединение свободно правильному месту назначения для удаленного вызова, то это используется. Клиент не может явно закрыть соединение с сервером, так как соединениями управляют в Java транспортный уровень RMI. Соединения будут время, если они будут неиспользованы сроком на время.

F.2 платформа Java заменяет все удаленные объекты их тупиками во время удаленного вызова метода?

JRMP и реализации IIOP RMI Java заменят каждый удаленный объект соответствующим тупиком (того же самого протокола), даже глубоко в графиках сериализуемых объектов.

F.3, который возможно записать новому транспортному уровню для Java RMI, который не использует сокеты? Как последующий вопрос, как о транспортном уровне, который использует не TCP базируемые сокеты?

Мы разработали транспортные интерфейсы так, чтобы различные реализации этих интерфейсов могли использоваться Java RMI. В более ранних выпусках эта абстракция использовалась в наших целях и не была представлена для общего использования. Теперь, в JDK, Java RMI поддерживает фабрики сокета клиента и сервера, которые могут использоваться, чтобы сделать Java перекличками RMI не TCP базируемые сокеты.

F.4 я замечаю реестр, продолжает использовать ресурсы ЦП, как будто это опрашивало вместо того, чтобы блокировать на a select() вызвать. Реестр реализуется, опрашивая?

Java RMI не опрашивает на избранных вызовах. Есть поток, который просыпается каждый так часто и опрашивает таблицу экспортируемых удаленных объектов. Это "пожинает" поток, используется в целях распределенного сборщика "мусора".

F.5 Является там только одним сокетным соединением между клиентским процессом и сервером, независимо от того сколько тупиков существует в том клиентском процессе?

Java RMI снова использует сокетные соединения между клиентом и сервером когда бы ни было возможно. Текущая реализация создает дополнительные сокеты по требованию, когда они необходимы. Например, если существующий сокет используется вызовом тогда, новый сокет создается для нового вызова. Как правило, есть по крайней мере два сокета, открытые, так как распределенный сборщик "мусора" должен выполнить удаленные вызовы, когда удаленные объекты возвращаются из сервера. Если кэшируемое соединение остается неиспользованным сроком на время, соединение закрывается.

Г 1, Что проблемы лицензирования окружают использование Java RMI?

Java RMI является частью Java платформа SE и как таковой, подвергается условиям лицензирования J2SE.

Г 2 у меня есть однопоточная программа, которая ожидает на стандартном вводе пользовательской команды, которая будет инициировать Java вызов RMI. Однако, мой удаленный объект не может обслужить этот входящий удаленный вызов, поскольку программа, кажется, блокируется на стандартном вводе. В чем проблема?

Это - известная проблема, не с Java RMI, а с потоком, который читает стандартный ввод. Поток не уступает на чтении блокирования, но вместо этого остается рабочим, едва позволяя слушателю получить любые циклы. Мы попробовали два обходных решения, которые кажутся успешными: установите основной поток (один ввод стандарта чтения) к более низкому приоритету, или урожаю, в то время как байты не доступны в потоке прежде фактически считать это.

Г 3 я копирую элементы массива в свой удаленный сервер и изменяю значения, но постепенно увеличенные значения не копируются назад в клиент. Почему?

Неудаленные объекты передает копия, так, если Вы хотите иметь новые значения массива, отраженного в клиенте, необходимо отослать их назад как параметр возврата.

Г 4 мне разрешают иметь статические поля в удаленном интерфейсе?

Да. Инициализатор выполняется в каждом VM, который загружает удаленный интерфейс, создавая новую статическую переменную с указанными значениями. Так, у Вас есть отдельная копия этой статической переменной в каждом VM, который загружает удаленный интерфейс.

Г 5 я определяю местоположение реестра, но тогда кажется, что это не там, что происходит?

Метод LocateRegistry.getRegistry(String host) не связывается с реестром на узле, а скорее только ищет узел, чтобы удостовериться, что это существует. Так, даже при том, что этот метод успешно выполнялся, это не обязательно означает, что реестр работает на указанном узле. Это только возвращает тупик, который может тогда получить доступ к реестру.

Г 6 я не могу найти ответ на свой вопрос здесь, там какие-либо другие ресурсы?

Огромное количество информации может быть найдено от гиперпочтового архива списка рассылки ПОЛЬЗОВАТЕЛЕЙ RMI.

Пользователи и Java RMI и объектной сериализации могут обсудить проблемы и подсказки с другими пользователями через список рассылки rmi-users@java.sun.com. Можно подписаться, отправляя электронное письмо, содержащее строку

    subscribe RMI-USERS
к listserv@java.sun.com, и отпишитесь, отправляя сообщение, содержащее строку
    unsubscribe RMI-USERS

Объектная Сериализация

1. Почему должен реализация классов Serializable чтобы быть записанным ObjectOutputStream?

Решение потребовать, чтобы классы реализовали java.io.Serializable интерфейс не был сделан слегка. Проект, требовавшийся баланс между потребностями разработчиков и потребностями системы быть в состоянии обеспечить предсказуемый и безопасный механизм. Самое трудное конструктивное ограничение, чтобы удовлетворить было безопасностью классов для языка программирования Java.

Если классы должны были быть отмечены как являющийся сериализуемым команда разработчиков, взволнованная, что разработчик, или из забвения, лени, или из невежества не мог бы объявить класс, как являющийся Serializable и затем сделайте тот класс бесполезным для RMI или в целях персистентности. Мы волновались, что требование поместит в разработчика бремя знания, как класс должен был использоваться другими в будущем, чрезвычайно непостижимом условии. Действительно, наш предварительный проект, как отражено в альфа-API, пришел к заключению, что случай по умолчанию для класса должен быть то, что объекты в классе сериализуемы. Мы изменили наш проект только после соображений безопасности и правильности, убежденной нас, что значение по умолчанию должно было быть то, что объект не был сериализирован.

Ограничения безопасности

Первое рассмотрение, которое заставило нас изменять поведение по умолчанию объектов, к которым имеют отношение безопасность, и в особенности в конфиденциальности полей, которые, как объявляют, были частными, пакет, защищенный, или защищенный. Платформа Java ограничивает доступ к таким полям или для чтения или для записи к подмножеству объектов в пределах времени выполнения.

Никакое такое ограничение не может быть сделано на объекте, как только он был сериализирован; поток байтов, который является результатом объектной сериализации, может быть считан и изменен любым объектом, у которого есть доступ к тому потоку. Это предоставляет любой объектный доступ к состоянию сериализированного объекта, который может нарушить пользователей гарантий конфиденциальности языка, ожидают. Далее, байты в потоке могут быть изменены произвольными способами, позволяя реконструкцию объекта, который никогда не создавался в пределах защит платформы Java. Есть случаи, в которых воссоздание такого объекта могло поставить под угрозу не только гарантии конфиденциальности, ожидаемые пользователями платформы Java, но целостность платформы непосредственно.

Эти нарушения не могут быть предотвращены, так как вся эта мысль о сериализации состоит в том, чтобы позволить объекту быть преобразованным в форму, которая может быть перемещена за пределами платформы Java (и поэтому за пределами гарантий конфиденциальности и целостности той среды) и затем возвращена в среду. Требование, чтобы объекты были объявлены сериализуемый, действительно означает, что разработчик класса должен принять активное решение позволить возможность такого нарушения в конфиденциальности или целостности. Разработчик, который не знает о сериализации, не должен быть открытым, чтобы пойти на компромисс из-за этого отсутствия знаний. Кроме того, мы надеялись бы, что разработчик, который объявляет, что класс сериализуем, делает так после некоторой мысли о возможных последствиях того объявления.

Отметьте, что этот вид проблемы безопасности не является тем, с которым может иметь дело механизм менеджера безопасности. Так как сериализация предназначается, чтобы позволить транспорт объекта от одной виртуальной машины до некоторого другого (или по пространству, поскольку это используется в RMI, или в течение долгого времени, как тогда, когда поток сохраняется к файлу), механизмы, используемые для безопасности, должны быть независимыми от среды выполнения любой определенной виртуальной машины. Мы хотели избежать в максимально возможной степени проблемы возможности сериализировать объект в одной виртуальной машине и не бывший способный десериализовывать тот объект в некоторой другой виртуальной машине. Так как менеджер безопасности является частью среды выполнения, используя менеджера безопасности для сериализации нарушил бы это требование.

Принуждение сознательного решения

В то время как проблемы безопасности были первой причиной рассмотрения изменения проекта, причина, что мы чувствуем, состоит, по крайней мере в том, как убеждение состоит в том, что сериализация должна только быть добавлена к классу после некоторого рассмотрения проекта. Слишком легко разработать класс, который разваливается при сериализации и реконструкции. Требуя, чтобы разработчик класса объявил поддержку интерфейса сериализации, мы надеялись, что разработчик также уделит некоторое внимание процессу сериализации того класса.

Примеры легко привести. Много классов имеют дело с информацией, которая только имеет смысл в контексте времени выполнения, в которое существует определенный объект; примеры такой информации включают дескрипторы файлов, открытые сокетные соединения, информацию о безопасности, и т.д. С такими данными можно иметь дело легко, просто объявляя поля как transient, но такое объявление только необходимо, если объект собирается быть сериализированным. Новичок (или забывчивый, или поспешил) программист мог бы забыть отмечать поля как transient почти таким же способом он или она мог бы забыть отмечать класс как реализацию Serializable интерфейс. Такой случай не должен привести к неправильному поведению; способ избежать этого не состоит в том, чтобы сериализировать объекты, не отмеченные как реализация Serializable.

Другим примером этого вида является "простой" объект, который является корнем графика, который охватывает большое количество объектов. Сериализация такого объекта могла привести к сериализации большого количества других, начиная с работ сериализации по всему графику. Выполнение чего-то вроде этого должно быть сознательным решением, не тем, которое происходит по умолчанию.

Потребность в этом виде мысли была приведена домой нам в группе, когда мы проходили через основные библиотеки классов API Java, отмечая системные классы как сериализуемые (где необходимо). Мы первоначально думали, что это будет довольно простым процессом, и что большинство системных классов могло только быть отмечено как реализация Serializable и затем используйте реализацию по умолчанию без других изменений. То, что мы нашли, было то, что это было намного менее часто случаем, чем мы подозревали. В большом количестве классов осторожная мысль должна была быть дана тому, должно ли поле быть отмечено как transient или ли имело смысл сериализировать класс вообще.

Конечно, нет никакого способа гарантировать, что разработчик программиста или класса фактически собирается думать об этих проблемах, отмечая класс как сериализуемый. Однако, требуя, чтобы класс объявил себя как реализация Serializable интерфейс мы действительно требуем, чтобы некоторая мысль была дана программистом. Наличие сериализации быть состоянием по умолчанию объекта означало бы, что нехватка мысли могла вызвать плохие эффекты в программе, что-то, чего общий замысел платформы Java попытался избежать.

2. Который JDK v1.1 системные классы отмечаются сериализуемые?

Удаленный. Эта информация легко доступна из документации API, сгенерированной javadoc инструмент.

3. У меня есть проблемы, десериализовывая JDK v1.0.2 AWT компоненты. Как я могу сделать эту работу?

То, когда Вы сериализируете виджеты AWT, также сериализированный Коллега, возражает, что отображают функции AWT на локальную оконную систему. Когда Вы десериализовываете (воссоздают) виджеты AWT, старые Коллеги воссоздаются, но они являются устаревшими. Коллеги являются собственными к локальной оконной системе и содержат указатели на структуры данных в локальном адресном пространстве, и поэтому не могут быть перемещены.

Как работа вокруг, следует сначала удалить высокоуровневый виджет из его контейнера (таким образом, виджеты больше не "живы"). Коллеги отбрасываются в этой точке, и Вы сохраните только состояние виджета AWT. Когда Вы позже десериализовываете и читаете, виджеты въезжают задним ходом, добавляют высокоуровневый виджет к фрейму, чтобы заставить виджеты AWT появиться. Вы, возможно, должны добавить a show вызвать.

В JDK v1.1 и позже, виджеты AWT сериализуемы. java.awt.Component реализации класса Serializable.

4. Объектная сериализация поддерживает шифрование?

Объектная сериализация не содержит шифрования/дешифрования сам по себе. Это пишет в и читает из стандартных потоков в API Java, таким образом, это может быть вместе с любой доступной технологией шифрования. Объектная сериализация может использоваться многими различными способами. Кроме только записи и чтения к и от файлов, это может также использоваться для Java RMI, чтобы связаться между узлами.

Использование RMI листового шифрования сериализации и дешифрование к более низкому сетевому транспорту. Мы ожидаем, что, когда безопасный канал необходим, сетевые соединения будут сделаны, используя SSL и т.п. (см. Используя RMI с SSL).

5. Объектные классы сериализации являются потоковыми. Как я пишу объекты в файл произвольного доступа?

В настоящий момент нет никакого прямого способа записать объекты в файл произвольного доступа.

Можно использовать ByteArrayInputStream и ByteArrayOutputStream объекты как промежуточное звено помещают в запись, и считайте байты в и от файла произвольного доступа и создайте ObjectInputStreams и ObjectOutputStreams от потоков байтов, чтобы транспортировать объекты. Только необходимо удостовериться, что у Вас есть весь объект в потоке байтов, или чтение/запись объекта перестанет работать.

Например, java.io.ByteArrayOutputStream может использоваться, чтобы получить байты ObjectOutputStream. От этого можно получить результат в форме байтового массива. Это поочередно может использоваться с ByteArrayInputStream как входной к ObjectInput поток.

6. Когда локальный объект сериализируется и передается в качестве параметра в Java вызов RMI, байт-коды для методов локального объекта, которые также передают? Что относительно объектной последовательности, если удаленное приложение VM "сохраняет" объектный дескриптор?

Байт-коды для методов локального объекта не передают непосредственно в ObjectOutputStream, но класс объекта, возможно, должен быть загружен получателем, если класс не уже доступен локально. Файлы самого класса не сериализируются, только имена классов. Все классы должны быть в состоянии быть загруженными во время десериализации, используя нормальные механизмы загрузки класса. Для апплетов это означает, что они загружаются AppletClassLoader.

Нет никаких гарантий последовательности локальных объектов, которые передают к удаленному VM, так как такие объекты передают, копируя их содержание (истинная передача значением).

7. Как может я создавать ObjectInputStream от ObjectOutputStream без файла промежуточный?

ObjectOutputStream и ObjectInputStream работайте к/от любому потоковому объекту. Вы могли использовать a ByteArrayOutputStream и затем получите массив и вставьте его в a ByteArrayInputStream. Вы могли также использовать переданные по каналу потоковые классы также. Любой java.io класс, который расширяется OutputStream и InputStream классы могут использоваться.

8. Я создаю объект и затем отправляю его через сеть, используя writeObject метод и получает это использующий readObject метод. Если я тогда изменяю значение поля в объекте и отправляю это как прежде, объект что readObject возвраты метода, кажется, то же самое как первый объект и не отражают новое значение поля. Я должен испытывать это поведение?

ObjectOutputStream класс отслеживает каждый объект, это сериализирует и отправляет только дескриптор, если тот объект замечается снова. Это - способ, которым это имеет дело с графиками объектов. Соответствие ObjectInputStream отслеживает все объекты, которые это создало и их дескрипторы так, когда дескриптор замечается снова, это может возвратить тот же самый объект. И выходные и входные потоки сохраняют это состояние, пока они не освобождаются.

Альтернативно, ObjectOutputStream класс реализует a reset метод, который отбрасывает память того, что отправил объект, таким образом отправляя объект снова, сделает копию.

9. Там какие-либо планы состоят в том, чтобы поддерживать сериализацию объектов потока?

Потоки НЕ будут сериализуемы. В существующей реализации, если Вы пытаетесь сериализировать и затем десериализовать поток, нет НИКАКОГО явного выделения нового собственного потока или стека; все, что происходит, - то, что объект является выделенными системными ресурсами ни с одной из собственной реализации. Короче говоря, это только не будет работать и перестанет работать непредсказуемыми способами.

Трудность с потоками состоит в том, что у них есть так много состояния, которое запутанно связывается в виртуальную машину, что это является трудным или невозможным восстановить контекст где-то в другом месте. Например, сохранение стека вызовов VM недостаточно потому что, если были собственные методы, которые вызвали процедуры C, которые поочередно вызывали код для платформы Java, будет невероятное соединение конструкций языка программирования Java и указателей C, чтобы иметь дело с. Кроме того, сериализация стека подразумевала бы сериализацию любого объекта, достижимого от любой переменной стека.

Если бы поток был возобновлен в том же самом VM, то он совместно использовал бы много состояния с исходным потоком, и поэтому перестал бы работать непредсказуемыми способами, если бы оба потока работали сразу, точно так же как два потока C, пытающиеся совместно использовать стек. Когда десериализовано в отдельном VM, трудно сказать то, что могло бы произойти.

10. Я могу вычислить разность (последовательный (x), последовательный (y))?

Разность произведет тот же самый поток каждый раз, когда тот же самый объект сериализируется. Вы должны будете создать новое ObjectOutputStream сериализировать каждый объект.

11. Я могу сжать последовательное представление своих объектов, используя мою собственную zip и разархивировать методы?

ObjectOutputStream производит OutputStream; если Ваш объект zip расширяется OutputStream класс там не является никакой проблемой, сжимающей это.

12. Я могу выполнить методы на сжатых версиях моих объектов, например isempty (zip (последовательный (x)))?

Это не действительно жизнеспособно для произвольных объектов из-за кодирования объектов. Для определенного объекта (такого как Строка) можно сравнить получающиеся потоки битов. Кодирование устойчиво в тот каждый раз, когда тот же самый объект кодируется, это кодируется к тому же самому набору битов.

13. Если я пытаюсь сериализировать шрифт или объект изображения и затем попытаться воссоздать это в различном VM, мое приложение умирает. Почему?

Удаленный. Шрифты теперь сериализуемы, но изображения не.

14. Как я сериализирую дерево объектов?

Вот краткий пример, который показывает, как сериализировать дерево объектов.

import java.io.*;

class tree implements java.io.Serializable {
    public tree left;
    public tree right;
    public int id;
    public int level;

    private static int count = 0;

    public tree(int depth) {
        id = count++;
        level = depth;
        if (depth > 0) {
            left = new tree(depth-1);
            right = new tree(depth-1);
        }
    }

    public void print(int levels) {
        for (int i = 0; i < level; i++)
            System.out.print("  ");
        System.out.println("node " + id);

        if (level <= levels && left != null)
            left.print(levels);

        if (level <= levels && right != null)
            right.print(levels);
    }


    public static void main (String argv[]) {

        try {
            /* Create a file to write the serialized tree to. */
            FileOutputStream ostream = new FileOutputStream("tree.tmp");
            /* Create the output stream */
            ObjectOutputStream p = new ObjectOutputStream(ostream);

            /* Create a tree with three levels. */
            tree base = new tree(3);

            p.writeObject(base); // Write the tree to the stream.
            p.flush();
            ostream.close();    // close the file.
            
            /* Open the file and set to read objects from it. */
            FileInputStream istream = new FileInputStream("tree.tmp");
            ObjectInputStream q = new ObjectInputStream(istream);
            
            /* Read a tree object, and all the subtrees */
            tree new_tree = (tree)q.readObject();

            new_tree.print(3);  // Print out the top 3 levels of the tree
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

15. Если класс A не реализует Serializable но подкласс B реализации Serializable, поля класса A будут сериализированы, когда B будет сериализирован?

Только поля Serializable объекты выписываются и восстанавливаются. Объект может быть восстановлен, только если у класса A есть конструктор без аргументов, который инициализирует поля несериализуемых супертипов. Если у подкласса есть доступ к состоянию суперкласса, это может реализовать writeObject и readObject сохранить и восстановить то состояние.

Oracle и/или его филиалы Авторское право © 1993, 2011, Oracle и/или его филиалы. Все права защищены.
Свяжитесь с Нами