Как можно (и можно ли вообще) написать 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;
    }
}

Для того, чтобы сделать это аннотация должна создавать в классе:

  1. Переменную private static volatile Singleton instance = null;
  2. private constructor:
    private Singleton(){
    }
    
  3. геттер
    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 шт):

Автор решения: EsReich

Я могу ошибаться, но, насколько я понимаю, сами по себе аннотации ничего не делают. Это просто некий вариант интерфейса (о чём говорит их объявление @interface). Подобно тому, как для интерфейса необходимо предоставить класс-реализацию, для аннотации необходим перехватчик. Его можно реализовать с помощью АОП (используя Spring AOP или AspectJ). Тогда для каждого вызова объекта аннотированного класса будет возвращаться не сам объект, а его прокси с накрученной логикой, сгенерированный неявно (точнее в данном случае будет возвращаться синглтон). Либо можно реализовать свой кастомный Spring scope для потокобезопасного синглтона. При настройке бинов Spring также использует проксирование. Наверняка есть ещё какие-то способы.

→ Ссылка
Автор решения: Sergey Zh.

Да, возможно.

Но надо понимать, что аннотация - это метаинформация, то есть это не "кусок кода", а скорее сообщение для остального кода, что на этом коде стоит метка (в вашем случае метка - @MySingleton)

Поэтому помимо самой аннотации нужен класс обработчик, который и будет выполнять бизнес-логику по обработке класса, над которым стоит эта аннотация (метка).

Для того, чтобы сделать это аннотация должна создавать в классе:

Вот это не верно, аннотация ничего создавать не будет, этим занимается класс обработчик.

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

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

В принципе, по этой логике (аннотация - обработчики) строятся все современные фреймворки на джаве (JUnit, Spring, Hibernate...)

→ Ссылка