Как можно (и можно ли вообще) написать custom annotation java @MySingleton, которая бы реализовывала паттерн Singleton?
Как можно (и можно ли вообще) написать custom annotation java @MySingleton, которая бы реализовывала паттерн Singleton (желательно thread safe version)?
Цель - написать custom annotation java @MySingleton
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface MySingleton {
//logic
}
, которая бы превращала пустой класс в Singleton:
@MySingleton
class Singleton {
}
Предполагается (но не обязательно) использовать вот этот вариант паттерна Singleton:
class Singleton {
private static volatile Singleton instance = null;
private Singleton(){
}
public static Singleton getInstance() {
//Double checked locking for correct operation in multithreaded applications
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
Для того, чтобы сделать это аннотация должна создавать в классе:
- Переменную
private static volatile Singleton instance = null; - private constructor:
private Singleton(){ } - геттер
public static Singleton getInstance() { //Double checked locking for correct operation in multithreaded applications if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; }
Например в Lombok в аннотации @Getter уже есть механизм создания геттера в классе (https://projectlombok.org/api/lombok/Getter.html).
Также в Lombok в аннотациях @NoArgsConstructor и @AllArgsConstructor уже есть механизм создания конструкторов в классе (https://projectlombok.org/api/lombok/package-summary.html).
Возможно, те же способы создания геттеров и конструкторов можно реализовать в аннотации @MySingleton.
Если все же невозможно поместить всю логику создания Singleton в одну аннотацию @MySingleton, то, может быть, можно разделить логику создания геттеров и конструкторов в аннотациях @MySingletonGetter и @MySingletonConstructor?
Ответы (2 шт):
Я могу ошибаться, но, насколько я понимаю, сами по себе аннотации ничего не делают. Это просто некий вариант интерфейса (о чём говорит их объявление @interface). Подобно тому, как для интерфейса необходимо предоставить класс-реализацию, для аннотации необходим перехватчик. Его можно реализовать с помощью АОП (используя Spring AOP или AspectJ). Тогда для каждого вызова объекта аннотированного класса будет возвращаться не сам объект, а его прокси с накрученной логикой, сгенерированный неявно (точнее в данном случае будет возвращаться синглтон). Либо можно реализовать свой кастомный Spring scope для потокобезопасного синглтона. При настройке бинов Spring также использует проксирование. Наверняка есть ещё какие-то способы.
Да, возможно.
Но надо понимать, что аннотация - это метаинформация, то есть это не "кусок кода", а скорее сообщение для остального кода, что на этом коде стоит метка (в вашем случае метка - @MySingleton)
Поэтому помимо самой аннотации нужен класс обработчик, который и будет выполнять бизнес-логику по обработке класса, над которым стоит эта аннотация (метка).
Для того, чтобы сделать это аннотация должна создавать в классе:
Вот это не верно, аннотация ничего создавать не будет, этим занимается класс обработчик.
Учитывая специфику задачи (синглтон), думаю в самом классе (над которым ставим аннотацию) нужно сделать конструктор приватным, но на этом всё - остальной код в классе обработчике.
Класс обработчик будет использовать рефлексию, чтобы получить доступ к приватному конструктору и создать инстанц.
В принципе, по этой логике (аннотация - обработчики) строятся все современные фреймворки на джаве (JUnit, Spring, Hibernate...)