Je suis un peu confus quant à la manière dont inversion du contrôle (IoC
) fonctionne dans Spring
.
Disons que j'ai une classe de service appelée UserServiceImpl
qui implémente l'interface UserService
.
Comment cela serait-il _@Autowired
_?
Et dans mon Controllers
, comment pourrais-je instantiate
un instance
de ce service?
Est-ce que je ferais juste ce qui suit?
_UserService userService = new UserServiceImpl();
_
Premièrement, et le plus important, tous les beans Spring sont gérés: ils "vivent" dans un conteneur, appelé "contexte d'application".
Deuxièmement, chaque application a un point d’entrée dans ce contexte. Les applications Web ont un servlet, JSF utilise un el-resolver, etc. Il existe également un emplacement où le contexte de l'application est initialisé et où tous les beans sont configurés automatiquement. Dans les applications Web, cela peut être un écouteur de démarrage.
Le câblage automatique se produit en plaçant une instance d'un bean dans le champ souhaité d'une instance d'un autre bean. Les deux classes doivent être des haricots, c'est-à-dire qu'elles doivent être définies pour vivre dans le contexte de l'application.
Qu'est-ce que "vivre" dans le contexte de l'application? Cela signifie que le contexte instancie les objets, pas vous. C'est à dire. - vous ne faites jamais new UserServiceImpl()
- le conteneur trouve chaque point d'injection et y définit une instance.
Dans vos contrôleurs, vous n’avez que ce qui suit:
@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);
}
}
Quelques notes:
applicationContext.xml
, vous devez activer le <context:component-scan>
afin que les classes soient analysées pour les annotations @Controller
, @Service
, etc.UserServiceImpl
devrait également être défini comme un haricot - en utilisant <bean id=".." class="..">
ou en utilisant l'annotation @Service
. Comme ce sera le seul implémenteur de UserService
, il sera injecté.@Autowired
, Spring peut utiliser le câblage automatique configurable par XML. Dans ce cas, tous les champs dont le nom ou le type correspond à un bean existant reçoivent automatiquement un bean injecté. En fait, c'était l'idée de départ du câblage automatique: avoir des champs injectés avec des dépendances sans configuration. D'autres annotations telles que @Inject
, @Resource
peuvent également être utilisées.Cela dépend si vous avez utilisé la route des annotations ou la route de définition XML du bean.
Supposons que vous ayez défini les haricots dans votre applicationContext.xml
:
<beans ...>
<bean id="userService" class="com.foo.UserServiceImpl"/>
<bean id="fooController" class="com.foo.FooController"/>
</beans>
L'auto-câblage a lieu au démarrage de l'application. Ainsi, dans fooController
, qui souhaite utiliser les arguments comme argument pour utiliser la classe UserServiceImpl
, vous l'annoteriez comme suit:
public class FooController {
// You could also annotate the setUserService method instead of this
@Autowired
private UserService userService;
// rest of class goes here
}
Lorsqu'il verra @Autowired
, Spring recherchera une classe qui correspond à la propriété dans la variable applicationContext
et l'injectera automatiquement. Si vous avez plus d'un bean UserService
, vous devrez alors spécifier lequel, il convient d'utiliser.
Si vous procédez comme suit:
UserService service = new UserServiceImpl();
Il ne prendra le @Autowired
que si vous le configurez vous-même.
@Autowired
est une annotation introduite dans Spring 2.5 et utilisée uniquement pour l'injection.
Par exemple:
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(););
}
}
Comment @Autowired
fonctionne-t-il en interne?
Exemple:
class EnglishGreeting {
private Greeting greeting;
//setter and getter
}
class Greeting {
private String message;
//setter and getter
}
Fichier .xml, il se ressemblera s'il n'utilise pas @Autowired
:
<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>
Si vous utilisez @Autowired
, alors:
class EnglishGreeting {
@Autowired //so automatically based on the name it will identify the bean and inject.
private Greeting greeting;
//setter and getter
}
Fichier .xml, il se ressemblera s'il n'utilise pas @Autowired
:
<bean id="englishGreeting" class="com.bean.EnglishGreeting"></bean>
<bean id="greeting" class="com.bean.Greeting">
<property name="message" value="Hello World"/>
</bean>
Si vous avez encore des doutes, passez par la démonstration en direct ci-dessous
Il vous suffit d'annoter votre classe de service UserServiceImpl
avec une annotation:
@Service("userService")
Le conteneur Spring prendra en charge le cycle de vie de cette classe lors de son enregistrement en tant que service.
Ensuite, dans votre contrôleur, vous pouvez automatiquement le filer (instancier) et utiliser ses fonctionnalités:
@Autowired
UserService userService;
Spring dependency inject vous aide à supprimer le couplage de vos classes. Au lieu de créer un objet comme ceci:
UserService userService = new UserServiceImpl();
Vous allez utiliser ceci après avoir introduit DI:
@Autowired
private UserService userService;
Pour ce faire, vous devez créer un bean de votre service dans votre fichier ServiceConfiguration
. Après cela, vous devez importer cette classe ServiceConfiguration
dans votre classe WebApplicationConfiguration
afin de pouvoir acheminer automatiquement ce bean dans votre contrôleur de la manière suivante:
public class AccController {
@Autowired
private UserService userService;
}
Vous pouvez trouver un exemple de POC basé sur la configuration Java ici .
Il y a 3 façons de créer une instance en utilisant @Autowired
.
1. @Autowired
sur Propriétés
L'annotation peut être utilisée directement sur les propriétés, éliminant ainsi le besoin de getters et de setters:
@Component("userService")
public class UserService {
public String getName() {
return "service name";
}
}
@Component
public class UserController {
@Autowired
UserService userService
}
Dans l'exemple ci-dessus, Spring recherche et injecte userService
lorsque UserController
est créé.
2. @Autowired
sur les Setters
L'annotation @Autowired
peut être utilisée avec les méthodes de définition. Dans l'exemple ci-dessous, lorsque l'annotation est utilisée sur la méthode setter, la méthode setter est appelée avec l'occurrence de userService
lorsque UserController
est créé:
public class UserController {
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
}
. @Autowired
sur les constructeurs
L'annotation @Autowired
peut également être utilisée sur des constructeurs. Dans l'exemple ci-dessous, lorsque l'annotation est utilisée sur un constructeur, une instance de userService
est injectée en tant qu'argument du constructeur lorsque UserController
est créé:
public class UserController {
private UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService= userService;
}
}
Le concept entier d'inversion de contrôle signifie que vous êtes libre d'une corvée d'instancier manuellement des objets et de fournir toutes les dépendances nécessaires. Lorsque vous annotez une classe avec une annotation appropriée (par exemple, @Service
), Spring instanciera automatiquement un objet pour vous. Si vous n'êtes pas familier avec les annotations, vous pouvez également utiliser un fichier XML. Toutefois, il n’est pas mauvais d’instancier manuellement les classes (avec le mot clé new
] dans les tests unitaires lorsque vous ne souhaitez pas charger tout le contexte de ressort.
N'oubliez pas que vous devez activer l'annotation @Autowired
en ajoutant l'élément <context:annotation-config/>
dans le fichier de configuration de ressort. Ceci enregistrera la AutowiredAnnotationBeanPostProcessor
qui prend en charge le traitement des annotations.
Et vous pouvez ensuite autoriser automatiquement votre service en utilisant la méthode d’injection sur site.
public class YourController{
@Autowired
private UserService userService;
}
J'ai trouvé cela dans le message Spring @autowired annotation