# CDI-Injektion vs. Instanzerzeugung mittels new



## oraclin25 (22. Dezember 2013)

Hallo zusammen,

so langsam geht es voran mit dem Erlernen der Java EE.  Ich stelle folgende Frage hier statt im Java EE-Thread, hoffentlich, das ist okay(wegen Foren-Regeln).  CDI ist (mittleweiler, oder schon immer?) verfügbar in Java SE

Also, soweite habe ich verstanden wie so eine CDI funktioniert.  Allerdings sehe ich noch nicht den "Vorteil" zwischen CDI und new-Operator.  Eine CDI stellt ja grob gesagt auch nur eine Instanz an der Stelle wo der Bean injiziert ist.  Ich könnte doch genauso gut mit new die Instanz erzeugen.  Bis auf den Unterschied, dass die Instanz bzw. das Objekt vom Applikationsserver hergestellt wird, habe ich noch kein Gefühl, was CDI so richtig positiv anders macht als ein new.

Vielen Dank für Eure Hilfestellungen.

Viele Grüße aus Rheinland,

Eure Ratna


----------



## saftmeister (22. Dezember 2013)

Hallo,

Dependency Injection macht dann Sinn, wenn du zur Compile-Zeit noch nicht festlegen willst, kannst oder darfst, welches Objekt denn nun tatsächlich verwendet werden soll. Durch DI baust du eine losgelöste Komponente, die statt mit konkreten Klassen eben mit Interfaces arbeitet. Dadurch ergeben sich Konfigurationsmöglichkeiten für deklarative statt imperative Programmierung.

Kurzum: du machst deine Applikation dadurch flexibler.

Falls aus irgendeinem Grund eine andere Klasse für deine Komponente als Implementierung herhalten soll, musst du nicht neu kompilieren, sondern kannst im Deployment festlegen, was konkret passieren soll.

Das beste Beispiel ist die Verwendung einer Datasource. Wenn du über Annotation an einer Klasse festlegst, welche Datasource verwendet werden soll, musst du nicht alles umwerfen, nur weil ein anderes RDBMS verwendet werden soll. Man tauscht beim Deployment die Datasource-Konfiguration aus, und damit hat es sich dann.


----------



## oraclin25 (22. Dezember 2013)

Hallo saftmeister,

vielen lieben Dank.  Ich habs jetzt verstanden:
man kann dann aus mehreren Beans die passende Bean auswählen(die Beans implementieren aber eine gemeinsame Schnittstelle).  Perfekt 

Vielleicht eine andere Frage:

```
try {
	Context ctx = new InitialContext(p);
			
	TheBeanRemote bean = (TheBeanRemote) ctx.lookup("MrBean#com.coolstory.TheBeanRemote");
			
               System.out.println("Main.main(): " + bean.sayHi());
			
} catch (NamingException e) {
			
e.printStackTrace();
		
}
```

die Methode lookup gibt ja ein Objekt aus dem String-Parameter zurück.  Meine eigentliche Frage ist der Schritt vorher:
warum muss ich denn hier ein Objekt vom Typ InitialContext bzw. Context erstellen?  Ich habe in der Doku bzgl. der Schnittstelle Context ein nachgeschaut:


> This interface represents a naming context, which consists of a set of name-to-object bindings. It contains methods for examining and updating these bindings.



Desweiteren steht für die implementierende Klasse InitialContext:


> This class is the starting context for performing naming operations.
> All naming operations are relative to a context. The initial context implements the Context interface and provides the starting point for resolution of names.



Mir wars trotzdem noch nicht erleuchtend, was das Thema Name to object bindings bedeutet

Könntest Du vielleicht mir vielleicht umgangssprachlich erklären? 

Vielen Dank

Viele Grüße aus Rheinland,

Eure Ratna


----------



## saftmeister (22. Dezember 2013)

Weißt du, wie Namensauflösung im Internet funktioniert? JNDI ist auch ein Namensdienst. Mit Hilfe des InitialContext kannst du den Application Server nach einem bestimmten Objekt fragen. Wie bei DNS bekommst du hier eine Antwort, allerdings in Form eines Objektes oder eine NameNotFoundException NamingException als Quittung.


