Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
ich bin mir nicht sicher ob das eine gute Lösung ist, aber ich beschreib mal was ich vor hab.
Ich wollte eine Factory machen die mir Objekte erzeugt und die ich dann meiner spring.xml bekannt mache und dann mit @Autowired an bestimmte Stellen injezieren lasse.
Zu meinem Problem: Die Factory gibt es einmal, jetzt hab ich eine create methode z.b
Java:
public X createX(){
return XImpl();
}
X ist auch eine Spring Bean.
jetzt will ich aber hier nicht die konkrete implmentierung angeben sondern, das XImpl mit Spring jedes mal neu erzeugen lassen. Wie kann ich das machen? Ich möchte ungern über den context die bean auslesen.
Kann man sowas machen wie
Java:
@Autowired
private X x;
public X createX(){
return x;
}
und jedes mal wenn die Methode aufgerufen wird, wird ein neues X mit der in Spring angebene Implementierung erzeugt??Geht sowas?????????:L
Oder wie macht man sowas besser?
Implementiere das Interface FactoryBean und setze isSingletion() == false
Zum Nutzen des FactoryBean setzt du im AppContext.xml statt der zu instanzierenden Klasse die FactoryBean implementierende Klasse ein.
Willst du also FooImpl instanzieren (injecten) lassen setzt du FooFactory implements FactoryBean stattdessen ein.
PS: Steht aber auch alles dick und breit in der Spring Dokumentation (Chapter3.The IoC container) und wer mit Spring arbeiten will für den ist die Spring Doku Pflichtlektüre!
public class FooFactory implements FactoryBean<FooIF>{
@Autowired
private FooIF foo;
@Override
public GameObjectModel getObject() throws Exception {
// oder aber würde ich nicht wollen return new FooImpl();
return foo;
}
@Override
public Class<?> getObjectType() {
return FooIF.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
Aber so bekomme ich ja die gleiche Instanz zurück anstatt eine neue, also hat sich ja nichts verändert
Weil ich hab einen Handler der wird nur einmal instanziert. Und wie bekomme ich nun aus der Factory immer wieder eine neue Instanz?
Java:
public class FoorHandler extends AbstractHandler{
@Autowired
private FooFactory factory;
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
try {
System.out.println(factory.getObject());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
Das weiß ich !!!!!!!!!!!!!!!!!!
Genau das ist ja mein Problem , wie man das machen kann darum hab ich ja die Kommentare dazu gemacht, dass ich es so machen könnte.
Und ich wollte wissen ob es eine Möglichkeit mit Spring gibt immer eine neue Instanz zu bekommen ohne dass man die Impl zurückgibt oder auf context.getBean zurückgreifen muss
Ich versteh nicht was du willst oder es ist so sinnfrei, dass ich es nicht verstehen will. Entweder du willst immer eine neue Instanz dann machst du in getObject eben new Foo() oder du keine Ahnung was du willst.
Ja ich will immer eine neue Instanz, vielleicht hab ich auch das Prinzip der FactoryBean nicht ganz verstanden.
Beispiel: Interface Foo. 2 Implmentierungen: Foo1Impl, Foo2Impl
Jetzt wollte ich eigentlich über die Factory immer neue Instanzen zurückbekommen, je nachdem was ich im Spring context.xml eingepflegt habe.
Entweder gibst du der Factory Bean über eine eigene Property die zu instanzierende Klasse mit oder du machst halt ne zweite Factory Bean. Klar ist mir die Frage immer noch nicht oder du hast das Prinzip nicht verstanden Oo
Also ich versuchs nochmal zu erklären ...
Ich hab einen Handler der einmal instanziert wird, der soll eine Factory injecten, soweit gut.
Die Factory soll neue Objekte zurück geben, aber in dieser Factory will ich nicht(falls das geht) die dirkete implmentierung angeben. Wie würdest du denn es machen, vielleicht check ich es dann Oo...
Also Interface Foo, Implementierung Foo1Impl, Foo2Impl... Wie würde dann die Factory aussehen?
Ohne Experte in Spring zu sein, gibts hier meiner Meinung nach zwei Möglichkeiten.
1) Du greifst in der FooFactory direkt auf den Spring Applikation Context zu und lädst eine Bean, die einen Prototpye Scope besitzt.
2) Du baust eine weitere Abstraktion ein.
Java:
public interface FooIFFactory {
FooIF getNewInstance();
Class<? extends FooIF> getInstanceClass();
Java:
public class FooFactory implements FactoryBean<FooIF>{
@Autowired
private FooIFFactory foo;
@Override
public GameObjectModel getObject() throws Exception {
// oder aber würde ich nicht wollen return new FooImpl();
return foo.getNewInstance();
}
@Override
public Class<?> getObjectType() {
return foo.getInstanceClass();
}
@Override
public boolean isSingleton() {
return false;
}
}
Dann kannst du für jede FooIF Implementierung eine eigenen FooIFFactory Implementierung schreiben.
Also zu Punkt 1 wie gesagt wollte nicht auf den Context zugreifen...
Punkt 2 werd ich mal versuchen ...
Was sagt der Spring Experte dazu? Ist sowas okay oder gibt es einen anderen (besseren) Weg?
Hm. Das mit dem Spring App Context hatte ich überlesen, also hab ich mir das gerade nochmal in Ruhe alles durchgelesen.
Das mit der FactoryBean Implementierung war ja schon nicht mehr Urpsrungscode. Also würde ich es ein bisschen anders machen. Dazu habe ich noch eine zweite Idee. Es hängt jedoch auch damit zusammen, ob deine Implementierungen von FooIF Dependencies injeziert bekommen sollen. Ist dies der Fall musst du meiner Meinung nach über den App Context gehen.
Nun die beiden Ideen:
1) Wie du oben schonmal oben irgendwie stehen hast, würde ich für das Problem eben für jede Implementierung von FooIF eine Factory schreiben.
Java:
public interface FooIFFactory {
FooIF getNewInstance();
}
Überall wo du dann eine Instanz von FooIF erzeugen möchtest, kannst du dir die FooIFFactory injezieren lassen.
2) Wenn du nicht für jede Implementierung von FooIF eine Factory schreiben möchtest, könntest du noch eine generische Factory schreiben, die durch ein String Property gesteuert wird. Hier gäbe es dann die Möglichkeit, diese Factory für jede Implementierung zu erweitern oder aber per Reflection deine Instanz zusammen zu bauen.
Java:
public class FooIFFactry {
@Autowired
@Qualifier("fooClassName")
private String fooClassName;
...
public FooIF getNewInstance() {
Class<?> clz = Class.getClassForName(fooClassName);
return clz.newInstance();
}
Die Methoden sind jetzt ausm Kopf, müssen also nicht stimmen.
P.S.: Da fällt mir noch was drittes ein:
3) 2., aber über eine tatsächliche Instanz.
Java:
public class FooIFFactry {
@Autowired
private FooIF fooImpl;
...
public FooIF getNewInstance() {
return fooImpl.getClass().newInstance()
}
Ich versteh den Sinn immer noch nicht. Mach doch einfach eine Factory welcher du mit newInstance(Class<? extends WhatEver> clazz) die zu instanzierende Klasse übergibst. Ich seh keinen Sinn darin das alles 3 und 4x zu abstrahieren.
Ich versteh den Sinn immer noch nicht. Mach doch einfach eine Factory welcher du mit newInstance(Class<? extends WhatEver> clazz) die zu instanzierende Klasse übergibst. Ich seh keinen Sinn darin das alles 3 und 4x zu abstrahieren.
Ja hab ich mir auch überlegt... Ist ja dann so ähnlich wie die 1. Idee von oben nur eine normale Factory
Und wie würdest du die Factory dann aurufen?So ungefähr?
Java:
public class Handler...{
@Autowired
FooIF foo;
@Autowired
Factory factory;
void doSth(){
foo = factory.newInstance(foo.getClass());
//....
}
}
Ja der Unterschied ist das ich oben eine Factory für alle Klassen hab...
Und bei deiner Variante immer wieder wenn ein neues Objekt hinzukommt die Factory erweitern muss...
Weiß auch nicht was die bessere und saubere Variante ist ^^....
Soll deine Factory bei jedem Aufruf von newInstance() dieselbe FooIF Implementierung zurückgeben, oder auch hier variabel sein?
Wenn jedesmal dieselbe Implementierung zurückgegeben werden soll, dann bist du auch mit meiner Variante raus. Dann musst du nur die FooIF Implementierung in die Factory injizieren. Im Endeffekt ist der Ansatz identisch, mit deiner Variante könntest du die Factory noch variabler nutzen.
Soll deine Factory bei jedem Aufruf von newInstance() dieselbe FooIF Implementierung zurückgeben, oder auch hier variabel sein?
Wenn jedesmal dieselbe Implementierung zurückgegeben werden soll, dann bist du auch mit meiner Variante raus. Dann musst du nur die FooIF Implementierung in die Factory injizieren. Im Endeffekt ist der Ansatz identisch, mit deiner Variante könntest du die Factory noch variabler nutzen.
Ich halte es trotzdem für den falschen Weg, allein schon weil das Injizieren der Factory an dieser Stelle keinen Sinn mehr macht, da kannst du die Methode newInstance als static auch in einer Utility-Class hinterlegen, die Factory per String zu instanzieren macht da quasi keinen Sinn mehr.
Ich halte es trotzdem für den falschen Weg, allein schon weil das Injizieren der Factory an dieser Stelle keinen Sinn mehr macht, da kannst du die Methode newInstance als static auch in einer Utility-Class hinterlegen, die Factory per String zu instanzieren macht da quasi keinen Sinn mehr.
Stimmt kann ich auch, jetzt wo dus sagst macht es echt keinen Sinn mehr -.-... Aber ich muss trz einmal ein Objekt injecten damit ich an die Impl komme.
Echt ich versteh dein Problem nicht, welche Methode willst du aufrufen? Junge drückt dich konkret aus, mach von mir aus mehr Codebeispiel als 5 Zeilen.
Mit dem InstanceHelper gibt es keine Methode, die du nicht aufrufen kannst, da diese bereits static ist und so ohne Instanz von InstanceHelper aufgerufen werden kann. Und für FooIF gibt es keine Methode die du nicht aufrufen kannst da du mit dem InstanceHelper eine Instanz dieser erschaffen hast (welche Implementierung des Interfaces auch immer).
Also konkrete Frage oder lass es, langsam komm ich mir blöd vor 100x das selbe zu sagen und das Gefühl zu bekommen du hörst nicht zu oder dir würden die absoluten Grundlagen fehlen (und das letzte glaube ich eigentlich nicht).
Was er will:
Er will per Spring sagen, welche Implementierung von FooIF verwendet werden soll. Zusätzlich möchte er jedoch mehrere unterschiedliche Instanzen dieser Implementierung verwenden.
Was mir noch nicht ganz klar ist:
Wieso genau, brauchst du mehrere verschiedenen Instanzen, und wieso hilft dir da der Protoype Scope von Spring nicht weiter?
Dann macht man mehrere verschiedene Factories, definiert diese als Springbean mit unterschiedlichen IDs und injiziert immer die gewünschte Bean. Alternativ nimmst man die Helper-Class und injiziert in die Klasse, welche die Instanz bekommen soll (entweder per Spring oder was weiß ich woher) den Classname der Implementierung.
public class Foo implements InitializingBean {
private String implementation;
public void setImplementation(String implementation) { ... }
public String getImplementation() { ... }
public void afterPropertiesSet() throws Exception {
Some some = InstanceHelper.newInstance(implementation);
}
}
PS: Ich versteh trotzdem nicht den Sinn dahinter. Versuch mal klar zustellen was du machen willst. Ich bin sicher du versuchst das einfach total falsch.
Okay ich versuch nochmal zu beschreiben was ich machen will... Ausführlicher!!!
Ich haben Handler der wird nur einmal instanziert und in dieser Handler öffnet einen Eclipse Editor und der brauch immer eine neue Instanz von einer Klasse für die es auch eine Interface gibt...
Also war ich soweit...
Java:
public interface FooIF{
void doSth();
}
Java:
public class FooImpl{
public void doSth(){
....
}
}
Java:
public class Handler{
public void excecute(){
//hier liegt mein Verständniss Problem
FooIF foo = FooFactory.createFoo(FooImpl.class);
.....
}
}
Jop also soweit so gut...
Jetzt muss ich aber jedes mal wenn sich die Impl ändert den Code ändern und NICHT nur die XML Datei!!! Und nun habe ich mich gefragt WOHER ich die Klasse bekomme, damit dass alles im Programmcode(siehe Kommentare) dynamisch bleibt und ich nicht die konkrete Implementierung angeben muss. Und ich nur in der XML meine richtige Klasse konfigurieren muss. Mhm besser?
Und meine Idee war halt mit @Autowired einmal die richtige Implmentierung injecten zu lassen, damit ich diese habe...
Wollt einfach nochmal genau beschreiben was ich vor hab...
Bin grad noch dabei es zu verstehen... Check net ganz was für dich das Some ist, aber so werd ich es mal versuchen...
Ja implementation und klassenname sind ja identisch...
Mach mal einen richtigen Beispielcode was du willst. Mal sagst du, du willst eine Factory, mal meinst du, du willst eine Instanz der Klasse die du schon hast. Mach ein vollständig (theoretisch) kompilierbares Stück Code, ohne das ganze Gepunkte in Methoden.
Nach wie vor ist mir absolut unklar was du willst.
Versuch den Gedanken mal umzudrehen. Hast du eine Möglichkeit in Sourcecode zu erfahren welche Klasse du brauchst? Bestimmtes Value in einem Datenwert oder sowas? Dann könnte man das in der Factory hart verdrahten.
Normalerweise sollte ein simples Scope=Prototype reichen, alternativ halt massig verschiedene Factory Implementierungen oder die gewünschten Implementierungen direkt in die Klasse injizieren wo sie später gebraucht wird (mein zweites Beispiel) oder in verschiedene Instanzen der Factory injizieren (denke hierbei immer daran, dass du den Qualifier beim Autowired mit angeben musst um die Instanzen zu unterscheiden) oder oder oder.
Trotzdem bin ich fest der Überzeugung du versuchst da Schmu zu machen.
Vielleicht nochmal eine kurze Erklärung was genau das Ziel ist:
Ich will die Klasse NICHT zur Laufzeit festlegen. Das Ziel ist, dass ich in meiner xml Datei einstellen kann welche Implementierung der Klasse ich will. Es GIBT NUR EINE gleichzeitig entweder oder.
Zum Beispiel für den einen Kunden zählt Foo1Impl für den anderen Kunden Foo2Impl... Dann will ich ja nichts mehr im Code ändern, sondern nur in der xml die richtige Impl konfigurieren. Also das ist das Ziel =)!!!
public class FooFactory implements FactoryBean, InitializingBean {
private Class<? extends FooIF> clazz;
private String implementation;
@Override
public Object getObject() throws Exception {
return clazz.newInstance();
}
@Override
public Class getObjectType() {
return clazz;
}
@Override
public boolean isSingleton() {
return false;
}
@Override
@SuppressWarnings("unchecked")
public void afterPropertiesSet() throws Exception {
clazz = (Class<? extends FooIF>) Class.forName(implementation);
}
public void setImplementation(String implementation) {
this.implementation = implementation;
}
public String getImplementation() {
return implementation;
}
}
PS: Du solltest dir dafür überlegen, ob du die Konfiguration der Klasse nicht per PropertyPlaceholder in eine Properties-Datei verschieben willst.
PPS: Jetzt hast du mich schon so genervt mit deiner Factory, dass ich total verplant habe: Du brauchst doch gar keine Factory wenn du eh nur eine bestimmte Implementierung instanzieren willst. Diese kannst du doch direkt als Bean instanzieren mit Scope Prototype.
[xml]
PS: Du solltest dir dafür überlegen, ob du die Konfiguration der Klasse nicht per PropertyPlaceholder in eine Properties-Datei verschieben willst.
[xml]
PPS: Jetzt hast du mich schon so genervt mit deiner Factory, dass ich total verplant habe: Du brauchst doch gar keine Factory wenn du eh nur eine bestimmte Implementierung instanzieren willst. Diese kannst du doch direkt als Bean instanzieren mit Scope Prototype.
Ja das hatte ich am Anfang ja auch... Aber da der Handler nur einmal instanziert wird, hab ich ja immer die gleiche Instanz und ich brauch für jeden Editor eine neue !!! Darum die Idee mit der Factory oder wie würdest du immer eine neue Instanz ansonsten erstellen...
Ja das hatte ich am Anfang ja auch... Aber da der Handler nur einmal instanziert wird, hab ich ja immer die gleiche Instanz und ich brauch für jeden Editor eine neue !!!
JAAA Oo hatte ich doch versucht und das hat nicht geklaaappt...
Also so siehts jetzt aus. Wie würdest es anders machen? Wie gesagt hatte am Anfang anstatt die FooFactory immer das Bean mit der richtigen Impl mit Scope Prototype, aber da der Handler nur einmal instanziert wird, hatte ich auch immer die gleiche Instanz!!!
Jetzt
Java:
public class Handler extends AbstractHandler{
@Autowired
FooFactory factory;
private Object execute(){
FooIF foo = factory.getObject();
//neuen Editor erstellen
}
}
Vorher
Java:
public class Handler extends AbstractHandler{
@Autowired
FooIF foo;
private Object execute(){
//neuen Editor mit foo erstellen
}
}
Dafür ist das Factorybean auch nicht gedacht. Das FactoryBean injiziert nicht das FactoryBean selber sondern eine fertige Instanz der Klasse die es bilden soll. Jetzt habe ich endlich verstanden was du machen willst.
Dafür kannst du das FactoryBean nicht verwenden. Mach einfach eine Klasse FooFactory (ohne Implementierung von FactoryBean) und mach die Methode getObject gleich von der Rückgabe her richtig. Z.B. wie in folgendem Snippet:
Java:
public class FooFactory implements InitializingBean {
private Class<? extends FooIF> clazz;
private String implementation;
public FooIF newInstance() throws Exception {
return clazz.newInstance();
}
@Override
@SuppressWarnings("unchecked")
public void afterPropertiesSet() throws Exception {
clazz = (Class<? extends FooIF>) Class.forName(implementation);
}
public void setImplementation(String implementation) {
this.implementation = implementation;
}
public String getImplementation() {
return implementation;
}
}
PS: Denk dran, dass Class.forName in OSGI eventuell nicht funktioniert und du die Klasse per BundleClassLoader oder so laden musst (ka wie das genau in Eclipse funktioniert)
Noch mal das FactoryBean injiziert nicht sich selber sondern beim Injizieren wird von Spring getObject aufgerufen und das zurückgegebene Objekt injiziert. Ergo lässt sich die FactoryBean so wie du möchtest nicht verwenden. Du müsstest quasi eine FactoryBean erzeugen welche dann die eigentliche FactoryBean injiziert, was ziemlich sinnfrei wäre.
Ja da mit dem getObject war mir klar, das hab ich davor mal getestet!
1. Aber eigentlich kann ich ja auch ein normales Bean nehmen den scope Protoype setzen und jedes mal aus dem app context mit getBean das Bean neu raus holen oder?
2. Versteh ich den Sinn der FacortyBean nicht so ganz hab mir die Sache in der Spring Doku nochmal durchgelesen. Die FacortyBean macht doch nur Sinn wenn das Object das bei getObject zurückgeliefert wird keine Spring Sachen mehr injeziert oder? Weill wenn ich dort eine Instanz z.B. mit new Instanzier werden alle Spring z.B. Autowired nicht injeziert. Oder wie instanzier ich bei einer FactoryBean bei getObject das Objekt richtig?
Das FactoryBean macht schon Sinn, es kommt ja drauf an, wie die Instanz welche ich injizieren will erzeugen muss. Z.B. hat Lycia eine eigene statische Factory welche die Instanzen des Parsers erzeugt.