Frage Richtiger Weg, ein Singleton zu einer Frühlingsbohne zu machen


Ich konvertiere ein Singleton in eine Spring-Bean, so dass, wenn das Singleton nicht initialisiert wird, der Spring-Kontext der gesamten Webanwendung nicht korrekt geladen wird.

Der Vorteil, dass der Spring-Kontext nicht ordnungsgemäß geladen wird, besteht darin, dass Benutzer die Konfiguration während der Bereitstellung selbst bemerken und beheben. Im Gegensatz zur Verwendung von 'Nicht-Spring-Beans' Singleton: Wenn während der Initialisierung eine Ausnahme ausgelöst wird, merkt dies niemand .. bis ein tatsächlicher Benutzer über fehlende Funktionalität klagt.

Meine Änderungen funktionieren wie erwartet .. aber ich bin mir nicht sicher, ob ich das Richtige mache.
Irgendwelche Gedanken?

Der Code sieht so aus:

public class MySingleton {

    private static MySingleton INSTANCE = null;
    private MySingleton(){}


public static MySingleton getInstance(){
    if(INSTANCE == null){
        synchronized(MySingleton.class){
            if(INSTANCE == null){
                try{
                    doWork()
                }catch(Exception e){
                    throw new IllegalStateException("xyz", e);
                }
                INSTANCE = new MySingleton();
            }
        }
    }

    return INSTANCE;
}

private static void doWork() {
    // do some work
    }

}

Und im Frühjahr config xml, wird die Bean wie folgt definiert:

<bean id="MySingletonBean"
    class="com.MySingleton"
    factory-method="getInstance" lazy-init="false" singleton="true">
</bean>

Hinweis: Das meiste ähnelt der in diesem Artikel beschriebenen Strategie: http://springtips.blogspot.com/2007/06/configuration-hell-remedy-with.html


Bearbeiten 1:

Die Klassen, die diesen Singleton benutzen, sind keine Frühlingsbohnen selbst. Es sind nur Frühlingspojos, die ich nicht in den Frühling umwandeln kann. Sie müssen sich darauf verlassen, dass die getInstance () -Methode den Singleton erreicht.


Bearbeiten 2: (Kopieren eines Kommentars, den ich unten in diesen Beschreibungsabschnitt gemacht habe)  Ich versuche zwei Ziele zu erreichen:

  1. Ich möchte, dass Spring das Singleton initialisiert. So dass wenn die Die Initialisierung schlägt fehl, und das Laden der Anwendung schlägt fehl.
  2. Ich möchte, dass die anderen Klassen Klassen verwenden können, ohne sich auf contextAwareObj.getBean ("MySingleton") verlassen zu müssen.


EDIT 3 (ENDGÜLTIG):  Ich habe beschlossen, diese Klasse zu einem Singleton zu machen ... und mache es nicht zu einer Frühlingsbohne. Wenn es nicht initialisiert wird, wird etwas in der Log-Datei protokolliert. Hoffentlich bemerkt die Person, die das Deployment erledigt .... Ich habe den Ansatz, den ich vorher erwähnt habe, aufgegeben, weil ich denke, dass es in Zukunft einen Wartungs-Albtraum schaffen wird Wählen Sie zwischen - Singleton - oder - Frühlingsbohne. Ich entschied mich für Singleton.


19
2018-06-01 17:19


Ursprung


Antworten:


Sie Muss erkläre die INSTANCE Feld als volatile damit die doppelte Überprüfung funktioniert.

Sehen Wirksames Java, Punkt 71.


18
2018-06-01 17:23



Warum benutzt du? Singleton Muster an erster Stelle? Lassen Sie Spring einfach Bean für Sie erstellen (standardmäßig singleton Umfang) und ... benutze es. Natürlich könnte jemand die Bohne immer von Hand herstellen, aber das war in meinem Fall nie ein Problem.

Dependency Injection und Spring-Managed Bean Lifecycle werden Ihr Leben erheblich erleichtern (sehen Sie, wie viele Fallstricke Sie vermeiden können). Beachten Sie auch, dass Ausnahmen von c-tor oder @PostContruct Die Methode propagiert und verursacht auch einen Fehler beim Start des Anwendungskontexts.

AKTUALISIEREN: Ich verstehe was sie meinen. Das kam mir in den Sinn:

@Service
public class Singleton {

    private static AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>();

    public Singleton() {
        final Singleton previous = INSTANCE.getAndSet(this);
        if(previous != null)
            throw new IllegalStateException("Second singleton " + this + " created after " + previous);
    }

    public static Singleton getInstance() {
        return INSTANCE.get();
    }

}

Und lass Spring seine Arbeit machen. Sie können DI verwenden, wenn möglich und Singleton.getInstance() wo du musst.

Es gibt auch mehr hard-Core-Lösungen wie kompilieren-Zeit AspectJ weben und Springbohnen im Grunde alles zu injizieren.


11
2018-06-01 17:28



Ich bin mir nicht sicher, warum du das machen willst. Wenn Sie Spring mitteilen, dass eine Bean ein Singleton sein soll, muss die entsprechende Klasse kein Singleton sein und benötigt keine Factory. Spring erstellt einfach immer nur eine Instanz.

Der verlinkte Artikel macht für mich keinen Sinn, da KEINE Injektion stattfindet, kann ich sehen: "AnyService" ruft die Singleton-Factory-Methode an; Dass das Singleton im App-Kontext referenziert wird, ist irrelevant, bis es referenziert wird, und es scheint, dass keine andere Bean es referenziert.


6
2018-06-01 17:32



Wahre Singleton sind schwer zu arbeiten.

Volatile doppelt geprüft Sperre funktioniert auch nicht Eigenschaft. Lies darüber im Wiki http://en.wikipedia.org/wiki/Double-checked_locking

Ihre beste Wette ist, dies einfach zu tun

public class MySingleton {

    private static MySingleton INSTANCE = new MySingleton();

Das heißt, wenn Sie in Ihrem echten Code keine Konstruktorparameter haben.


4
2017-08-11 15:14



Meiner Meinung nach ist dies eine Gürtel-und-Hosenträger-Lösung.

Wenn Sie eine Bean erstellen und sie in der Konfiguration als Singleton deklarieren, muss die Bean nicht vor dem Multiplizieren geschützt werden.

Sie schützen sich im Grunde vor einer Person, die die Bean fälschlicherweise konfiguriert.

Ich persönlich würde das durch Dokumentation in der Frühjahrskonfiguration und Javadoc "lösen".


3
2018-06-01 17:29



Um Code beim Start auszuführen (und bei Fehler fehlzuschlagen), verwenden Sie eine der vielen Möglichkeiten, Startup-Ereignisse zu registrieren, z. sehen http://www.baeldung.com/running-setup-logic-on-startup-in-spring

Beispiel:

@Component
public class InitializingBeanExampleBean implements InitializingBean {

    private static final Logger LOG = Logger.getLogger(InitializingBeanExampleBean.class);

    @Autowired
    private Environment environment;

    @Override
    public void afterPropertiesSet() throws Exception {
        LOG.info(Arrays.asList(environment.getDefaultProfiles()));
    }
}

1
2017-12-05 01:26