Возьмем следующий код:
public class Main {
public static final List<Object> configuration = new ArrayList<>();
public static void main(String[] args) {
System.out.println(configuration);
}
}
Теперь я хочу иметь возможность предоставлять «самоконфигурируемые» классы.Это означает, что они должны иметь возможность просто предоставить что-то вроде статического блока, который будет вызываться автоматически следующим образом:
public class Custom {
static {
Main.configuration.add(Custom.class);
}
}
Если вы выполните этот код, список конфигурации будет пуст (из-за способ выполнения статических блоков ).Класс "достижим", , но не "загружен" .Вы можете добавить следующее к классу Main перед System.out
Class.forName("Custom");
, и теперь список будет содержать объект класса Custom (поскольку класс еще не инициализирован, этот вызов инициализирует его).Но поскольку элемент управления должен быть обратным (пользовательский интерфейс должен знать Main, а не наоборот), этот подход непригоден для использования.Custom никогда не следует вызывать напрямую из Main или любого другого класса, связанного с Main.
Хотя это возможно, можно сделать следующее: вы можете добавить аннотацию к классу и собрать все классы с указанной аннотацией, используячто-то вроде ClassGraph Framework и вызов Class.forName
для каждого из них.
TL; DR
Есть ли способ автоматического вызова статического блока без необходимостипроанализировать все классы и необходимость знания конкретного, «самоконфигурируемого» класса?Идеальный подход - это подход, который при запуске приложения автоматически инициализирует классы (если они снабжены определенной аннотацией).Я думал о пользовательских ClassLoaders, но из того, что я понимаю, они ленивы и поэтому не могут использоваться для этого подхода.
Подоплекой этого является то, что я хочу включить его в аннотациюпроцессор, который создает «самоконфигурируемый код».
Пример ( предупреждение : дизайн-разговор и углубленно)
Чтобы сделать это немного менее абстрактным, представьте следующее:
Вы разрабатываете Framework.Давайте назовем это Foo.Foo имеет классы GlobalRepository и Repository.GlobalRepository следует шаблону проектирования Singleton (только статические методы).Репозиторий, как и GlobalRepository, имеет методы «void add (Object)» и «T get (Class)».Если вы вызываете get в репозитории и класс не может быть найден, он вызывает GlobalRepository.get (Class).
Для удобства вы хотите предоставить аннотацию с именем @Add.Эта аннотация может быть размещена в объявлениях типов (или классах).Процессор аннотаций создает некоторые конфигурации, которые автоматически добавляют все аннотированные классы в GlobalRepository и, следовательно, сокращают стандартный код.Это должно произойти только (во всех случаях) один раз.Для этого в сгенерированном коде есть статический инициализатор, в котором заполнен глобальный репозиторий, как если бы вы делали это с локальным репозиторием.Поскольку ваши Конфигурации имеют имена, которые спроектированы настолько уникальными, насколько это возможно, и по какой-то причине даже содержат дату создания (это немного произвольно, но оставайтесь со мной), их почти невозможно угадать.
Таким образом, вы также добавляете аннотацию к этим Конфигурациям, которая называется @AutoLoad.Требуется, чтобы использующий разработчик вызвал GlobalRepository.load (), после чего все классы анализируются, и все классы с этой аннотацией инициализируются, и для этого вызываются их соответствующие статические блоки.
Это не очень масштабируемыйподход.Чем больше приложение, тем больше область поиска, тем дольше время и т. Д.Лучше было бы, чтобы при запуске приложения все классы автоматически инициализировались.Как через ClassLoader.Что-то вроде этого - то, что я ищу.