bean proxy à portée de ressort

98

Quelqu'un peut-il expliquer l'utilisation de l' @ScopedProxyannotation de printemps ? Je pensais que cela avait quelque chose à voir avec les beans de session, mais je ne sais pas trop quoi.

Dans mon utilisation des étendues, j'ai utilisé des beans à portée de session sans @ScopedProxyannotation (ou sans proxies à portée aop), donc je suis vraiment sûr de savoir comment l'utiliser correctement.

Jeff Storey
la source
consultez la documentation du bean . La session est l' une des portées , mais pas la seule.
Gus
1
@Gus, je suis au courant des portées, mais je ne sais pas comment le proxy scoped joue là
dedans
1
La section 3.4.4.5 est à mon avis une assez bonne explication de ce que fait un proxy de portée. - le bit entre les deux exemples est la partie importante.
Gus
2
Ouais ça explique ça, merci. Si vous souhaitez ajouter une réponse à la question, j'accepterai.
Jeff Storey

Réponses:

249

La section 3.4.4.5 de la documentation du printemps l'explique assez bien:

(veuillez noter que la définition suivante du bean 'userPreferences' telle qu'elle est est incomplète):

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

<bean id="userManager" class="com.foo.UserManager">
    <property name="userPreferences" ref="userPreferences"/>
</bean>

D'après la configuration ci-dessus, il est évident que le bean singleton 'userManager' est injecté avec une référence au bean à portée de session HTTP 'userPreferences'. Le point saillant ici est que le bean 'userManager' est un singleton ... il sera instancié exactement une fois par conteneur , et ses dépendances (dans ce cas une seule, le bean 'userPreferences') ne seront également injectées (une fois! ) .

Cela signifie que le 'userManager' ne fonctionnera (conceptuellement) que sur le même objet 'userPreferences', c'est-à-dire celui avec lequel il a été injecté à l'origine.

Ce n'est pas ce que vous voulez lorsque vous injectez un bean à portée de session HTTP en tant que dépendance dans un objet collaborant (généralement). Ce que nous voulons plutôt, c'est un seul objet 'userManager' par conteneur , puis, pendant la durée de vie d'une session HTTP, nous voulons voir et utiliser un objet 'userPreferences' qui est spécifique à ladite session HTTP .

Ce dont vous avez besoin est plutôt d'injecter une sorte d'objet qui expose exactement la même interface publique que la classe UserPreferences (idéalement un objet qui est une instance UserPreferences) et qui est suffisamment intelligent pour pouvoir aller chercher le véritable objet UserPreferences quel que soit le mécanisme de portée sous-jacent que nous avons choisi (requête HTTP, session, etc.). Nous pouvons alors injecter en toute sécurité cet objet proxy dans le bean 'userManager', qui ignorera parfaitement que la référence UserPreferences qu'il tient est un proxy .

Dans notre cas, lorsqu'une instance UserManager appelle une méthode sur l'objet UserPreferences injecté de dépendance, elle appellera vraiment une méthode sur le proxy ... le proxy va alors s'éteindre et récupérer le véritable objet UserPreferences à partir de (dans ce cas) la session HTTP et déléguez l'appel de méthode sur l'objet réel UserPreferences récupéré.

C'est pourquoi vous avez besoin de la configuration suivante, correcte et complète lors de l'injection de beans de type requête, session et globalSession dans des objets collaboratifs:

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
    <aop:scoped-proxy/>
</bean>

<bean id="userManager" class="com.foo.UserManager">
    <property name="userPreferences" ref="userPreferences"/>
</bean>
Gus
la source
Ainsi, lorsque j'utilise l'annotation @ScopedProxy, un proxy sera automatiquement utilisé, et c'est tout? ScopedProxy signifie -> Ne pas utiliser cette classe telle quelle, utiliser un proxy pour cela?
Koray Tugay
3
J'utilise spring-web: 4.3.3 et il semble que l'annotation a @ScopedProxyété remplacée par @RequestScopeet d'autres. Vous pouvez trouver des exemples ici: logicbig.com/tutorials/spring-framework/spring-core
...
1
Nous pourrions dire que lorsque la notation @Scope(value="session", proxyMode = ScopedProxyMode.TARGET_CLASS)est utilisée, SpringMVC n'utilise pas WebApplicationContext pour Autowired, mais utilise CGLIB pour créer le proxy ?. Voici des exemples d' autres explications sur
Kurapika
0

Après avoir essayé diverses options différentes spécifiées ici et la documentation de printemps, j'ai compris pour une raison quelconque que Spring MVC est un contrôleur de câblage automatique bizarre lorsque vous utilisez l'annotation @Controller et que vous avez plusieurs contrôleurs de ce type dans votre application Web. Modification de l'annotation en @RestController (value = "UniqueControllerv1"), le problème est résolu.

geeksquad87
la source