----------



## oraclin25 (22. Dezember 2013)

Hallo saftmeister,

danke erstmal für die rasche Antwort.  JNDI ist also wie ein DNS-System, okay, das verstehe ich.  Wenn ich mir den Code angucke, ist mir noch etwas unklar:

TheBeanRemote ist ja eigentlich eine Schnittstelle/Interface.  Die Zeile:

```
TheBeanRemote bean = (TheBeanRemote) ctx.lookup("MrBean#com.coolstory.TheBeanRemote");
```

lookup gibt mir ja ein Objekt als Rückgabe zurück.  Aber aus einer Schnittstelle kann doch kein Objekt erstellt werden.  Man kann lediglich ein Objekt aus einer Klasse erstellen, die in diesem Fall TheBeanRemote implementiert.  Wo ist hier mein Denkfehler?

Viele Grüße aus Rheinland,

Eure Ratna


----------



## saftmeister (22. Dezember 2013)

Zeig mal den Code der Klasse, die TheBeanRemote implementiert.


----------



## oraclin25 (22. Dezember 2013)

Hallo saftmeister,

gerne:


```
package com.coolstory;

import javax.ejb.Remote;

@Remote
public interface TheBeanRemote {
	public String sayHi();
}
```

die implementierende Klasse:


```
package com.coolstory;

import javax.ejb.Stateless;

/**
 * Session Bean implementation class TheBean
 */
@Stateless(mappedName = "MrBean")
public class TheBean implements TheBeanRemote {

    /**
     * Default constructor. 
     */
    public TheBean() {
        
    }

	@Override
	public String sayHi() {
		return "Hi I am Ratnalein";
	}

}
```

Also, TheBeanRemote ist wirklich eine Schnittstelle.


----------



## saftmeister (22. Dezember 2013)

Ja, das war mir soweit klar ;-)

Aber schau an, was als Annotation über der Klasse TheBean steht. Da hast du dem Applikation Server mitgeteilt, dass es sich um eine Stateless Bean handelt, also eine status-unbehaftete solche. Beim Deployment im AS analysiert derselbe, welche Klassen er laden soll. Dabei berücksichtigt er diese Annotation. Es wird also quasi im Namensdienst diese Bean registriert und zwar über den gemappten Namen "MrBean". Der AS merkt sich also, ich habe da eine Bean, deren Namen gemappt werden soll. Diese Bean implementiert eine bestimmte Schnittstelle. Wenn jemand von mir ein Objekt haben möchte, dass diese Schnittstelle implementiert, gebe ich ihm eine Instanz dieser Klasse. Außerdem behalte ich das Objekt in meinem Container und zwar so lange, bis es keiner mehr braucht (vorher wird es noch passiviert, aber das ist evtl. noch nicht erwähnenswert).

EDIT: noch zu erwähnen wäre, dass der AS dem Client eigentlich kein Objekt sondern eine Referenz darauf zurück gibt. Diese Referenz stellt dann deine Schnittstellen-Deklaration (TheBeanRemote bean) dar.


EDIT2: Außerdem hast du ja den gemappten Namen der Bean im Lookup angegeben:

MrBean#com.coolstory.TheBeanRemote


----------



## oraclin25 (22. Dezember 2013)

Hallo saftmeister,

es ist also ein Key --> Value-Eintrag in dem AS:

MrBean --> die Klasse TheBean, die die Schnittstelle TheBeanRemote implementiert

Danach meintest Du:


> Wenn jemand von mir ein Objekt haben möchte, dass diese Schnittstelle implementiert, gebe ich ihm eine Instanz dieser Klasse.



Ich nehme an, Du meintest die Instanz der Klasse TheBean.

Aber trotzdem:


```
(TheBeanRemote) ctx.lookup("MrBean#com.coolstory.TheBeanRemote");
```

Wieso wird das Objekt der Klasse TheBean denn hier auf den Typ TheBeanRemote gecastet?  

Vielen Dank

Viele Grüße aus Rheinland,

Eure Ratna

PS.  dieses Casting von groß(implementierede Klasse) auf klein(ihre Interface), ist das eigentlich ein indirekter Weg um Objekt von einer Schnittstelle zu bekommen?


