2009-07-24 5 views
0

Grundsätzlich habe ich eine Klasse A, die von Klasse B abhängt, die wiederum von einer federverwalteten Bean C abhängt, aber ich möchte B nicht als Klassenvariable behalten, sondern B innerhalb einer Methode aus irgendeinem Grund verwenden . Meine Lösung besteht darin, eine statische Methode get() in B zu erstellen, die eine Instanz von B zurückgibt. Das Problem ist nun, dass C nicht korrekt in B injiziert wird.Kann Spring diesen Benutzerfall verarbeiten? Weder Eigenschaft noch Konstruktorinjektion

// A cannot have B as a class/field variable. 

public class A { 
    public void method(){ 
     // B.get() returns a instance of B, but this instance is not the 
     // instance that spring created, it is the static "instance" in B. 

     B.get().doSomething();// ofcourse it throws out a nullpointer exception 
    } 
} 

class B{ 
    @Resource(name = "c") 
    private C c; 

    private static B instance; 


    public static B get() { 
     return instance==null ? (instance=new B()) : instance; 
    } 

    public void doSomething(){ 
     c.toString();  // this line will break if c is not 
          // injected to the instance of b 
    } 
} 

@Service("c") 
class C {    
} 

Wie löse ich dieses Problem?

+0

Warum ist es unmöglich, B nach A zu injizieren? Das ist der korrekteste und "früheste" Weg, dies zu tun. Ich würde versuchen, das Grundproblem zu lösen, anstatt zu versuchen, einen Workaround zu finden. –

Antwort

0

Sie müssen die Bean programmgesteuert von der Spring ApplicationContext, entweder innerhalb A#method(), oder im Konstruktor von A oder seiner Initialisierungsmethode, und Zwischenspeichern der Spring injected B-Instanz.

2

Der ganze Sinn der Verwendung von Spring ist es ein Dependency Injection-Framework ist, und Sie sind hartzucodieren die Abhängigkeit von B in A.

Versuchen sehr schwer, nicht das zu tun. Wenn Sie B nicht in einer Instanzvariablen speichern möchten, übergeben Sie es als Argument an die Methode.

Wenn Sie hartnäckig dabei sind, dann müssen Sie einen ApplicationContext holen und ihn selbst laden. Eine Alternative könnte darin bestehen, dass B InitializingBean implementiert und anschließend die Methode afterPropertiesSet die aktuelle Instanz mit einer statischen Instanzvariable registriert.

+0

Wenn Sie einen ApplicationContext abrufen möchten, können Sie die ApplicationContextAware-Schnittstelle implementieren. –

1

Es gibt kein direktes bisschen Frühling, um dies zu unterstützen, aber es gibt ein paar Arbeitsumgebungen, um das Problem zu lösen.

  1. fasse den Application in B.get() und rufen getBean um Frühling zu bekommen B. Habhaft der Application zu konstruieren ist eine andere Aufgabe als es in der Regel nicht überall statisch gehalten wird, einen Blick Referenzhandbuch im Frühjahr für 'schmutzige Singletons'

  2. Let Feder konstruieren, um die Bohnen und halten dann einen Verweis auf sie in der Instanzvariable:

@Service ('b') Klasse B { @Resource (name = "c") private C c;

private static B instance; 

public B(){ 
    // sets the static here 
    // not ideal...should use afterProperties set or what ever the Annotation equivalent is 
    instance = this; 
} 

public static B get() { 
    if(instance == null){ 
      throw new IllegalStateException("errr...say something useful here") 
    } 
    return instance; 
} 

public void doSomething(){ 
    c.toString();  // this line will break if c is not 
         // injected to the instance of b 
} 

}

I 2. verwendet ein paar Mal an verschiedenen Projekten gesehen haben, ist es nicht schön, und wenn Sie die Wahl haben, es nicht tun, nur Frühjahr bekommen die ganze App verdrahten . Aber wenn Sie keine Wahl haben, könnte es die schlechteste Option sein.

Verwandte Themen