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

查看:31
本文介绍了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 的父级.将 <context:component-scan/> 放在 applicationContext.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>

我还在 dispatcher-servlet.xml 中使用 mvc:annotation-driven,它应该选择控制器(我想?).

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

编辑 2:这是配置文件.我从 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>

编辑 3:好的,这很有趣.我的服务和 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 项目中只有 Controller 注释(applicationContext.xml 所在的位置).回想起来,从我的 applicationContext.xml 中删除 context:component-scan 应该没有任何影响,因为除了 @Controller 之外没有任何注释(修复到有一些 @Autowired 注释).但是,当我从 applicationContext.xml 中删除 context:component-scan 时,它说控制器(从调度程序 servlet 扫描中找到)找不到我的服务类.对 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 和任何其他注释 - 我不确定这是否是最佳实践.

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 Context(由 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 应用程序上下文,而不是根应用程序上下文),并且由于您没有在这里定义 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.

一个好的做法是在根应用程序上下文中排除与控制器相关的 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天全站免登陆