@Service построены дважды
У меня проблема с моим приложением 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 />
Ответы
Ответ 1
В дополнение к @GaryF answer для этой проблемы существует следующее красивое решение (используется в проектах, сгенерированных Spring Roo
):
MyApp-config.xml
<!-- Load everything except @Controllers -->
<context:component-scan base-package="com.myapp">
<context:exclude-filter expression="org.springframework.stereotype.Controller"
type="annotation"/>
</context:component-scan>
MyApp-servlet.xml
<!-- 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>
EDIT:
Удаление <context:component-scan>
из myapp-config.xml
означает, что все ваши автообнаруженные аннотированные beans зарегистрированы в контексте DispatcherServlet
(то есть, контекст загружен из myapp-servlet.xml
).
Однако рекомендуемый подход заключается в использовании контекста сервлета для специфичных для представления вещей (таких как контроллеры) и использования корневого контекста (myapp-config.xml
) для основных служб вашего приложения. Решение выше упрощает этот подход.
Что касается практических соображений, когда ваши основные службы размещены в контексте сервлет-приложений, к ним нельзя получить доступ из-за пределов этого сервлета, например, из других сервлетов (вам может потребоваться использовать другие сервлеты для реализации другого технологии доступа) или фильтры (например, фильтры Spring Security
). Это причина наличия основных сервисов в контексте корневого приложения.
Ответ 2
В качестве дополнения к ответу @axtavt, Id хотел бы предоставить соответствующий Spring JavaConfig здесь.
В RootConfig.java
:
@ComponentScan(basePackages = { "com.myapp" },
excludeFilters = @Filter({Controller.class, Configuration.class}))
В WebMvcConfig.java
:
@ComponentScan(basePackages = { "com.myapp" },
useDefaultFilters = false, includeFilters = @Filter(Controller.class))
Ответ 3
Вы выполняете два отдельных компонентных сканирования по одному базовому пакету. Удалите один из них.