# Spring ApplicationContext



## MQue (3. Aug 2009)

Hallo,

ich verwende in meiner Web- Application Spring und benötige den ApplicationContext in mehreren Klassen, um über die XML- Datei auf andere Objekte zuzugreifen.

Meine Frage wäre jetzt, ist es OK, mehrere Instanzen von ClassPathXmlApplicationContext zu haben (in diesem Fall 2 (unten))? Ich bekomme  nämlich eine Exception (unten) und vermute mal, das diese 2 Instanzen zuviel sind, sprich das man nur eine Instanz von ClassPathXmlApplicationContext habe darf??
lg

in Klasse 1 und Klasse 2 steht genau dieser Code, also ich erzeuge 2 Instanzen von 
ClassPathXmlApplicationContext

```
final ApplicationContext ctx = new ClassPathXmlApplicationContext(PATH);     
startDatabase = (StartDatabase)ctx.getBean("startdatabase");
```


```
INFO: Illegal access: this web application instance has been stopped already.  Could not load org.springframework.expression.spel.antlr.SpringExpressionsParserExtender.  
The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact.
java.lang.IllegalStateException

        at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1273)
Exception in thread "Thread-1" java.lang.NoClassDefFoundError: org/springframework/expression/spel/antlr/SpringExpressionsParserExtender
        at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1233)
        at org.springframework.expression.spel.antlr.SpelAntlrExpressionParser.<init>(SpelAntlrExpressionParser.java:51)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
```


----------



## maki (3. Aug 2009)

Mit deinem Design stimmt imho etwas grundlegendes nicht.

getBean() sollte man eigentlich nie aufrufen, höchstens in Unittests.
Dass du damit dann auch noch mehrere ApplicationContexts erzeugst ist ein weiterer Fehler.


----------



## MQue (3. Aug 2009)

maki hat gesagt.:


> Mit deinem Design stimmt imho etwas grundlegendes nicht.
> 
> getBean() sollte man eigentlich nie aufrufen, höchstens in Unittests.
> Dass du damit dann auch noch mehrere ApplicationContexts erzeugst ist ein weiterer Fehler.



Versteh ich jetzt nicht (das mit getBean). In diesem Tut. wurde es aber so gemacht??

http://www.java-forum.org/blogs/tfa/27-how-engl-thread-opener-themeneroeffner-dependency-injection-mit-spring.html

Wie kann ich es dann am Besten machen


----------



## byte (3. Aug 2009)

Du hast das Prinzip von DI noch nicht verstanden. Wenn Du in einer Klasse ein Objekt aus dem ApplicationContext brauchst, dann brauchst Du dafür nicht auf den ApplicationContext zugreifen. Du verdrahtest einfach das Objekt als Member und Spring macht dann den Rest.

Am einfachsten geht das mit Annotations:


```
public class Foo {
  @Autowired
  private Bar bar;

  ...
}
```


----------



## byte (3. Aug 2009)

Michael1234 hat gesagt.:


> Versteh ich jetzt nicht (das mit getBean). In diesem Tut. wurde es aber so gemacht??
> 
> http://www.java-forum.org/blogs/tfa/27-how-engl-thread-opener-themeneroeffner-dependency-injection-mit-spring.html
> 
> Wie kann ich es dann am Besten machen



Das ist ein simpler Test mit einer Main-Methode. In der Main Methode wird der ApplicationContext geladen.

Du hast aber keine Main Methode sondern eine Webanwendung. In Webanwendungen wird kein ClasspathApplicationContext benutzt sondern ein WebApplicationContext. Dieser wird vom Container geladen, wenn die Webanwendung deployed bzw. gestartet wird.

Wenn Du wirklich Zugriff auf den ApplicationContext brauchst (was in den meisten Fällen aber NICHT nötig ist), dann kannst Du einfach das Interface ApplicationContextAware implementieren und der AppContext wird dann von Spring injiziert.


----------



## maki (3. Aug 2009)

Michael1234 hat gesagt.:


> Versteh ich jetzt nicht (das mit getBean). In diesem Tut. wurde es aber so gemacht??
> 
> ....
> 
> Wie kann ich es dann am Besten machen


tfa hat in seinem Blog ein Bespiel erstellt, das auch eine main beinhaltet, zu Demostrationszwecken. Ein einziges mal kann man den Kontext so schon erstellen, und da dann getBean aufrufen, ist aber eher etwas für Demonstrationszwecke und soll die Grundlagen von Spring und DI erklären.

