Je souhaite utiliser un prototype de bean annoté dans mon contrôleur. Mais le printemps crée plutôt un haricot singleton. Voici le code pour cela:
@Component
@Scope("prototype")
public class LoginAction {
private int counter;
public LoginAction(){
System.out.println(" counter is:" + counter);
}
public String getStr() {
return " counter is:"+(++counter);
}
}
Code contrôleur:
@Controller
public class HomeController {
@Autowired
private LoginAction loginAction;
@RequestMapping(value="/view", method=RequestMethod.GET)
public ModelAndView display(HttpServletRequest req){
ModelAndView mav = new ModelAndView("home");
mav.addObject("loginAction", loginAction);
return mav;
}
public void setLoginAction(LoginAction loginAction) {
this.loginAction = loginAction;
}
public LoginAction getLoginAction() {
return loginAction;
}
}
Modèle de vitesse:
LoginAction counter: ${loginAction.str}
Spring config.xml
a activé l'analyse des composants:
<context:annotation-config />
<context:component-scan base-package="com.springheat" />
<mvc:annotation-driven />
J'obtiens un décompte incrémenté à chaque fois. Je ne sais pas où je me trompe!
Mettre à jour
Comme suggéré par @gkamal , j'ai créé HomeController
webApplicationContext
-aware et cela a résolu le problème.
code mis à jour:
@Controller
public class HomeController {
@Autowired
private WebApplicationContext context;
@RequestMapping(value="/view", method=RequestMethod.GET)
public ModelAndView display(HttpServletRequest req){
ModelAndView mav = new ModelAndView("home");
mav.addObject("loginAction", getLoginAction());
return mav;
}
public LoginAction getLoginAction() {
return (LoginAction) context.getBean("loginAction");
}
}
spring
spring-mvc
Tintin
la source
la source
Réponses:
Le prototype de portée signifie que chaque fois que vous demanderez à spring (getBean ou injection de dépendances) une instance, il créera une nouvelle instance et y donnera une référence.
Dans votre exemple, une nouvelle instance de LoginAction est créée et injectée dans votre HomeController. Si vous avez un autre contrôleur dans lequel vous injectez LoginAction, vous obtiendrez une instance différente.
Si vous voulez une instance différente pour chaque appel - alors vous devez appeler getBean à chaque fois - l'injection dans un bean singleton n'y parviendra pas.
la source
request
portée au lieu d'uneprototype
étendue? Auriez-vous encore besoin de récupérer le haricot aveccontext.getBean(..)
?Depuis Spring 2.5, il existe un moyen très simple (et élégant) d'y parvenir.
Vous pouvez simplement changer les paramètres
proxyMode
etvalue
de l'@Scope
annotation.Avec cette astuce, vous pouvez éviter d'écrire du code supplémentaire ou d'injecter le ApplicationContext chaque fois que vous avez besoin d'un prototype à l'intérieur d'un bean singleton.
Exemple:
Avec la configuration ci-dessus
LoginAction
(à l'intérieurHomeController
), il y a toujours un prototype même si le contrôleur est un singleton .la source
Ce n'est pas parce que le bean injecté dans le contrôleur est à portée prototype que le contrôleur l'est!
la source
@controller est un objet singleton, et si vous injectez un bean prototype dans une classe singleton, le bean prototype sera également un singleton à moins que vous ne spécifiez en utilisant la propriété lookup-method qui crée en fait une nouvelle instance de bean prototype pour chaque appel que vous effectuez.
la source
Comme mentionné par nicholas.hauschild, l' injection de contexte Spring n'est pas une bonne idée. Dans votre cas, @Scope ("request") suffit à le corriger. Mais disons que vous avez besoin de plusieurs instances de la
LoginAction
méthode du contrôleur. Dans ce cas, je recommanderais de créer le bean de Supplier ( solution Spring 4 ):Puis injectez-le dans le contrôleur:
la source
ObjectFactory
qui servent le même but que le fournisseur, mais peuvent être définis comme une norme@Bean
par laquelle je veux dire pas besoin de retourner un lambda.L'utilisation
ApplicationContextAware
vous lie à Spring (ce qui peut ou non être un problème). Je recommanderais de passer unLoginActionFactory
, que vous pouvez demander une nouvelle instance de aLoginAction
chaque fois que vous en avez besoin.la source
factory-method
ici ...LoginActionFactory
dans le contrôleur, maisfactory-method
ne semble pas résoudre le problème car il crée simplement un autre haricot de printemps via l'usine. L'injection de ce bean dans le contrôleur singleton ne résoudra pas le problème.utiliser la portée de la requête
@Scope("request")
pour obtenir le bean pour chaque requête, ou@Scope("session")
pour obtenir le bean pour chaque session 'utilisateur'la source
Un bean protoype injecté à l'intérieur d'un bean singelton se comportera comme singelton jusqu'à ce qu'il soit appelé expilitivement pour créer une nouvelle instance par get bean.
la source
@Composant
@Scope (valeur = "prototype")
public class TennisCoach implémente Coach {
// du code
}
la source
Vous pouvez créer une classe statique dans votre contrôleur comme ceci:
la source
Une autre façon de résoudre le problème est l'injection de méthode avec l' annotation @Lookup .
Voici un bel article sur cette question de l' injection de haricots prototypes dans une instance singleton avec plusieurs solutions.
https://www.baeldung.com/spring-inject-prototype-bean-into-singleton
la source
Votre contrôleur besoin également
@Scope("prototype")
définicomme ça:
la source