applicationContext ne trouve pas de contrôleurs pour le contexte de Servlet
J'ai une application Web Spring avec un applicationContext.xml et un répartiteur-servlet.de configuration xml. J'ai défini le <context:component-scan />
dans applicationContext.xml, mais quand j'exécute mon application, les contrôleurs ne sont pas trouvés sauf si j'ajoute également <context:component-scan />
au dispatcher-servlet.XML. J'utilise le même paquet de base dans les deux, donc ce n'est pas le problème.
Je suis confus, parce que je pensais {[14] } que l'applicationContext.xml était un parent de dispatcher-servlet.XML. Je ne mettrais pas <context:component-scan />
dans applicationContext.xml suffit-il?
Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
EDIT: j'utilise également mvc: annotation-driven dans le dispatcher-servlet.xml, qui est censé ramasser les Contrôleurs (je pensais?).
EDIT 2: Voici les fichiers de configuration. J'ai supprimé un tas de paramètres Spring Security et OAuth de applicationContext.xml (pour des raisons de sécurité et étant qu'ils ne sont probablement pas pertinents de toute façon).
ApplicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"
xmlns:context="http://www.springframework.org/schema/context" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:component-scan base-package="bar.foo"/>
<context:property-placeholder location="classpath:my.properties" />
<bean class="bar.foo.ServicesConfig" />
</beans>
Répartiteur-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"
xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:component-scan base-package="bar.foo.controller" />
<mvc:annotation-driven/>
<mvc:default-servlet-handler />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
<property name="order" value="2" />
</bean>
<bean id="contentViewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</property>
<property name="order" value="1" />
</bean>
</beans>
EDIT 3: OK, c'est intéressant. Mes services et les classes dao sont dans un projet différent (JAR) que je référence du projet web. J'utilise la configuration basée sur java et le référencer à partir de applicationContext.xml:
<bean class="bar.foo.config.ServicesConfig" />
Donc, cela signifie qu'il n'y a que des annotations de contrôleur dans mon projet web (où applicationContext.xml est situé). Rétrospectivement, enlever contexte: component-scan à partir de mon applicationContext.xml ne devrait pas avoir d'effet, car il n'y a pas d'annotations à l'exception de celles de @Controller (correction à modifier: il y a des annotations @Autowired). Mais, quand je supprime le contexte: component-scan de applicationContext.xml, il dit que les contrôleurs (trouvés à partir de dispatcher servlet scan) ne peuvent pas trouver mes classes de Service. La référence à ServicesConfig ne devrait-elle pas suffire? Voici la classe ServicesConfig pour les références-elle a sa propre analyse des composants pour les Services, qui sont un paquet différent de ce que l'applicationContext.xml a été la numérisation.
@Configuration
@ComponentScan({ "some.other.package", "another.package" })
@ImportResource({ "classpath:commonBeans.xml" })
@PropertySource({ "classpath:services.properties",
"classpath:misc.properties" })
public class ServicesConfig {
// Bean definitions //
}
SOLUTION:
Lorsque j'ai supprimé context: component-scan de mon contexte racine, les contrôleurs ne récupéraient pas les beans de services autowired. C'est parce que le contexte racine fait référence à mon Bean de configuration basé sur java des services, mais je n'avais pas la configuration du contexte racine pour rechercher les composants. Par conséquent, lorsque j'ajoute l'analyse des composants au contexte racine (applicationContext.xml) tout fonctionne. Voici ce que j'ai maintenant:
ApplicationContext.xml:
<bean class="bar.foo.config.ServicesConfig" />
<context:component-scan base-package="bar.foo.config" />
Répartiteur-servlet.xml:
<context:component-scan base-package="bar.foo.controller" />
J'ai la configuration du contexte web pour pickup Controller, Autowired et toutes les autres annotations dans le package controller - Je ne suis pas sûr que ce soit la meilleure pratique ou non.
3 réponses
Vous avez raison-il y a deux contextes d'application différents, le contexte d'application racine chargé par ContextLoaderListener (au moment où le ServletContext est initialisé), et le contexte Web (chargé par DispatcherServlet), le contexte d'application racine est le parent du contexte Web.
Maintenant, puisque ce sont deux contextes d'application différents, ils sont agis différemment - si vous définissez component-scan
pour vos services dans le contexte de l'application, alors tous les beans pour le les services sont créés ici.
Lorsque votre servlet Dispatcher se charge, il commencera à créer le contexte Web, à un moment donné (piloté par <mvc:annotation-driven/>
il créera un mappage pour les méthodes de votre uri vers le Gestionnaire, il obtiendra la liste des beans dans le contexte de l'application (qui sera le contexte de l'application web, pas le contexte de l'application racine) et puisque vous doivent également définir une analyse de composant dans le contexte des servlets du répartiteur.
Une bonne pratique consiste à exclure les beans liés au contrôleur dans le contexte de L'Application racine:
<context:component-scan base-package="package">
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
Et seul le contrôleur est lié au contexte de L'Application Web:
<context:component-scan base-package="package" use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation" />
</context:component-scan>
Dans nos applications, nous définissons dans le répartiteur de servlet.xml
Je crois que c'est là qu'il est censé être plutôt que dans applicationContext.xml
Cette section de la documentation de printemps devrait fournir plus d'informations:
Http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html
Comme vous pouvez le voir sur l'un des diagrammes de la section 16.2, le dispatcher-servlet se trouve au-dessus de applicationContext dans le hiérarchie de contexte.
J'ai eu le même problème et après avoir comparé mon code web.xml
avec ce tutoriel Je l'ai changé et cela a fonctionné. voici mon fichier web.xml
:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/business-config.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
context-param
et listener
étaient ce que j'ai manqué.
J'espère que ça vous aidera.