Die orig. Spring Dopku enthält dann noch viel mehr Bespiele, solltest du unbedingt auch mal lesen


----------



## MQue (3. Aug 2009)

Gibts irgendwo eine "main"- Applikation in der nur @Autowired verwendet wird?
Ich hab jetzt meine Applikation (NICHT meine Webapplikation) nur auf @Autowired umgeändert und bekomme glatt eine NPE:

Meine Klasse:


```
public final class StartService {

    @Autowired
    @Qualifier("startdatabase")
    private StartDatabase startdatabase;
    private static final String PATH;

    static {
        PATH = "file:///C:/conf/applicationContext.xml";
        }

    public StartService() {
        final ApplicationContext ctx = new ClassPathXmlApplicationContext(PATH);
        }

    private void start() {
         /* start database (hibernate) */
        System.out.println("Das ist startdatabase: " + startdatabase);
        startdatabase.insertVariables();
        /* start tcpconnection */
        //final StartTcp startTcp = (StartTcp)ctx.getBean("starttcp");
        //startTcp.startTCPConnection();
        }

    public static void main(String[] args) {
        final StartService startService = new StartService();
        startService.start();
        }
}
```


```
<beans .... >
	<context:annotation-config />                                               <!-- Beans über Annotationen konfigurieren -->
		<bean id="startdatabase"       class="net.hibernate.StartDatabase"       scope="singleton"/>
		<bean id="starttcp"            class="net.tcpinterface.StartTcp"         scope="singleton" >
	        <constructor-arg>
	            <ref local="startdatabase"/>
	        </constructor-arg>
	    </bean>
		<bean id="xmlElementProvider"  class="net.xmlreader.XMLElementProvider"  scope="singleton"/>
	    <bean id="reader"              class="net.xmlreader.ReadController"      scope="singleton"/>	    	    
</beans>
```


----------



## MQue (4. Aug 2009)

Moin,

ich muss nochmal fragen, warum das unten mit 

@Autowired
@Qualifier("writer")
private IWriteController wc;

nicht geht (das ist das Beispiel vom Blog)


```
import config.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public final class Main {

    @Autowired
    @Qualifier("writer")
    private IWriteController wc;
    private static final String PATH;

    static {
        PATH = "file:///" + System.getProperty("user.dir") + "/conf/applicationContext.xml";
        }

    public Main() {
        final ApplicationContext ctx = new ClassPathXmlApplicationContext(PATH);        // Spring initialisieren und Kontext laden, applicationContext.xml ist die oben angegebene Konfigurationsdatei.
        //final IWriteController wc = (IWriteController)ctx.getBean("writer");              // Über das Context-Objekt können die konfigurierten Beans über ihre Namen abgerufen werden.
        final IReadController rc = (IReadController)ctx.getBean("reader");
        wc.doConfig();
        rc.printConfig();        
        }

    public void setWriter(final WriteController wc) {
        this.wc = wc;
        }

    public static void main(String... args) {
        new Main();
        }
}
```


----------



## byte (4. Aug 2009)

Der Code macht überhaupt keinen Sinn. Lies erstmal die Doku.


----------



## MQue (4. Aug 2009)

byte hat gesagt.:


> Der Code macht überhaupt keinen Sinn. Lies erstmal die Doku.



