Вход на хостинг
IT-новости
20.04.2016 iPhone 2017 года поместят в водонепроницаемый корпус из стекла
Линейка iPhone в новом году серьезно поменяется. В этом уверен аналитический исследователь Мин Чи Ку......
30.07.2015 Ищем уникальный контент для сайта
Ищем уникальный контент для сайта Без уникального контента Ваш сайт обречен на то, что его страницы......
В то же время программа постоянно развивается. Создаются новые независимые блоки, переписываются и отлаживаются старые. Возможно, программа «умеет» исполнять сторонние классы, разработанные пользователями (как делать такие вещи с помощью отражений, рассказывалось в первой части статьи). В таких условиях возникает естественное желание, чтобы подключение новых классов или новых версий старых классов не требовало полной остановки и перезапуска программы.
Что касается действительно новых классов – тут проблем нет. Вы вольны в любой момент скомпилировать новый класс с новым уникальным именем – даже когда программа уже запущена. Если ваша программа после этого выполнит вызов Class.forName(name) с этим именем (например, в результате автоматического сканирования каталогов поиска CLASSPATH в поисках новых .class-файлов), то этот класс будет успешно подключен, и программа сможет им пользоваться.
Что касается версий .class-файлов – тут все значительно хуже. Однажды обратившись к некоторому классу, стандартный системный загрузчик запомнит его в своем внутреннем кэше и будет всегда использовать именно его. Никакие последующие перекомпиляции .class-файла и даже физическое удаление этого файла не отразятся на работе этого класса. Насколько я знаю, никакими силами, кроме полного перезапуска программы (т.е. всей виртуальной машины Java), нельзя заставить системный загрузчик «забыть» тот байт-код класса, который он однажды загрузил.
Если вы когда-нибудь разрабатывали и отлаживали апплеты, возможно вы сталкивались с неприятной особенностью броузеров: не учитывать изменения в перекомпилированном классе апплета до тех пор, пока программа-броузер не будет закрыта и запущена заново. Судя по всему, происхождение этой проблемы кроется как раз в описанном поведении системного загрузчика (вместе с нежеланием разработчиков броузера рестартовать по кнопке «Refresh»/»Reload» виртуальную Java-машину).
На самом деле у такого поведения системного загрузчика есть веские причины. Это станет вполне очевидно позже, когда мы – как вы, вероятно, уже догадались – реализуем собственный загрузчик классов, лишенный описанного «недостатка». На самом деле возможность «на лету» менять реализацию классов, не перезапуская программу, может оказаться очень полезной в описанной выше ситуации. Но при этом, как мы увидим, в разработке Java-программ появляются некоторые экзотические нюансы, которые были бы совершенно неуместны в большинстве обычных программ – поэтому разработчики Java и заблокировали подобную возможность в стандартном системном загрузчике.
Итак, наша задача – написать загрузчик классов, аналогичный стандартному системному, который, в отличие от него, умел бы «забывать» загруженные ранее версии классов и загружать .class-файлы заново.
Заодно мы решим и более простую традиционную задачу – загрузку .class-файлов из собственного списка каталогов поиска. Это нам ничего не будет стоить. Какая разница – загружать файлы непременно из каталогов CLASSPATH или из каких-либо других. Мы будем учитывать, что некоторые (или все) каталоги CLASSPATH могут попасть в наш список.
Для простоты мы не будем поддерживать в этом загрузчике работу с JAR-архивами. Все-таки JAR предназначен для упаковки достаточно стабильных версий программных модулей, которые вряд ли стоит обновлять настолько часто, что ради этого нежелательно выполнять перезапуск основной Java-программы. В частности, загрузку стандартных библиотечных классов (пакеты java.lang и подобные), которые обычно находятся в JAR-файле, мы возложим на системный загрузчик.