applicationContext找不到Servlet上下文的控制器 [英] applicationContext not finding Controllers for Servlet context

查看:64
本文介绍了applicationContext找不到Servlet上下文的控制器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有applicationContext.xml和dispatcher-servlet.xml配置的Spring Web应用程序.我已经在applicationContext.xml中定义了<context:component-scan />,但是当我运行我的应用程序时,除非将<context:component-scan />添加到dispatcher-servlet.xml中,否则找不到控制器.我在两者中都使用了相同的基本软件包,所以这不是问题.

I have a Spring web app with an applicationContext.xml and a dispatcher-servlet.xml configuration. I've defined the <context:component-scan /> in applicationContext.xml, but when I run my app the Controllers are not found unless I also add <context:component-scan /> to the dispatcher-servlet.xml. I'm using the same base-package in both, so that's not the issue.

我很困惑,因为我认为,applicationContext.xml是dispatcher-servlet.xml的父级.

I am confused, because I thought that the applicationContext.xml was a parent of dispatcher-servlet.xml. Wouldn't putting <context:component-scan /> in applicationContext.xml suffice?

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>

我还在调度程序servlet.xml中使用mvc:annotation驱动,应该用来拾取Controllers(我想?).

I am also using mvc:annotation-driven in the dispatcher-servlet.xml, which is supposed to pick up Controllers (I thought?).

这是配置文件.我从applicationContext.xml中删除了一堆Spring Security和OAuth设置(出于安全原因,并且可能与它们无关).

EDIT 2: Here are the config files. I removed a bunch of Spring Security and OAuth settings from applicationContext.xml (for security reasons and being they probably aren't relevant anyway).

applicationContext.xml

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>

dispatcher-servlet.xml

dispatcher-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>

好的,这很有趣.我的服务和dao类位于从Web项目引用的其他项目(JAR)中.我正在使用基于Java的配置,并从applicationContext.xml引用它:

EDIT 3: Okay, this is interesting. My services and dao classes are in a different project (JAR) that I reference from the web project. I am using java-based config and referencing it from the applicationContext.xml:

<bean class="bar.foo.config.ServicesConfig" />

因此,这意味着我的Web项目(位于applicationContext.xml所在的位置)中仅存在Controller批注.回顾一下,从我的applicationContext.xml中删除context:component-scan应该不会有任何影响,因为除了@Controller以外,没有其他注释(FIX到有一些@Autowired注释).但是,当我从applicationContext.xml中删除context:component-scan时,它表示控制器(从分派器servlet扫描中找到)找不到我的Service类.对ServicesConfig的引用不够吗?这是用于引用的ServicesConfig类-它具有针对服务的自己的组件扫描,该组件与applicationContext.xml所扫描的包不同.

So, this means there are only Controller annotations in my web project (where applicationContext.xml is located). In retrospect, removing context:component-scan from my applicationContext.xml should not have any affect, since there are no annotations except for @Controller ones (FIX to there are some @Autowired annotations). But, when I remove the context:component-scan from applicationContext.xml, it says that the Controllers (found from dispatcher servlet scan) cannot find my Service classes. Shouldn't the reference to the ServicesConfig be enough? Here is the ServicesConfig class for references - it has its own component scan for the Services, which are a different package from what the applicationContext.xml was scanning.

@Configuration
@ComponentScan({ "some.other.package", "another.package" })
@ImportResource({ "classpath:commonBeans.xml" })
@PropertySource({ "classpath:services.properties",
"classpath:misc.properties" })
public class ServicesConfig {
  // Bean definitions //
}

解决方案:

当我从根上下文中删除context:component-scan时,控制器没有选择自动装配的服务bean.这是因为根上下文引用了我的服务基于Java的配置Bean,但是我没有根上下文设置来扫描组件.因此,当我将组件扫描添加到根上下文(applicationContext.xml)时,一切正常.这是我现在所拥有的:

When I removed context:component-scan from my root context, the Controllers were not picking up the autowired services beans. This was because the root context references my services java-based config Bean, but I did not have the root context setup to scan for Components. Hence, when I add component scanning to the root context (applicationContext.xml) everything works. Here is what I have now:

applicationContext.xml:

applicationContext.xml:

<bean class="bar.foo.config.ServicesConfig" />
<context:component-scan base-package="bar.foo.config" />

dispatcher-servlet.xml:

dispatcher-servlet.xml:

<context:component-scan base-package="bar.foo.controller" />

我已通过Web上下文设置了Controller,Autowired以及Controller软件包中的所有其他注释-我不确定这是否是最佳实践.

I have the web context setup to pickup Controller, Autowired, and any other annotations in the controller package - I'm not sure if this is best practice or not.

推荐答案

您是对的-有两种不同的应用程序上下文,即ContextLoaderListener加载的根应用程序上下文(在ServletContext初始化时),以及Web上下文(由DispatcherServlet加载),根应用程序上下文是Web上下文的父级.

You are right - there are two different application contexts, the root application context loaded up by ContextLoaderListener (at the point the ServletContext gets initialized), and the Web Context (loaded up by DispatcherServlet), the root application context is the parent of the Web context.

现在,由于这是两个不同的应用程序上下文,因此它们的作用方式有所不同-如果您在应用程序上下文中为服务定义component-scan,则将在此处创建服务的所有bean.

Now, since these are two different application contexts, they get acted on differently - if you define component-scan for your services in application context, then all the beans for the services get created here.

当您的Dispatcher servlet加载时,它将开始创建Web上下文,在某个时候(由<mvc:annotation-driven/>驱动,它将为您的uri创建到处理程序方法的映射,它将获取应用程序上下文中的bean列表(这将是Web应用程序上下文,而不是Root应用程序上下文),并且由于您尚未在此处定义component-scan,因此将找不到与控制器相关的bean,也不会创建映射,这就是您必须定义的原因在分派器servlet上下文中也可以进行组件扫描.

When your Dispatcher servlet loads up it will start creating the Web Context, at some point(driven by <mvc:annotation-driven/> it will create a mapping for your uri's to handler methods, it will get the list of beans in the application context(which will be the web application context, not the Root application Context) and since you have not defined a component-scan here the controller related beans will not be found and the mappings will not get created, that is the reason why you have to define a component-scan in the dispatcher servlets context also.

一个好的做法是在根应用程序上下文中排除与Controller相关的bean:

A good practice is to exclude the Controller related beans in the Root Application Context:

<context:component-scan base-package="package">
    <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>

和在Web应用程序上下文中只有控制器相关的人:

and only controller related one's in Web Application Context:

<context:component-scan base-package="package" use-default-filters="false">
    <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation" />
</context:component-scan>

这篇关于applicationContext找不到Servlet上下文的控制器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