Подтвердить что ты не робот

Singleton: как остановить создание экземпляра через Reflection

Я знаю, что в Java мы можем создать экземпляр класса new, clone(), Reflection и serializing and de-serializing.

Я создал простой класс, реализующий Singleton.

И мне нужно полностью остановить экземпляр моего класса.

public class Singleton implements Serializable{
    private static final long serialVersionUID = 3119105548371608200L;
    private static final Singleton singleton = new Singleton();
    private Singleton() { }
    public static Singleton getInstance(){
        return singleton;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException("Cloning of this class is not allowed"); 
    }
    protected Object readResolve() {
        return singleton;
    }
    //-----> This is my implementation to stop it but Its not working. :(
    public Object newInstance() throws InstantiationException {
        throw new InstantiationError( "Creating of this object is not allowed." );
    }
}

В этом классе мне удалось остановить экземпляр класса new, clone() и serialization, но я не смог остановить его с помощью Reflection.

Мой код для создания объекта

try {
    Class<Singleton> singletonClass = (Class<Singleton>) Class.forName("test.singleton.Singleton");
    Singleton singletonReflection = singletonClass.newInstance();
} catch (ClassNotFoundException e) {
    e.printStackTrace();
} catch (InstantiationException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
}
4b9b3361

Ответ 1

Попробуйте создать свой публичный конструктор

private Singleton() {
    if( Singleton.singleton != null ) {
        throw new InstantiationError( "Creating of this object is not allowed." );
    }
}

Ответ 2

Определите синглтон следующим образом:

public enum Singleton {
    INSTANCE
}

Ответ 3

Как насчет проверки в конструкторе:

private Singleton() {
    if (singleton != null) {
        throw new IllegalStateException("Singleton already constructed");
    }
}

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

(EDIT: Как сказал Божо, окончательные поля могут быть недоступны даже при отражении. Я не удивлюсь, если есть какой-то способ сделать это через JNI и т.д., хотя... если вы дадите людям достаточно доступа, я смогу сделать почти что угодно...)

Ответ 4

private Singleton() { 
    if (Singleton.singleton != null) {
        throw new RuntimeException("Can't instantiate singleton twice");
    }
}

Еще одна вещь, которую вы должны посмотреть - это метод readResolve(..), потому что ваш класс реализует Serialiable. Там вы должны вернуть существующий экземпляр.

Но самый простой способ использования синглонов - перечислить - вы не беспокоитесь об этом.

Ответ 5

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

В шаблоне monostate все поля в вашем классе static. Это означает, что все экземпляры класса имеют одно и то же состояние, как с одним синглоном. Более того, этот факт прозрачен для вызывающих; им не нужно знать о специальных методах, таких как getInstance, они просто создают экземпляры и работают с ними.

Но, как и в случае с singleton, это форма скрытого глобального состояния; что очень плохо.

Ответ 6

I Thing Ниже код будет работать.

class Test {

    static private Test t = null;
    static {
        t = new Test();
    }

    private Test(){}

    public static Test getT() {
        return t;
    }

    public String helloMethod() {
        return "Singleton Design Pattern";
    }
}


public class MethodMain {

    public static void main(String[] args) {
        Test t = Test.getT();
        System.out.println(t.helloMethod());
    }
}

: Шаблон проектирования Singleton

Ответ 7

Мы можем разбить его, используя статический вложенный класс

Пожалуйста, следуйте приведенному ниже коду, его 100% правильно, я протестировал

package com.singleton.breakable;

import java.io.Serializable;

class SingletonImpl implements Cloneable, Serializable {

    public static SingletonImpl singleInstance = null;

    private SingletonImpl() {

    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return singleInstance;
    };

    public Object readResolve() {
        return SingletonImpl.getInstance(); // 
    }

    public static SingletonImpl getInstance() {

        if (null == singleInstance) {
            singleInstance = new SingletonImpl();
        }
        return singleInstance;
    }

}


package com.singleton.breakable;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;

class FullySingletonClass {

    public static void main(String[] args) {

        SingletonImpl object1 = SingletonImpl.getInstance();
        System.out.println("Object1:" + object1);

        try {
            FileOutputStream fos = new FileOutputStream("abc.txt");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(object1);

            FileInputStream fis = new FileInputStream("abc.txt");
            ObjectInputStream ois = new ObjectInputStream(fis);
            SingletonImpl object2 = (SingletonImpl) ois.readObject();
            System.out.println("Object2" + object2);

        } catch (Exception e) {
            // TODO: handle exception
        }
        try {
            Constructor[] constructors = SingletonImpl.class.getDeclaredConstructors();
            for (Constructor constructor : constructors) {
                // Below code will not destroy the singleton pattern
                constructor.setAccessible(true);
                SingletonImpl Object3 = (SingletonImpl) constructor.newInstance();
                System.out.println("Object3: Break through Reflection:" + Object3);
                break;
            }
        } catch (Exception ew) {

        }

    }
}

**OUTPUT**
Object1:[email protected]
[email protected]
Object3: Break through Reflection:[email protected]

Ответ 8

Просто отметим, что с Java 8 и, согласно моей проверке, вы не можете создать экземпляр Singleton через Reflections, если у него есть частный конструктор.

Вы получите это исключение:

Exception in thread "main" java.lang.IllegalAccessException: Class com.s.Main can not access a member of class com.s.SingletonInstance with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at com.s.Main.main(Main.java:6)

Ответ 9

Here Reflection not work     

    package com.singleton.nonbreakable;

        import java.io.FileInputStream;
        import java.io.FileOutputStream;
        import java.io.ObjectInputStream;
        import java.io.ObjectOutputStream;
        import java.lang.reflect.Constructor;

        class FullySingletonClass {

            public static void main(String[] args) {

                SingletonImpl object1 = SingletonImpl.getInstance();
                System.out.println("Object1:" + object1);

                try {
                    FileOutputStream fos = new FileOutputStream("abc.txt");
                    ObjectOutputStream oos = new ObjectOutputStream(fos);
                    oos.writeObject(object1);

                    FileInputStream fis = new FileInputStream("abc.txt");
                    ObjectInputStream ois = new ObjectInputStream(fis);
                    SingletonImpl object2 = (SingletonImpl) ois.readObject();
                    System.out.println("Object2" + object2);

                } catch (Exception e) {
                    // TODO: handle exception
                }
                try {
                    Constructor[] constructors = SingletonImpl.class.getDeclaredConstructors();
                    for (Constructor constructor : constructors) {
                        // Below code will not destroy the singleton pattern
                        constructor.setAccessible(true);
                        SingletonImpl Object3 = (SingletonImpl) constructor.newInstance();
                        System.out.println("Object3:" + Object3);
                        break;
                    }
                } catch (Exception ew) {

                }

            }
        }


    package com.singleton.nonbreakable;

    import java.io.Serializable;

    class SingletonImpl implements Cloneable, Serializable {

        public static SingletonImpl singleInstance = null;

        private static class SingletonHolder {
            public static SingletonImpl getInstance() {
                if (null == singleInstance) {
                    singleInstance = new SingletonImpl();
                }
                return singleInstance;
            }
        }

        private SingletonImpl() {

        }

        @Override
        protected Object clone() throws CloneNotSupportedException {
            return singleInstance;
        };

        public Object readResolve() {
            System.out.println("Executing readResolve again");
            return SingletonImpl.getInstance(); // FIXME
        }

        public static SingletonImpl getInstance() {

            return SingletonHolder.getInstance();
        }

    }

    Output : 
    Object1:[email protected]
    Executing readResolve again
    [email protected]