----------



## saftmeister (22. Dezember 2013)

oraclin25 hat gesagt.:


> ```
> (TheBeanRemote) ctx.lookup("MrBean#com.coolstory.TheBeanRemote");
> ```
> 
> Wieso wird das Objekt der Klasse TheBean denn hier auf den Typ TheBeanRemote gecastet?



Ok, noch mal deutlicher:

InitialContext.lookup() liefert Typ Object zurück. Aber eigentlich kommt da ja ein konkretes Objekt (Referenz), nämlich TheBean zurück. Aber wie schon geschrieben, es ist nur die Referenz auf das Objekt. Die Referenz kann man auch in einem Schnittstellen-Objekt ablegen, gar kein Problem. Das hier ist auch in Java ohne AS möglich:


```
package de.tutorials;

public interface IFace
{
    String hello(String name);
}

package de.tutorials;

public class Klass implements IFace
{
    @Override
    public String hello(String name)
    {
        return "Hello " + name;
    }
}

package de.tutorials;

public class MainKlass
{
    public static void main(String[] args)
    {
        IFace ref = new Klass();
        System.out.println(ref.hello("Ratna"));
    }
}
```

EDIT: Und da lookup() Object zurückliefert, muss gecastet werden, sonst kannst du die Schnittstellen-Methoden ja nicht verwenden ;-)


----------



## oraclin25 (22. Dezember 2013)

Hallo saftmeister,

mhh.. 


```
noch zu erwähnen wäre, dass der AS dem Client eigentlich kein Objekt sondern eine Referenz darauf zurück gibt. Diese Referenz stellt dann deine Schnittstellen-Deklaration (TheBeanRemote bean) dar.
```


```
TheBeanRemote bean = (TheBeanRemote) ctx.lookup("MrBean#com.coolstory.TheBeanRemote");
```

Also, ctx.lookup(...) gibt eine Referenz zurück?  Ich hab in die Doku reingeschaut, lookup gibt eigentlich ein Objekt zurück.  In diesem Fall das Objekt von der Klasse TheBean.

Ist das nicht so, dass es wirklich ein Casting von groß nach klein ist?  Ich hab nämlich festgestellt, dass das geht:


```
interface Foo{
 void display();
 }

public class TestFoo implements Foo{

void display(){
 System.out.println(“Hello World”);
 }

public static void main(String[] args){
 Foo foo = new TestFoo();
 foo.display();
 }

}
```


----------



## saftmeister (22. Dezember 2013)

Les bitte noch mal das Posting #10


----------



## oraclin25 (22. Dezember 2013)

Wenn also eine Referenz statt ein Objekt vom Typ Object als rückgabe rauskommt, dann haben wir ja in dem gesamten ausdruck eine referenz, die wiederum auf eine referenz zeigt?  Es kommt mir wie C vor.

TheBean hat bsplweise 0000xx001 als Wert

Der Wert bzw der Inhalt von 0000xx001 ist 0000xx018

Der Inhalt von 0000xx018 ist dann wirklich das Objekt 

Ist das was du meinst? Och jee, ich irre mich wieder****


----------



## saftmeister (22. Dezember 2013)

Lass mal C weg, da würde ich es eher mit Pointern vergleichen. Im Prinzip ist in Java alles was kein primitiver Datentyp ist, eine Referenz. Sonst wäre Java nicht so schnell wie es ist ;-)

Daher kann man auch kein String-Objekt mit einem anderen String-Objekt vergleichen, in dem man die == Operatoren verwendet, sondern muss den "Umweg" über die equals-Funktion wählen. Sonst würdest du nur eine Referenz mit einer anderen Referenz vergleichen und das kann, muss aber nicht gleich sein, selbst wenn die Zeichenketten an sich identisch sind.

