Как я могу запустить свой код при загрузке класса? - PullRequest
8 голосов
/ 26 октября 2010

Есть ли способ запустить мой собственный код всякий раз, когда какой-либо класс загружается в Java, не заставляя пользователя явно и вручную загружать все классы с помощью пользовательского загрузчика классов?

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

Редактировать: Черт, я пойду к деталям: я делаю библиотеку обработки событий. То, что я делаю, - это чтобы клиентский код делал свои собственные пары Listener / Event, которые должны быть зарегистрированы в моей библиотеке как пара. (Хм, это было не так долго, в конце концов).

Дальнейшее редактирование: В настоящее время клиентскому коду необходимо зарегистрировать пару классов / интерфейсов вручную, что работает довольно хорошо. Я намереваюсь автоматизировать это, и я подумал, что соединение двух классов с аннотациями поможет. Далее я хочу избавиться от клиентского кода, необходимого для постоянного обновления списка регистраций.

PS: Статический блок не подходит, поскольку мой интерфейс объединен в библиотеку, а код клиента создаст дополнительные интерфейсы. Таким образом, абстрактные классы тоже не подойдут, поскольку это должен быть интерфейс.

Ответы [ 2 ]

8 голосов
/ 26 октября 2010

Если вы хотите основать поведение на интерфейсе, вы можете использовать статический инициализатор в этом интерфейсе.

public interface Foo{

    static{
        // do initializing here
    }

}

Я не говорю, что это хорошая практика, но она определенно инициализируется при первой загрузке одного из реализующих классов.

Обновление: статические блоки в интерфейсах недопустимы. Вместо этого используйте абстрактные классы!

Справка:


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

Я бы сказал, что самые чистые варианты: либо генерировать код во время сборки (с помощью обработки аннотаций с помощью apt, либо с помощью анализа байт-кода с помощью такого инструмента, как asm), либо использовать агент во время загрузки класса для динамического создания отображения.


Ах, больше ввода. Отлично. Поэтому клиенты используют вашу библиотеку и предоставляют сопоставления на основе аннотаций. Тогда я бы сказал, что ваша библиотека должна предоставить метод инициализатора, где клиентский код может регистрировать классы. Примерно так:

YourLibrary.getInstance().registerMappedClasses(
    CustomClass1.class,
    CustomClass2.class,
    CustomClass3.class,
    CustomClass4.class
)

Или, что еще лучше, механизм сканирования пакетов (пример кода для реализации этого можно найти по этому вопросу ):

YourLibrary.getInstance().registerMappedClassesFromPackages(
    "com.mycompany.myclientcode.abc",
    "com.mycompany.myclientcode.def"
)

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

2 голосов
/ 26 октября 2010

Если вы хотите, чтобы какой-то фрагмент кода запускался при загрузке любого класса, вам следует:

  1. перезаписать ClassLoader, добавив свой собственный код в методы loadClass (не забудьте переслать вродительский ClassLoader после или перед вашим пользовательским кодом).
  2. Определите этот пользовательский ClassLoader как используемый по умолчанию для вашей системы (здесь вы узнали, как это сделать: Как установить мой пользовательский загрузчик классов по умолчанию? ).
  3. Запустите и проверьте его.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...