Как я могу запустить свой код при загрузке класса?

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

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

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

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

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


person Henrik Paul    schedule 26.10.2010    source источник
comment
Хм, вы пытались использовать статический блок инициализации?   -  person Kel    schedule 26.10.2010


Ответы (2)


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

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"
)

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

person Sean Patrick Floyd    schedule 26.10.2010
comment
(Просто добавил больше информации в OP) статические блоки или абстрактные классы не подойдут. Вы правильно поняли - это будет сделано для интерфейса клиентского кода. - person Henrik Paul; 26.10.2010
comment
В настоящее время я занимаюсь регистрацией (за исключением того, что у меня еще нет аннотаций, и они зарегистрированы в определяемых клиентом парах), и это работает хорошо. Думал автоматизировать это. Но этот метод сканирования пакетов кажется довольно привлекательным (если не считать усложнения рефакторинга). Я посмотрю на это решение. Увы, и здесь пока нет приема. - person Henrik Paul; 26.10.2010
comment
Расслабься, ты только что задал вопрос час назад, не нужно ничего принимать сейчас. Кстати: даже если вы это сделаете, вы можете отменить ответ позже. - person Sean Patrick Floyd; 26.10.2010
comment
Будет ли это действительно скомпилировано? - person Andremoniy; 16.12.2015
comment
@SeanPatrickFloyd правда? Вы не можете использовать блок static внутри блока interface. Вы пробовали? - person Andremoniy; 16.12.2015

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

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

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

person Tomas Narros    schedule 26.10.2010
comment
Спасибо. Я попробую. Однако я пока не приму этот ответ. - person Henrik Paul; 26.10.2010