我的Spring应用程序有一个问题,该应用程序启动时会两次创建我的@Service类。我知道这是我的配置存在的问题,就像我以前经历过的那样,但是我到底在做什么错呢?
我在下面布置配置的方式有什么根本错误吗?(我忽略了我认为无关的所有内容)
web.xml:
<servlet> <servlet-name>myapp</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>myapp</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/myapp-config.xml /WEB-INF/myapp-security.xml /WEB-INF/myapp-mvc.xml </param-value> </context-param> <listener> <listener-class>com.myapp.servlet.MyAppContextListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
myapp-servlet.xml
<context:component-scan base-package="com.myapp" annotation-config="true" /> <mvc:annotation-driven />
myapp-config.xml
<context:component-scan base-package="com.myapp" annotation-config="true" /> <context:annotation-config />
除了@GaryF的答案外,还有以下针对该问题的漂亮解决方案(用于产生的项目中Spring Roo):
Spring Roo
<!-- Load everything except @Controllers --> <context:component-scan base-package="com.myapp"> <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/> </context:component-scan>
<!-- Load @Controllers only --> <context:component-scan base-package="com.myapp" use-default-filters="false"> <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/> </context:component-scan>
编辑:
<context:component-scan>从中删除myapp-config.xml意味着,所有自动发现的带注释的Bean都在DispatcherServlet的上下文(即从中加载的上下文myapp-servlet.xml)中注册。
<context:component-scan>
但是,推荐的方法是将servlet的上下文用于特定于表示的内容(例如控制器),并将根上下文(myapp-config.xml)用于应用程序的核心服务。上面的解决方案使此方法变得容易。
关于实际考虑,当你将核心服务放在servlet的应用程序上下文中时,不能从该servlet的范围之外访问它们,例如,从另一个servlet进行访问(你可能需要使用另一个servlet来实现另一种访问技术)或过滤器(例如Spring Security过滤器)。这就是在根应用程序上下文中拥有核心服务的原因。