Ich bin ein wenig verwirrt darüber, wie das Inversion der Kontrolle (IoC
) in Spring
funktioniert.
Angenommen, ich habe eine Serviceklasse mit dem Namen UserServiceImpl
, die die Schnittstelle UserService
implementiert.
Wie wäre das @Autowired
?
Und in meinem Controllers
, wie würde ich instantiate
und instance
von diesem Service?
Würde ich einfach Folgendes tun?
UserService userService = new UserServiceImpl();
Erstens, und vor allem - alle Spring Beans werden verwaltet - "leben" sie in einem Container, der als "Anwendungskontext" bezeichnet wird.
Zweitens hat jede Anwendung einen Einstiegspunkt in diesen Kontext. Webanwendungen haben ein Servlet, JSF verwendet einen El-Resolver usw. Außerdem gibt es einen Ort, an dem der Anwendungskontext gebootet und alle Beans automatisch verdrahtet werden. In Webanwendungen kann dies ein Startup-Listener sein.
Die automatische Verdrahtung erfolgt, indem eine Instanz einer Bean in das gewünschte Feld einer Instanz einer anderen Bean eingefügt wird. Beide Klassen sollten Beans sein, d. H. Sie sollten so definiert sein, dass sie im Anwendungskontext leben.
Was ist "Leben" im Anwendungskontext? Dies bedeutet, dass der Kontext die Objekte instanziiert, nicht Sie. Das heißt - Sie machen niemals new UserServiceImpl()
- der Container findet jeden Injektionspunkt und setzt dort eine Instanz.
In Ihren Controllern haben Sie nur Folgendes:
@Controller // Defines that this class is a spring bean
@RequestMapping("/users")
public class SomeController {
// Tells the application context to inject an instance of UserService here
@Autowired
private UserService userService;
@RequestMapping("/login")
public void login(@RequestParam("username") String username,
@RequestParam("password") String password) {
// The UserServiceImpl is already injected and you can use it
userService.login(username, password);
}
}
Ein paar Anmerkungen:
applicationContext.xml
sollten Sie den <context:component-scan>
aktivieren, damit Klassen nach den Anmerkungen @Controller
, @Service
usw. durchsucht werden.UserServiceImpl
sollte auch als Bean definiert werden - entweder mit der Annotation <bean id=".." class="..">
oder mit der Annotation @Service
. Da es der einzige Implementierer von UserService
sein wird, wird es injiziert.@Autowired
kann Spring XML-konfigurierbares Autowiring verwenden. In diesem Fall wird allen Feldern, deren Name oder Typ mit einer vorhandenen Bean übereinstimmt, automatisch eine Bean hinzugefügt. Tatsächlich war dies die ursprüngliche Idee von Autowiring: In Felder wurden Abhängigkeiten ohne Konfiguration eingefügt. Andere Anmerkungen wie @Inject
, @Resource
können ebenfalls verwendet werden.Hängt davon ab, ob Sie die Annotationsroute oder die Bean-XML-Definitionsroute gewählt haben.
Angenommen, Sie haben die Bohnen in Ihrem applicationContext.xml
definiert:
<beans ...>
<bean id="userService" class="com.foo.UserServiceImpl"/>
<bean id="fooController" class="com.foo.FooController"/>
</beans>
Die automatische Verdrahtung erfolgt beim Start der Anwendung. In fooController
, das aus Gründen der Argumentation die UserServiceImpl
-Klasse verwenden möchte, würden Sie dies folgendermaßen kommentieren:
public class FooController {
// You could also annotate the setUserService method instead of this
@Autowired
private UserService userService;
// rest of class goes here
}
Wenn @Autowired
angezeigt wird, sucht Spring nach einer Klasse, die der Eigenschaft in applicationContext
entspricht, und fügt sie automatisch ein. Wenn Sie mehr als eine UserService
Bean haben, müssen Sie festlegen, welche verwendet werden soll.
Wenn Sie Folgendes tun:
UserService service = new UserServiceImpl();
Der @Autowired
wird nur abgerufen, wenn Sie ihn selbst einstellen.
@Autowired
ist eine Annotation, die im Frühjahr 2.5 eingeführt wurde und nur für die Injektion verwendet wird.
Zum Beispiel:
class A {
private int id;
// With setter and getter method
}
class B {
private String name;
@Autowired // Here we are injecting instance of Class A into class B so that you can use 'a' for accessing A's instance variables and methods.
A a;
// With setter and getter method
public void showDetail() {
System.out.println("Value of id form A class" + a.getId(););
}
}
Wie funktioniert @Autowired
intern?
Beispiel:
class EnglishGreeting {
private Greeting greeting;
//setter and getter
}
class Greeting {
private String message;
//setter and getter
}
.xml-Datei sieht ähnlich aus, wenn @Autowired
nicht verwendet wird:
<bean id="englishGreeting" class="com.bean.EnglishGreeting">
<property name="greeting" ref="greeting"/>
</bean>
<bean id="greeting" class="com.bean.Greeting">
<property name="message" value="Hello World"/>
</bean>
Wenn Sie @Autowired
verwenden, dann:
class EnglishGreeting {
@Autowired //so automatically based on the name it will identify the bean and inject.
private Greeting greeting;
//setter and getter
}
.xml-Datei sieht ähnlich aus, wenn @Autowired
nicht verwendet wird:
<bean id="englishGreeting" class="com.bean.EnglishGreeting"></bean>
<bean id="greeting" class="com.bean.Greeting">
<property name="message" value="Hello World"/>
</bean>
Wenn Sie immer noch Zweifel haben, gehen Sie die folgende Live-Demo durch
Sie müssen nur Ihre Serviceklasse UserServiceImpl
mit Anmerkungen versehen:
@Service("userService")
Der Federbehälter kümmert sich um den Lebenszyklus dieser Klasse, da er als Service registriert wird.
Dann können Sie es in Ihrem Controller automatisch verbinden (instanziieren) und seine Funktionalität nutzen:
@Autowired
UserService userService;
Spring Dependency Inject hilft Ihnen, Kopplungen aus Ihren Klassen zu entfernen. Anstatt ein Objekt wie dieses zu erstellen:
UserService userService = new UserServiceImpl();
Sie werden dies verwenden, nachdem Sie DI eingeführt haben:
@Autowired
private UserService userService;
Um dies zu erreichen, müssen Sie eine Bean Ihres Dienstes in Ihrer ServiceConfiguration
-Datei erstellen. Danach müssen Sie diese ServiceConfiguration
-Klasse in Ihre WebApplicationConfiguration
-Klasse importieren, damit Sie diese Bean wie folgt automatisch in Ihren Controller verdrahten können:
public class AccController {
@Autowired
private UserService userService;
}
Ein konfigurationsbasiertes POC für Java finden Sie hier Beispiel .
Es gibt drei Möglichkeiten, wie Sie eine Instanz mit @Autowired
erstellen können.
1. @Autowired
unter Eigenschaften
Die Annotation kann direkt auf Eigenschaften angewendet werden, sodass keine Getter und Setter mehr erforderlich sind:
@Component("userService")
public class UserService {
public String getName() {
return "service name";
}
}
@Component
public class UserController {
@Autowired
UserService userService
}
Im obigen Beispiel sucht Spring und injiziert userService
, wenn UserController
erstellt wird.
2. @Autowired
on Setters
Die Annotation @Autowired
kann für Setter-Methoden verwendet werden. Wenn im folgenden Beispiel die Annotation für die Setter-Methode verwendet wird, wird die Setter-Methode mit der Instanz von userService
aufgerufen, wenn UserController
erstellt wird:
public class UserController {
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
}
. @Autowired
auf Konstruktoren
Die Annotation @Autowired
kann auch für Konstruktoren verwendet werden. Im folgenden Beispiel wird, wenn die Annotation für einen Konstruktor verwendet wird, eine Instanz von userService
als Argument in den Konstruktor eingefügt, wenn UserController
erstellt wird:
public class UserController {
private UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService= userService;
}
}
Das gesamte Konzept der Umkehrung der Steuerung bedeutet, dass Sie keine Zeit haben, Objekte manuell zu instanziieren und alle erforderlichen Abhängigkeiten bereitzustellen. Wenn Sie eine Klasse mit einer entsprechenden Anmerkung versehen (z. B. @Service
), instanziiert Spring das Objekt automatisch für Sie. Wenn Sie mit Anmerkungen nicht vertraut sind, können Sie stattdessen auch eine XML-Datei verwenden. Es ist jedoch keine schlechte Idee, Klassen in Komponententests manuell zu instanziieren (mit dem Schlüsselwort new
), wenn Sie nicht den gesamten Spring-Kontext laden möchten.
Beachten Sie, dass Sie die Annotation @Autowired
aktivieren müssen, indem Sie das Element <context:annotation-config/>
in die Spring-Konfigurationsdatei einfügen. Dadurch wird AutowiredAnnotationBeanPostProcessor
registriert, das die Verarbeitung von Anmerkungen übernimmt.
Anschließend können Sie Ihren Dienst mithilfe der Feldinjektionsmethode automatisch verdrahten.
public class YourController{
@Autowired
private UserService userService;
}
Ich fand dies aus dem Beitrag Spring @autowired Annotation