Je suis en train de convertir un singleton en bean Spring. Ainsi, si le singleton ne parvient pas à s'initialiser, le contexte de printemps de l'application Web entière ne se charge pas correctement.
L'avantage de ne pas charger correctement le contexte Spring est que les utilisateurs en prendront note et corrigeront la configuration pendant le déploiement. Contrairement à l'utilisation de singleton 'non-spring bean': quand cela lève une exception lors de l'initialisation, personne ne le remarque .. jusqu'à ce qu'un utilisateur réel se plaint de la fonctionnalité manquante.
Mes changements fonctionnent comme prévu .. mais je ne suis pas sûr de faire la bonne chose.
Des pensées?
Le code ressemble à ceci:
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
}
}
Et au printemps config xml, le haricot sera défini comme suit:
<bean id="MySingletonBean"
class="com.MySingleton"
factory-method="getInstance" lazy-init="false" singleton="true">
</bean>
Remarque: La plupart de ces opérations sont similaires à la stratégie décrite dans cet article: http://springtips.blogspot.com/2007/06/configuration-hell-remedy-with.html
Les classes qui utilisent ce singleton ne sont pas des haricots de printemps, mais des pojos non printaniers, que je ne peux pas convertir en printemps. Ils doivent compter sur la méthode getInstance () pour obtenir le Singleton.
Edit 2: (en copiant un commentaire que j'ai fait ci-dessous dans cette section de description) J'essaie de cibler deux choses:
Vous devez déclarer le champ INSTANCE
comme volatile
pour que le verrouillage coché double fonctionne correctement.
Voir Effective Java , Point 71 .
Pourquoi utilisez-vous le motif singleton en premier lieu? Laissez simplement Spring créer un haricot pour vous (avec la portée par défaut singleton
) et ... utilisez-le. Bien sûr, toujours quelqu'un peut créer le haricot à la main, mais cela n'a jamais été un problème dans mon cas.
L'injection de dépendance et le cycle de vie des haricots gérés par Spring faciliteront considérablement votre vie (voyez juste combien de pièges vous pouvez éviter). Notez également que les exceptions émises par la méthode c-tor ou @PostContruct
se propagent et entraînent également l'échec du démarrage du contexte de l'application.
UPDATE: Je comprends ce que vous voulez dire. C'est ce qui m'est venu à l'esprit:
@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();
}
}
Et laissez Spring faire son travail. Vous pouvez utiliser DI lorsque cela est possible et Singleton.getInstance()
où vous devez.
En outre, il existe de plus en plus de solutions de base telles que le tissage AspectJ au moment de la compilation et l'injection de beans Spring essentiellement à tout.
Je ne sais pas pourquoi tu voudrais faire ça. Lorsque vous indiquez à Spring qu’un haricot doit être un singleton, la classe correspondante n’a pas besoin d’être un singleton ni une usine. Spring crée simplement une seule instance.
L'article lié n'a aucun sens pour moi, puisqu'il n'y a PAS d'injection en cours, ce que je peux voir: "AnyService" appelle la méthode singleton factory; que le singleton soit référencé dans le contexte de l'application est sans importance jusqu'à ce qu'il soit référencé, et il semble qu'aucun autre bean ne le mentionne.
Les vrais singleton sont difficiles à obtenir.
Le verrouillage à double vérification volatile ne fonctionne pas non plus. Lisez à ce sujet sur wiki http://en.wikipedia.org/wiki/Double-checked_locking
Votre meilleur pari est simplement de le faire
public class MySingleton {
private static MySingleton INSTANCE = new MySingleton();
C'est-à-dire si vous n'avez aucun paramètre de constructeur dans votre code réel.
Selon moi, c'est une solution ceinture et bretelles.
Si vous créez un bean et le déclarez en tant que singleton dans la configuration, il ne devrait pas être nécessaire de le protéger contre la création multiple.
Vous vous protégez maintenant essentiellement contre les erreurs de configuration du haricot.
Personnellement, je "résoudre" cela par la documentation dans la configuration de printemps et Javadoc.
Pour exécuter le code au démarrage (et échouer en cas d’erreur), utilisez l’un des nombreux moyens d’enregistrer les événements de démarrage, par exemple. voir http://www.baeldung.com/running-setup-logic-on-startup-in-spring
Exemple:
@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()));
}
}