Das lookup() eine Referenz auf ein Objekt zurück gibt, solltest spätestens dann einleuchten, wenn du Methoden aufrufst, die Aktionen auf der Datenbank ausführen. Stell dir mal vor, du hättest jetzt einen AS, eine Bean im AS und einen Client, der außerhalb des AS operiert. Der Client fragt jetzt über JNDI-Lookup den AS nach einem Objekt das eine komplizierte Geschäftslogik ausführt, in dem es Operationen mit Datenbank-Tupeln durchführt und ein Ergebnis an den Client zurück gibt. Die Datenbank-Operationen können ja schlecht auf dem Client ausgeführt werden, da der ja gar keine Funktionen dafür hat, noch die Datenquelle kennt. Also wird die Geschäftslogik natürlich auf dem AS und nicht auf dem Client ausgeführt. Der Client bekommt über das Interface also die Referenz auf ein Objekt (Bean), das im Container liegt und führt dort die Interface-Methode aus.

So läuft das ab.


----------



## oraclin25 (22. Dezember 2013)

Ich glaube, du meinst es so wie ich es auch meine:
Die Variable bean hast als Wert die Speicheradresse 0000xxx001.  Diese Speicheradresse hat auf der anderen Seite als Wert den Objekt vom Typ Object.

Bin grad unterwegs auf der autobahn.


----------



## oraclin25 (23. Dezember 2013)

Hallo saftmeister,

danke für die ausführliche Erklärung.  Hätte ich vorher gewusst, dass Referenz = Speicheradresse eines Objekts ist, hätten wir uns den Java-Grundkurs sparen können   Aber gut, jetzt weiss ich es zumindest.  Zudem, es ist mir jetzt klar geworden, dass "EJBeans vom AS verwaltet" nicht nur vomgleichen erzeugt werden bedeutet, sondern auch noch dass Methoden auf diesem Objekt in der AS-Maschine ausgeführt werden.  Ich nehme an, das heißt = Maschine wo AS drauf ist muss schon leistungsfähig sein.

Jetzt weiss ich auch, dass in jedem AS ein JNDI-System existiert.  LDAP ist beispielsweise so ein JNDI-System.   Desweiteren kann man Resourcen mittels Java-JNDI-API ansprechen, da diese Resourcen vom AS mit Hilfe des JNDI-Systems verwaltet bzw. gespeichert werden.  In unserem Beispiel verwendeteten wir die Methode lookup, um ein Objekt einer EJBean zu erzeugen.  Darauf bauen wir dann Methoden bzw. Geschäftslogiken.

Meine ursprüngliche Frage war ja, warum wir so ein InitialContext-Objekt brauchen, um auf EJBeans(-Objekte) zu kommen.  Ich verstehe das so:
Resourcen vom AS werden mit Hilfe des JNDI-Systems verwaltet.  Methoden auf einem JNDI-System lassen sich nur im Rahmen eines vorhandenen Initial-Kontextes ausführen(ich weiss zwar nicht warum das so ist, aber ich glaube, ich kann mit diesem Unverständnis leben), lookup ist beispielsweise so eine Methode.  Entsprechende Umgebungsinformationen werden vorbereitet und aschließend als Parameter bei der Erzeugung vom InitialContext-Objekt.  Dies ist nötig, weil wir ja das JNDI-System eines bestimmten AS ansprechen wollen.

Ich bin dankbar für korrigierende Kommentare, falls es noch Denkfehler gibt.

Viele Grüße aus Rheinland,

Eure Ratna


----------



## saftmeister (23. Dezember 2013)

LDAP ist kein JNDI. JNDI gibt es nur in Java, es heißt ja "Java Naming and Directory Interface". JNDI ist eine API. LDAP ist ein Protokoll, und nur auf logischer Ebene mit JNDI verwand. LDAP gab es schon vor JNDI. Ich wollte damit keine Verwirrung stiften, als ich DNS in Spiel gebracht hatte, dachte mir, es vereinfacht die Sache. JNDI hat mit DNS oder LDAP nichts gemein.

Eine Maschine, die einen AS beherbergt, kann, muss aber nicht leistungsstark sein. Einen AS kann man wie eine Cloud auf mehrere Rechner verteilen. Daher gibt es bei Beans auch das sog. Local- und das Remoteinterface.