Bin dabei, "Spring in Action" zu lesen, und bin da auf Seite 86 (von 700 :-( ), mir ist Grundsätzlich auch klar, wies funktioniert und was man alles in der XML- Datei einstellen kann (autowire, abstract, set, list, value, ref usw.), mit ist jetzt aber nicht klar, warum das nicht funktioniert bzw. warum das keinen Sinn macht.

Was ich bis jetzt verstehe ist folgendes: 
Ich lade mit ApplicationContext ctx = new ClassPathXmlApplicationContext(PATH); den Kontext, ab da müsste das SpringFramework aktiv?/ bereit sein um dann z.B.: @Autowired auszuführen (so mal meine einfache Vorstellung).

Bin ich da am Holzweg, wie könnte man das von oben realisieren, sodass ich nur einmal ApplicationContext bzw. WebApplicationContext brauche?


----------



## Noctarius (4. Aug 2009)

Warum nutzt du nicht das hier um an den Context zu gelagen?
ApplicationContextAware (Spring Framework API 2.0)


----------



## MQue (4. Aug 2009)

Noctarius hat gesagt.:


> Warum nutzt du nicht das hier um an den Context zu gelagen?
> ApplicationContextAware (Spring Framework API 2.0)



Keine Ahnung wie ich das einsetzen soll???


----------



## Noctarius (4. Aug 2009)

Implementieren und von Spring automatisch den ApplicationContext injecten lassen


----------



## byte (4. Aug 2009)

Michael1234 hat gesagt.:


> Bin dabei, "Spring in Action" zu lesen, und bin da auf Seite 86 (von 700 :-( ), mir ist Grundsätzlich auch klar, wies funktioniert und was man alles in der XML- Datei einstellen kann (autowire, abstract, set, list, value, ref usw.), mit ist jetzt aber nicht klar, warum das nicht funktioniert bzw. warum das keinen Sinn macht.



Wenn Du ein Objekt per new Operator erzeugst, dann funktioniert @Autowire natürlich nicht. :autsch:

@Autowire funktioniert natürlich nur für Spring Beans, also Objekte, die Spring selbst erzeugt und die man über den ApplicationContext abruft. Wichtig ist, dass Du den ApplicationContext nur ein einziges Mal erzeugst und nicht mehrfach. In WebAnwendungen erzeugt man ihn gar nicht, das passiert über den Container.


----------



## MQue (4. Aug 2009)

zwei Fragen hätte ich noch:



byte hat gesagt.:


> Wenn Du ein Objekt per new Operator erzeugst, dann funktioniert @Autowire natürlich nicht. :autsch:



ich vermute mal, Du sprichtst da obiges Beispiel von mir an, meinst Du da das new Main()? und wie kann ich das machen, das es so (ähnlich) funktioniert?



byte hat gesagt.:


> Wichtig ist, dass Du den ApplicationContext nur ein einziges Mal erzeugst und nicht mehrfach. In WebAnwendungen erzeugt man ihn gar nicht, das passiert über den Container.



Muss ich dem Container (bei mir tomcat) was konfigurieren (in der web.xml) oder reicht es wenn ich die jar's im WEB-INF/lib habe und ins Projekt hinzugefügt habe (ich vermute mal ich muss was in den dd hineinschrieben)?

Vielen Dank!


----------



## byte (4. Aug 2009)

Du musst etwas in die web.xml schreiben, damit der WebApplicationContext beim Starten der WebAnwendung hochgefahren wird.

Wie das genau geht, kannst Du alles in der sehr guten Spring Doku lesen. Ist mir jetzt zuviel Arbeit, das hier alles im Detail zu erläutern.

PS: _Learning by asking_ ist nicht umbedingt die beste Art voranzukommen...


----------



## MQue (4. Aug 2009)

byte hat gesagt.:


> PS: _Learning by asking_ ist nicht umbedingt die beste Art voranzukommen...




Aber fragen kostet nichts , Werd mir die Doku durchkauen, Danke für die Hilfe,
lg


----------



## byte (4. Aug 2009)

Kannst ja gerne konkrete Fragen stellen, aber bei manchen Deiner Fragen sieht man einfach, dass Du die Basics noch nicht beherrscht. Und ein bißchen Eigeninitiative ist schon gefordert.


----------



## MQue (4. Aug 2009)

byte hat gesagt.:


> Kannst ja gerne konkrete Fragen stellen, aber bei manchen Deiner Fragen sieht man einfach, dass Du die Basics noch nicht beherrscht. Und ein bißchen Eigeninitiative ist schon gefordert.



Da magst Du recht haben, es ist am Anfang halt schwierig, wenn man bei einem so großen Framework von null anfangen muss. Leider kann ich in der Firma auch keinen fragen, es hat keiner einen Ahnung.
Ich hoffe meine Lernkurve steigt schnelle (hab nächste Woche Urlaub)

Könntest Du mir noch einen Tipp geben, wo ich das finde, was ich in den dd schreiben muss? ist es das -> PartIII.The Web


----------



## Noctarius (4. Aug 2009)

Prinzipiell hat Spring eine sehr steile Lernkurve. Hast du die Grundbasics verstanden, kommt der Rest beim lesen der Soku oder API fast von alleine.


----------



## byte (4. Aug 2009)

Michael1234 hat gesagt.:


> Könntest Du mir noch einen Tipp geben, wo ich das finde, was ich in den dd schreiben muss? ist es das -> PartIII.The Web



Spring 3.0 gibts erst als Milestone. Das würde ich nicht umbedingt produktiv einsetzen. Die aktuelle GA ist 2.5.

Bzgl. WebApplicationContext: Chapter3.The IoC container


----------

