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)}
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
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.
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
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.
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.
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.
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.