Kan hierdie Java Singleton herhaaldelik kry herbou in WebSphere 6?
Vra
Ek probeer om te hou op 'n probleem in ons stelsel en die volgende kode bekommer my. Die volgende plaasvind in ons doPost () metode in die primêre Servlet (name is verander om die skuldiges te beskerm):
...
if(Single.getInstance().firstTime()){
doPreperations();
}
normalResponse();
...
Die Singleton 'Enkel' lyk soos volg:
private static Single theInstance = new Single();
private Single() {
...load properties...
}
public static Single getInstance() {
return theInstance;
}
Met die manier waarop dit is ingestel op 'n statiese inisialiseerder gebruik in plaas van die beheer van 'n nul theInstance in die metode getInstance (), kan hierdie ontslae herbou oor en oor weer?
PS - Ons loop WebSphere 6 met die App op Java 1.4
Oplossing
Ek het gevind dat hierdie op die terrein Sun se:
meerdere single Terselfdertyd Loaded deur ander klas Loaders
Wanneer twee klas loaders te laai 'n klas, jy eintlik twee afskrifte van die klas, en elkeen kan sy eie te hê Singleton byvoorbeeld. dit is veral relevant in servlets loop in sekere Servlet enjins (IPlanet byvoorbeeld), waar elke Servlet by verstek gebruik sy eie klas loader. Twee verskillende servlets toegang tot 'n gesamentlike Singleton sal, in Trouens, kry twee verskillende voorwerpe.
Verskeie klas loaders voorkom meer algemeen as wat jy dink. Wanneer blaaiers vrag klasse van die netwerk vir gebruik deur applets, hulle gebruik 'n afsonderlike klas loader vir elke bediener adres. Net so, Jini en RMI stelsels kan 'n aparte klas gebruik loader vir die verskillende kode basisse waaruit hulle aflaai klas lêers. As jou eie stelsel gebruik persoonlike klas loaders, almal dieselfde kwessies kan ontstaan.
As gelaai deur verskillende klas loaders, twee klasse met dieselfde naam, selfs dieselfde naam pakket, word beskou as duidelike - selfs al is, in werklikheid, hulle is byte-for-byte dieselfde klas. Die ander klas loaders verteenwoordig verskillende naamruimtes wat onderskei klasse (selfs al is die klasse ' name is dieselfde), sodat die twee
MySingleton
klasse is in werklikheid duidelike. (Sien "Klas Loaders as 'n Naamruimte Meganisme "in Resources.) Sedert twee Singleton voorwerpe behoort aan twee klasse van dieselfde naam, sal dit verskyn die eerste oogopslag dat daar twee Singleton voorwerpe van dieselfde klas.
Citation .
In bykomend tot die bogenoemde probleem, as firstTime()
nie gesinchroniseer, jy kan threading kwessies het daar so goed.
Ander wenke
Nee, dit sal nie gebou kry oor en oor weer. Dit is staties, so dit slegs een keer sal gebou word, reg wanneer die klas geraak vir die eerste keer deur die Classloader.
enigste uitsondering -. As jy gebeur om verskeie Classloaders het
( GeekAndPoke ):
As ander genoem het, die statiese inisialiseerder sal slegs een keer uitgevoer word per classloader.
Een ding wat ek sou 'n blik op die firstTime()
metode - hoekom kan nie die werk in doPreparations()
binne die Singleton self
Dit klink na 'n nare stel afhanklikhede.
Daar is absoluut geen verskil tussen die gebruik van 'n statiese inisialiseerder en lui inisialisering. In werklikheid is dit baie makliker om te mors op die lui inisialisering, wat ook dwing sinchronisasie. Die JVM waarborg dat die statiese inisialiseerder altyd uitgevoer word voordat die klas is toeganklik en dit sal vir eens en slegs een keer gebeur.
Dit gesê JVM nie waarborg dat jou klas net een keer sal gelaai word nie. Maar selfs al is dit meer as een keer gelaai, sal jou web-program nog sien net die relevante Singleton, as dit nie in die web-program classloader of sy ouer sal gelaai word nie. As jy 'n paar web aansoek ontplooi, dan firstTime () sal een keer vir elke aansoek genoem.
Die mees klaarblyklike dinge om te kyk is dat firstTime () moet gesinchroniseer en dat die firstTime vlag is ingestel voor die verlaat van hierdie metode.
Nee, dit sal nie veelvuldige kopieë van 'Enkel' skep. (Classloader kwessie sal later besoek word)
Die implementering jy uiteengesit word beskryf as 'gretig inisialisering' deur in boek Briant Goetz se - ' Java Concurrency in praktyk '.
public class Single
{
private static Single theInstance = new Single();
private Single()
{
// load properties
}
public static Single getInstance()
{
return theInstance;
}
}
Die kode is nie wat jy wou. Jou kode is besig om lui-inisialisering te voer na die geval is geskep. Dit vereis dat alle die kliënt biblioteek om 'firstTime () / doPreparation ()' uit te voer voordat dit gebruik word. Jy gaan om te vertrou op die kliënt om regte ding wat die kode baie broos maak doen.
Jy kan die kode te verander as die volgende so daar sal nie enige duplikaat kode.
public class Single
{
private static Single theInstance = new Single();
private Single()
{
// load properties
}
public static Single getInstance()
{
// check for initialization of theInstance
if ( theInstance.firstTime() )
theInstance.doPreparation();
return theInstance;
}
}
Ongelukkig is dit 'n swak implementering van lui inisialisering en dit sal nie werk nie in konkurrente omgewing (soos J2EE houer).
Daar is baie artikels geskryf oor Singleton inisialisering, spesifiek op die geheue model. JSR 133 aangespreek baie swakheid in Java geheue model in Java 1.5 en 1.6.
Met Java 1.5 & 1.6, jy het 'n paar keuses en hulle word genoem in die boek ' Doeltreffende Java 'deur Josua Bloch.
- Gretig Initialziation, soos die bokant [EJ Item 3]
- Lazy Initalization Holder Klas idioom [EJ Item 71]
- Enum tipe [EJ Item 3]
- dubbel gekontroleer sluiting met 'vlugtige 'n statiese veld [EJ Item 71]
Oplossing 3 en 4 sal slegs werk in Java 1.5 en hoër. So die beste oplossing sou wees # 2.
Hier is die psuedo-implementering.
public class Single
{
private static class SingleHolder
{
public static Single theInstance = new Single();
}
private Single()
{
// load properties
doPreparation();
}
public static Single getInstance()
{
return SingleHolder.theInstance;
}
}
Let daarop dat 'doPreparation ()' is binnekant van die konstruktor so jy waarborg aan die behoorlik geïnisialiseer byvoorbeeld kry. Ook, is jy piggying terug op lui klas laai JVM se en doen enige sinkronisasie 'getInstance ()' nie nodig het nie.
Een ding wat jy opgemerk dat statiese veld theInstance is nie 'n finale ". Die voorbeeld op Java Concurrency nie" finale "het maar EJ doen. Miskien James se kan meer kleur aan sy antwoord op 'classloader en vereiste van "finale" om korrektheid te verseker,
Noudat dit gesê is, is daar 'n newe-effek wat met behulp van 'n statiese finale ". Java samesteller is baie aggressief wanneer dit sien 'n statiese finale en probeer om dit so veel as moontlik inline. Dit is genoem op n blog boodskap deur Jeremy Manson .
Hier is 'n eenvoudige voorbeeld.
lêer: A.java
public class A
{
final static String word = "Hello World";
}
lêer: B.java
public class B
{
public static void main(String[] args) {
System.out.println(A.word);
}
}
As jy beide A.java en B.java stel, A.java verander jy na volgende.
lêer: A.java
public class A
{
final static String word = "Goodbye World";
}
Jy heropstel 'A.java en tik B.class. Die uitset wat jy sou kry is
Hello World
As vir die classloader kwessie, die antwoord is ja, jy kan meer as een geval van Singleton in verskeie classloaders het. Jy kan meer inligting oor wikipedia vind. Daar is ook 'n spesifieke artikel oor Websphere .
Die enigste ding wat ek wil hê dat Singleton implementering (behalwe nie met behulp van 'n Singleton enigsins) verander oor is om die geval veld finale maak. Die statiese veld sal weer geïnisialiseer word, op klas vrag. Sedert klasse lui gelaai, jy effektief kry lui Instantiëring gratis.
Natuurlik, as dit gelaai uit afsonderlike klas loaders kry jy verskeie "single", maar dit is 'n beperking van elke Singleton idioom in Java.
wysig : Die firstTime () en doPreparations () stukkies hoef te kyk verdagte though. Kan hulle nie wankel in die konstruktor van die Singleton byvoorbeeld?
Nee - die statiese inisialisering van die instance
sal altyd net een keer gedoen. Twee dinge om te oorweeg:
- Dit is nie draad-veilige (die geval is nie "gepubliseer" te hoofgeheue)
- Jou
firstTime
metode is waarskynlik meer as een keer genoem word, tensy behoorlik gesinchroniseer
In teorie is dit sal net een keer gebou. Maar hierdie patroon breek in verskillende aansoek bedieners, waar jy verskeie gevalle van 'Singleton' klasse (aangesien hulle nie ryg-veilige).
kan kryOok die Singleton patroon is critized baie. Sien byvoorbeeld Singleton Ek is lief vir jou, maar jy my afbring
Dit sal kry net een keer gelaai word wanneer die klas is gelaai met die classloader. Hierdie voorbeeld gee 'n beter Singleton implementering egter dis as lui-gelaai as moontlik en draad-veilige. Verder, dit werk in alle bekende weergawes van Java. Hierdie oplossing is die mees draagbare oor verskillende Java opstellers en virtuele masjiene.
public class Single {
private static class SingleHolder {
private static final Single INSTANCE = new Single();
}
private Single() {
...load properties...
}
public static Single getInstance() {
return SingleHolder.INSTANCE;
}
}
Die innerlike klas is nie vroeër gekla (en dus nie vroeër deur die klas loader laai) as die oomblik dat getInstance () genoem word. So, hierdie oplossing is draad-veilige sonder dat spesiale taalkonstrukte (maw vlugtige en / of gesinchroniseer).
Dit is nie verpligtend vir die enkele geval om finaal (dit is nie 'n goeie idee te alle inderdaad, want dit sal verhoed dat jy om te skakel is dit gedrag met behulp van ander patrone).
In die kode hieronder kan jy sien hoe dit slegs een keer kry aangehaal (eerste keer wat jy die konstruktor noem)
pakket datum;
invoer java.util.Date;
openbare klas USDateFactory implemente DateFactory { private statiese USDateFactory usdatefactory = null
private USDateFactory () { }
public static USDateFactory getUsdatefactory() {
if(usdatefactory==null) {
usdatefactory = new USDateFactory();
}
return usdatefactory;
}
public String getTextDate (Date date) {
return null;
}
public NumericalDate getNumericalDate (Date date) {
return null;
}
}