wake-up-neo.com

Selbsteinspritzung mit Feder

Ich habe den folgenden Code mit Spring 3.x ausprobiert, der mit BeanNotFoundException fehlgeschlagen ist, und er sollte den Antworten auf eine Frage entsprechen, die ich zuvor gestellt habe. - Kann ich dieselbe Klasse mit Spring injizieren?

@Service
public class UserService implements Service{
    @Autowired
    private Service self;
}

Da ich dies mit Java 6 ausprobiert habe, habe ich festgestellt, dass der folgende Code gut funktioniert:

@Service(value = "someService")
public class UserService implements Service{
    @Resource(name = "someService")
    private Service self;
}

aber ich verstehe nicht, wie es die zyklische Abhängigkeit auflöst.

BEARBEITEN:
Hier ist die Fehlermeldung. Das OP erwähnte es in einem Kommentar zu einer der Antworten:

Ursache: org.springframework.beans.factory.NoSuchBeanDefinitionException: Es wurde keine übereinstimmende Bean vom Typ [com.spring.service.Service] für die Abhängigkeit gefunden: Es wird mindestens eine Bean erwartet, die als autowire-Kandidat für diese Abhängigkeit qualifiziert ist. Abhängigkeitsanmerkungen: {@ org.springframework.beans.factory.annotation.Autowired (required = true)}

52
Premraj

Update: Februar 2016

Self Autowiring wird offiziell in Spring Framework 4.3 unterstützt. Die Implementierung ist in diesem GitHub-Commit zu sehen.


Der entscheidende Grund dafür, dass Sie sich nicht selbst einrichten können, ist, dass die Implementierung der Spring-Methode DefaultListableBeanFactory.findAutowireCandidates(String, Class, DependencyDescriptor) die Möglichkeit ausdrücklich ausschließt. Dies ist im folgenden Codeauszug dieser Methode sichtbar:

for (String candidateName : candidateNames) {
    if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) {
        result.put(candidateName, getBean(candidateName));
    }
}

Zu Ihrer Information: Der Name der Bean (d. H. Der Bean, die versucht, sich automatisch zu verbinden) ist beanName. Diese Bean ist in der Tat ein Kandidat für die automatische Verbindung, aber die obige if-Bedingung gibt false zurück (da candidateName tatsächlich der beanName entspricht). So kann man eine Bean einfach nicht mit sich selbst drahtieren (zumindest nicht ab Spring 3.1 M1).

Nun, ob dies beabsichtigtes Verhalten semantisch ist oder nicht, das ist eine andere Frage. ;)

Ich werde Jürgen fragen und sehen, was er zu sagen hat.

Grüße,

Sam (Core Spring Committer)

p.s. Ich habe eine Spring-JIRA-Ausgabe geöffnet, um zu prüfen, ob das automatische Abhören mit @Autowired unterstützt werden soll. Fühlen Sie sich frei, diese Ausgabe hier anzusehen oder zu stimmen: https://jira.springsource.org/browse/SPR-8450

40
Sam Brannen

Dieser Code funktioniert auch:

@Service
public class UserService implements Service {

    @Autowired
    private ApplicationContext applicationContext;

    private Service self;

    @PostConstruct
    private void init() {
        self = applicationContext.getBean(UserService.class);
    }
}

Ich weiß nicht warum, aber Spring scheint die Bean von ApplicationContext zu bekommen, wenn erstellt , aber nicht initialisiert ist. @Autowired funktioniert vor der Initialisierung und kann dieselbe Bean nicht finden. Also funktioniert @Resource vielleicht nach @Autowired und vor @PostConstruct.

Aber ich weiß nicht, nur spekulieren. Wie auch immer, gute Frage.

31
sinuhepop

Die elegantere Lösung für das Selbstaufrufproblem ist übrigens die Verwendung von AspectJ Load-Time Weaving für Ihre Transaktionsproxys (oder den von AOP eingeführten Proxy).

Mit der annotationsgesteuerten Transaktionsverwaltung können Sie beispielsweise den Modus "Aspektj" wie folgt verwenden:

<tx:annotation-driven mode="aspectj" />

Der Standardmodus ist "Proxy" (d. H. Dynamische JDK-Proxies).

Grüße,

Sam

1
Sam Brannen

AOP-Proxy vom Objekt selbst holen frage schlägt einen alternativen Hacky-Ansatz mit AopContext.currentProxy() vor, der für spezielle Fälle geeignet sein kann.

1
Vadzim

In Anbetracht des obigen Codes sehe ich keine zyklische Abhängigkeit. Sie müssen eine Instanz von Service in UserService injizieren. Die Implementierung des injizierten Dienstes muss nicht unbedingt ein anderer Benutzerservice sein, so dass keine zyklische Abhängigkeit besteht.

Ich verstehe nicht, warum Sie einen UserService in UserService injizieren würden, aber ich hoffe, dass dies ein theoretischer Versuch ist oder so.

1
Stijn Geukens

Es sieht aus, als würde Frühling ein Objekt erstellen und konfigurieren und es dann in den Bean-Lookup-Kontext einfügen. Im Falle von Java denke ich, dass es das Objekt erstellt und es mit dem Namen und der Konfiguration verknüpft, wenn das Objekt anhand des Namens im Kontext nachgeschlagen wird. 

0
Krishna

Nur ein weiterer Ansatz:

@EnableAsync
@SpringBootApplication
public class Application {

    @Autowired
    private AccountStatusService accountStatusService;

    @PostConstruct
    private void init() {
        accountStatusService.setSelf(accountStatusService);
    }
}

@Service
public class AccountStatusService {
    private AccountStatusService self;

    public void setSelf(AccountStatusService self) {
        this.self = self;
    }
}

damit ist Ihr Service in Vertretung. Ich habe dies getan, um mit asynchronen Methoden in sich selbst zu arbeiten.

Ich habe die @sinuhepop-Lösung ausprobiert:

@PostConstruct
private void init() {
    self = applicationContext.getBean(UserService.class);
}

Es wurde eine Injektion durchgeführt, aber der Dienst befand sich nicht im Proxy und meine Methoden liefen nicht in einem neuen Thread. Mit diesem Ansatz funktioniert es so, wie ich es gerne hätte.

0
user3081007