Spring singleton meerdere keren gemaakt

Ik heb een boon gedefinieerd in mijn lente-webapplicatie en ik verwacht maar één exemplaar van deze boon te hebben, hier is mijn boondefinitie:


In de constructor van AccessControl wijs ik een identifier toe aan het object, iets als dit:

public class AccessControl {
   private long id = 0;
   public AccessControl() {
        id = System.currentTimeMillis();
   }

   public long getAccessControlId() {
        return id;
   }
}

In een andere klasse probeer ik het exemplaar van AccessControl te bemachtigen, zoiets als dit:

            ApplicationContext ctx =
                     new ClassPathXmlApplicationContext("acbean.xml");

            AccessControl ac = (AccessControl) ctx.getBean("accessControl");
            LOGGER_.info("AccessControl Identifier : " + ac.getAccessControlId());

Ik verwacht dat de waarde "id" hetzelfde is omdat de waarde van "id" is ingesteld in de constructor en dat de constructor niet opnieuw en opnieuw moet worden gebeld, maar dat is precies wat er gebeurt. Sterker nog, ik heb een loginstructie toegevoegd aan de constructor en er wordt telkens een nieuw object gemaakt.

Ik heb gelezen: http: //www.digizenstudio.com/blog/2006/09/14/a-spring-singleton-is-not-a-singleton/ maar ik denk niet dat ik te maken heb met dezelfde klasse die twee keer is gedefinieerd met twee verschillende bean-identifiers en de applicatie-context is hetzelfde.

Kan iemand vertellen wat er mis is met de manier waarop ik de boon heb gedefinieerd?

Ik heb ook geëxperimenteerd met singleton = "true" en scope = "singleton" maar ze maken geen verschil.

Bedankt.

6
Wordt de constructor twee keer gebeld of telkens wanneer u getBean() aanroept?
toegevoegd de auteur Tomasz Nurkiewicz, de bron
Is dit gedeelte van de code in een main -methode dat u gewoon telkens opnieuw uitvoert? Als dat het geval is, krijgt u elke keer een andere waarde, want elke keer dat u hardloopt, maakt u een nieuwe JVM. Objecten blijven niet uit zichzelf bestaan ​​buiten een instantie van een JVM, dat is iets dat u alleen zou moeten doen (waarschijnlijk met een database).
toegevoegd de auteur nicholas.hauschild, de bron
Helaas weet ik het antwoord daarop niet. Volgens de documentatie zou het me steeds opnieuw hetzelfde object moeten geven, wat betekent dat het de constructeur helemaal niet na de eerste keer zou moeten noemen. Op basis van wat ik heb gezien, wordt de constructor telkens opgeroepen als "getBean (...)", wat precies het tegenovergestelde is van wat de documentatie zegt
toegevoegd de auteur user305210, de bron
Het is een webapplicatie en zolang de app niet opnieuw wordt opgestart, zou de nieuwe JVM-instantie niet in beeld moeten komen
toegevoegd de auteur user305210, de bron

3 antwoord

de singeltonigheid in de lente is per toepassingscontext, elke keer dat u een nieuw exemplaar van de toepassingscontext creëert (zoals de eerste regel in uw tweede codevoorbeeld) worden alle singletons geïnstantieerd.

U moet één toepassingscontext hebben en deze opnieuw gebruiken in uw toepassing

16
toegevoegd
ja, dat is wat de fout is. Ik heb je oplossing nog niet geprobeerd, maar ik ben er 100% van overtuigd dat dit het probleem veroorzaakt. Bedankt.
toegevoegd de auteur user305210, de bron

U maakt een nieuwe toepassingscontext met elke aanroep van:

ApplicationContext ctx = new ClassPathXmlApplicationContext("acbean.xml");

U krijgt dus een nieuwe veercontainer, wat betekent dat uw bonen allemaal opnieuw worden gemaakt door de nieuwe container.

Ook zei je dat je dit had in een webapplicatie. Als dit het geval is, moet u toestaan ​​dat de webtoepassing de lentecontext laadt en die context zo nodig verkrijgt en gebruikt.

Voeg toe aan web.xml:


    Core Spring context.
    contextConfigLocation
    /WEB-INF/classes/applicationContext.xml


    Spring loader.
    org.springframework.web.context.ContextLoaderListener

of iets dergelijks. Verkrijg de webcontext via een servletcontext als dat nodig is.

Een andere opmerking: één punt van de lente is het verschaffen van inversie van controle, gewoonlijk met injectie van afhankelijkheid. Je zou moeten overwegen om de lente toe te staan ​​om afhankelijkheden voor je te injecteren in plaats van de context te verkrijgen en zelf bonen te trekken.

7
toegevoegd
Bedankt hiervoor. Ik was me niet bewust van deze aanpak, maar ik was zelf op zoek naar iets vergelijkbaars.
toegevoegd de auteur user305210, de bron

In een Spring-app moet u niet expliciet een toepassingscontext van uzelf maken.

Idealiter moet de singleton in uw klasse worden geïnjecteerd, of moet u ApplicationContextAware ( docs en enkele opmerkingen ). Ik geef de voorkeur aan injectie; gemakkelijker.

2
toegevoegd