Spring - невозможно создать экземпляр объекта компонента в области запроса

Я пытаюсь создать экземпляр объекта компонента, для которого я объявил запись <bean> в applicationContext.xml. Поток создания экземпляра моего целевого класса компонентов выглядит следующим образом

CalculateController -> CalculateService -> CalculateComponent

Где

CalculatorController — scope = request, аннотированный @Controller и включенный в сканирование компонентов в webapplicationContext.xml

CalculatorService — Scope = singleton, аннотированный @service и включенный в сканирование компонентов в applicationContext.xml

CalculateComponent — область действия = запрос, без аннотации, исключено из сканирования компонентов как в webapplicationConext.xml, так и в applicationContext.xml. Определенная запись bean-компонента в webApplicationContext.xml с областью видимости = request. Также включите <aop:scoped-proxy/> в определение <bean>.

Я включил следующую запись в web.xml

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
            classpath:spring/applicationContext.xml
            /WEB-INF/mvc-dispatcher-servlet.xml
            ....Other resource xmls
    </param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- To retrieve session related information -->
<listener>
    <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>

<listener>
    <listener-class>
            org.springframework.web.context.request.RequestContextListener 
    </listener-class>
</listener> 


<servlet>
    <servlet-name>mvc-dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>mvc-dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

обратите внимание, что CalculateComponent имеет конструктор объекта ref с 3 параметрами, и все три из них имеют запись <bean> в webApplicationContext.xml с одноэлементной областью действия, и они не аннотированы.

Когда запрос отправляется для создания объекта CalculateComponent, контейнер Spring выдает следующую ошибку.

«Запрос, связанный с потоком, не найден: вы ссылаетесь на атрибуты запроса вне фактического веб-запроса или обрабатываете запрос вне исходного потока получения? Если вы фактически работаете в веб-запросе и все еще получаете это сообщение, ваш код вероятно, работает за пределами DispatcherServlet/DispatcherPortlet: в этом случае используйте RequestContextListener или RequestContextFilter, чтобы открыть текущий запрос».

Пожалуйста, порекомендуйте.

Обновление:

Когда я удалил /WEB-INF/mvc-dispatcher-servlet.xml из contextConfigLocation и запустил сервер, я получил ошибку Autowired failed — «Нет подходящего bean-компонента типа CalculateComponent для зависимости:», даже после того, как я изменил область запроса к синглтону.

Затем я прокомментировал автопроводку CalculateComponent в CalculateService, и теперь я вижу, что CalculateComponent инициирован дважды (как упоминалось в моем @Serge Ballesta). Итак, я пришел к выводу, что CalculateService инициируется через ContextLoaderListener (запись bean-компонента в applicationContext.xml) до загрузки DispatcherServlet (т.е. bean-компонент, упомянутый в mvc-dispatcher-servlet, не загружен).

Я снова добавил /WEB-INF/mvc-dispatcher-servlet.xml в contextConfigLocation, но на этот раз в качестве первой записи (т. е. поверх applicationContext.xml). Теперь CalculateComponent снова загружается дважды, и Autowiring выполняется с одноэлементной областью видимости. С помощью этой настройки я изменил область CalculateComponent обратно на запрос, но снова «Я получил ошибку «Нет запроса, привязанного к потоку».

Итак, проблема в том,

ContextLoaderListener пытается инициировать ресурсы DispatcherServlet (CalculateComponent) до его загрузки/доступности.


person gopal    schedule 27.05.2015    source источник


Ответы (2)


Странно иметь контроллер с областью запроса... Насколько я знаю, фреймворк ожидает, что он будет одноэлементным. Попробуйте поместить его в одноэлементную область.

И я думаю, что у вас есть все bean-компоненты из /WEB-INF/mvc-dispatcher-servlet.xml, созданные дважды:

  • сначала в корневом контексте приложения, как это объявлено в глобальном contextConfigLocation
  • следующий в контексте приложения сервлета сервлета с именем mvc-dispatcher

Вы должны либо переименовать файл, чтобы он не был загрузчиком в качестве контекста приложения сервлета, либо удалить его из корневого контекста.

person Serge Ballesta    schedule 28.05.2015
comment
Я удалил значение @scope со всех контроллеров и удалил запись /WEB-INF/mvc-dispatcher-servlet.xml из параметра контекста. Теперь, когда я запускаю сервер, я получаю сообщение об ошибке. Для зависимости не найден подходящий bean-компонент типа CalculateComponent: ожидается по крайней мере 1 bean-компонент, который квалифицируется как кандидат autowire для этой зависимости. Аннотации зависимостей: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=BeanDefNameForCalcualteComponenet - person gopal; 28.05.2015
comment
@Gopal: теперь это более стандартная ошибка ... Поскольку вы используете прокси для подключения bean-компонента с областью запроса в синглтоне, CalculateComponent должен быть подключен как интерфейс, потому что по умолчанию Spring использует JDK прокси. Вы можете принудительно использовать прокси класса javassist (proxy_target_class = true), но никогда не смешивайте оба. - person Serge Ballesta; 28.05.2015
comment
Спасибо за ваши ответы. Добавления ‹aop:scoped-proxy› в bean-компонент с областью запроса недостаточно для проксирования класса. Я также добавил cglib в свой pom.xml. - person gopal; 28.05.2015
comment
@Gopal: да, это эффективно cglib, вы правильно исправили мой комментарий :-) - person Serge Ballesta; 28.05.2015
comment
Если вы видите из моего вопроса, я использую прокси-сервер с областью действия aop для bean-компонентов с областью действия запроса, но я все еще получаю сообщение об ошибке. Пожалуйста, порекомендуйте. - person gopal; 28.05.2015

Отвечая на мой собственный вопрос. Как я уже упоминал в своем вопросе, это мой поток для получения компонента bean-компонента с областью запроса.

CalculateController -> CalculateService -> CalculateComponent.

Но CalculateController был вызван через асинхронный запрос. Мы не можем получить доступ к веб-компонентам из потока асинхронных запросов.

Ссылка: Как включить область запроса в асинхронном исполнителе задач

person gopal    schedule 01.06.2015