CDI-Injektion vs. Instanzerzeugung mittels new

oraclin25

Erfahrenes Mitglied
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:rolleyes:

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

:)
 
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.
 
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:
Code:
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:)
 
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.
 
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:
Code:
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
 
Hallo saftmeister,

gerne:

Code:
package com.coolstory;

import javax.ejb.Remote;

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

die implementierende Klasse:

Code:
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.
 
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
 
Zuletzt bearbeitet:
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:

Code:
(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?
 
Code:
(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:

Java:
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 ;-)
 
Zurück