Du brauchst für die Namensauflösung bzw. -Binding einen Dienst, der durch die Context-API bereit gestellt wird. InitialContext ist dabei die Referenz- (oder auch Basis-)Implementierung für das Context-Interface. Ich würde dieses Unverständnis nicht stehen lassen wollen ;-)
Context ist hier "einfach" die Bezeichnung für den Teil, der die Auflösung oder das Binding vornimmt. Vielleicht liest du noch mal die API-Doku für Context nach, statt für InitialContext.


----------



## oraclin25 (23. Dezember 2013)

Hallo saftmeister,

danke für die Klarstellung. 

Es waren so viele Informationen, ich kam ein bisschen durcheinander, aber ich glaube, ich habs jetzt: 

Du hast natürlich Recht, JNDI ist nur eine Java-API.  Diese API kann man Gebrauch machen, um viele verschiedene Protokoll-Implementierungen "anzusprechen".  LDAP ist beispielsweise so ein Protokoll; konkrete LDAP-Implementierungen sind beispielsweise OpenLDAP oder Active Directory.  

Es gibt weitere Protokolle, wie Du auch schon erwähnt hast, beispielsweise das DNS-Protokoll.  

Man kann jedenfalls mit Hilfe der Java-API all dieser Protokoll-Implementierungen "ansprechen".  

Nun wollte ich wissen, welches Protokoll verfolgt Glassfish bzw. WebLogic bzgl. Naming Directory Service.  Ich habe soeben gegoogelt, anscheinend kann man frei wählen, das alles wird vom AS unterstützt?

Zum Thema (Initial)Context im Zusammenhang mit Naming Directory Services:
Man braucht also für die Namensauflösung bzw. -Binding immer ein Kontext-Objekt, deren Klasse das Interface Context implementiert.  Egal was für ein Protokoll das Namensauflösungs bzw. -Binding-System hat.  Zum Beispiel:
Um OpenLDAP anzusprechen brauchen wir ein Kontext (Java hat sogar InitialLdapContext dafür)

Jetzt weiss ich zumindest, WIE die Sache zwischen Context, Namensservice und JNDI funktioniert.  

Ich hoffe, es hört sich gut an.  Och jee, viel gelernt in den letzten 20 Stunden, das auch noch während Feiertage.  Dir ganz vielen Dank.

Viele Grüße aus Rheinland,

Eure Ratna


----------



## saftmeister (23. Dezember 2013)

Leider kann ich weder zu Glassfish noch zu Weblogic irgendwas mitteilen, was dir weiter hilft, da ich weder den einen noch den anderen kenne oder benutzt habe. Ich "kenne" JBoss AS bzw. Wildfly. Kenne deswegen in Anführungszeichen, weil ich mich damit bei weitem nicht so gut auskenne, wie ich es gern hätte ;-)

Prima an Java und dessen API ist, dass es platform- und sogar produkt-unabhängig ist, und man ggf. trotzdem irgendwie helfen kann.

Grundsätzlich verhält sich die Sache mit dem Kontext so wie du es beschrieben hast. Und ja, man kann mit JNDI viele verschiedene Namensdienste in Anspruch nehmen. Was du allerdings vorhast, ist in der AS-Welt relativ einfach, straight und wird permanent so eingesetzt: Objekt-Zugriff auf Geschäftsbeans. Dafür braucht es nicht mehr, als den Standard InitialContext und dessen statische lookup()-Methode sowie gebundene (binded) EJBs. Das erledigt der AS für dich, sofern du deine EJBs richtig annotierst und mindestens EJB 3 einsetzt (welcher Teil eines jeden heute verfügbaren AS sein sollte).

Ich kann allerdings vollkommen nachvollziehen, dass das Thema anfangs etwas frustrierend und unübersichtlich ist, man muss erstmal hinter die Logik steigen. Es freut mich, wenn du da voran kommst, das ist schließlich das Ziel dieses Forums. Und eines Tages kannst du selbst den Fragenden hier Rede und Antwort stehen  Und natürlich kann auch ich noch ne Menge dabei lernen ;-) Freue mich schon darauf, wenn du hier Fragen zum Thema Entities, Transaction Management, Messaging und dergleichen stellen wirst. Ich bin mir fast sicher, dass diese Themen auch noch kommen werden.

Grüße aus dem Mainland.


----------

