Объявление Spring Bean в Родительском контексте против дочернего контекста

у меня есть объект spring bean (dao), который я создаю в своем ServletContext через следующий xml:

<bean id="userDao" class="com.company.dao.impl.UserDaoImpl">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

этот компонент объявлен внутри моего webapp-сервлета.xml-файл и используется моим приложением в ServletContext.

Я также использую SpringSecurity. Насколько я понимаю, это работает в другом контексте (SecurityContext).

мое приложение имеет webapp-security.xml, где я создаю экземпляр пользовательского поставщика проверки подлинности. Я бы как использовать мой dao, который используется в моем приложении, чтобы также выполнить поиск пользователя в контексте безопасности, но когда я запускаю:

<bean id="userAuthenticationProvider" class="com.company.security.UserAuthenticationProvider">
    <property name="userDao" ref="userDao" />
</bean>

Я получаю ошибки, говоря, что нет такого Боба "userDao". Фасоль автоматически настраивается в фасолях, объявленных в моем другом контексте, но не в моем контексте безопасности. Согласно весенним документам, я считаю, что в интернете необходимы оба отдельных контекста.в XML

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

<listener>
    <listener-class>
        org.springframework.security.web.session.HttpSessionEventPublisher
    </listener-class>
</listener>

Итак, мой вопрос: как я могу получить доступ к моему DAO, который живет в моем ServletContext внутри мой SecurityContext? Есть ли модификатор области для моего dao, или я могу каким-то образом получить ServletContext во время выполнения в моем поставщике аутентификации? Для справки, вот как я хочу использовать его внутри моего поставщика аутентификации:

public class UserAuthenticationProvider extends
    AbstractUserDetailsAuthenticationProvider {

    @Override
protected UserDetails retrieveUser(String userName,
        UsernamePasswordAuthenticationToken authenticationToken)
        throws AuthenticationException {

    // use dao here

спасибо, что объяснил мне это

обновление:

продолжая мое расследование, кажется, что DispatcherServlet, где я использую свой daos, является дочерним контекстом, и контекст безопасности где-то высоко. Следовательно, бобы в моем DispatcherServlet не могут быть замечены родительскими контекстами. Я думаю, что ответ-переместить мои объявления bean в контекст родительского приложения, но я не уверен, как это сделать. Вот моя паутина.в XML

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>WEB-INF/spring-*.xml
    </param-value>
</context-param>

<listener>
    <listener-class>
        org.springframework.security.web.session.HttpSessionEventPublisher
    </listener-class>
</listener>

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

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy
    </filter-class>
</filter>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<servlet>
    <servlet-name>myapp</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
    <init-param>
        <param-name>listings</param-name>
        <param-value>true</param-value>
    </init-param>
</servlet>

    ...

я переместил все свое творение dao в spring-dao.xml, а у меня весной-безопасность.xml теперь я делаю:

<import resource="spring-dao.xml" />

daos все еще остается видимым для контекста DispatcherServlet и невидимым для моего SecurityContext хотя.

ответ:

хорошо, я понял. Вот некоторые полезные ссылки:

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#context-create

http://forum.springsource.org/showthread.php?115774-Spring-Security-Custom-UserDetailsService-to-use-User-Service-Dao

http://static.springsource.org/spring-security/site/faq.html#faq-method-security-in-web-context

Итак, проблема заключалась в том, что нам нужно было убедиться, что dao существует в ApplicationContext (более высоком контейнере spring). Чтобы убедиться, что это произошло, я изменил свою сеть.XML должен быть:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>WEB-INF/spring-dao.xml WEB-INF/spring-security.xml
    </param-value>
</context-param>

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

<listener>
    <listener-class>
        org.springframework.security.web.session.HttpSessionEventPublisher
    </listener-class>
</listener>

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy
    </filter-class>
</filter>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<servlet>
    <servlet-name>webapp</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
    <init-param>
        <param-name>listings</param-name>
        <param-value>true</param-value>
    </init-param>
</servlet>

Я думал, что это гарантирует, что первый загрузчик контекста, который запускается, прочитает мою конфигурацию dao (и создаст мои бобы dao), а затем мою конфигурацию безопасности. Поскольку бобы dao создаются таким образом, я удалил предыдущий "import resource="spring-dao.XML "" оператор в безопасности.xml, потому что он больше не будет нужен.

право после этой конфигурации contextloaderlistener я создал ContextLoaderListener. Это контейнер spring более высокого уровня, чем DispatcherServlet, поэтому я решил, что это первый парень, который прочитает эти файлы конфигурации, и он затем создаст бобы. Тогда любой дочерний контекст будет иметь к ним доступ. Это может быть не так, как это работает, поскольку DispatcherServlet может даже не читать contextConfigLocation, но даже если это так, я понял, что на данный момент бобы будут уже объявлено, так что слишком плохо, Родительский контекст владеет ими.

теперь, для другого трюка... чтобы получить мой DAO, я мог бы не @Autowired это. Мне пришлось вручную ввести его через XML:

    <bean id="userAuthenticationProvider" class="com.company.app.security.UserAuthenticationProvider">
    <property name="userDao" ref="userDao" />
</bean>

конечно, я сделал методы геттера и сеттера на моем dao, и вуаля! Я не знаю, почему @Autowired здесь не работает. Я предполагаю, что это преднамеренно. Возможно, это относится к SecurityContext (он не будет тянуть из других контекстов), или, возможно, @Autowired в общем только тянет из текущего контекста, или, может быть, потому, что я создал bean через XML, я должен также установить любые свойства через xml, а не через аннотации? (аннотации включены и работают в моем пространстве имен приложений верхнего уровня).

в любом случае.. все еще многого не понимаю, но важно то, что это наконец-то работает.

1 ответов


Если вы собираетесь использовать Spring MVC, вам определенно нужно понять иерархию ApplicationContext Spring MVC. Вы также должны узнать что-то о основные компоненты и жизненные циклы в контейнере сервлетов, поскольку вы, похоже, смущены тем, как работают слушатели и сервлеты.

чтобы кратко объяснить вашу ситуацию:

  1. вы создаете два ApplicationContexts: корневой контекст и контекст DispatcherServlet. Корневой контекст создается ContextLoaderListener на основе файлов, названных в contextConfigLocation. Этот контекст предназначен для содержания компонентов, составляющих основную логику вашего приложения. Контекст DispatcherServlet создается при запуске этого сервлета и основан на файле с именем "webapp-servlet.XML." Этот контекст должен содержать все компоненты, поддерживающие экземпляр DispatcherServlet, с которым он связан и должен иметь только связанные с представлением компоненты он.
  2. контекст DispatcherServlet становится дочерним для корневого контекста. Это позволяет вводить основные бобы из корневого контекста в бобы слоя представления. Видимость односторонняя. Бобы слоя представления недоступны для основных бобов, что желательно. Вот почему ваш DAO не может быть введен в ваш поставщик проверки подлинности. Дао было в контексте ребенка.
  3. службы на основе аннотаций применяются только в контексте, в котором они объявлены. Если @Autowired не работает для конкретного компонента, это потому, что вы не объявили <context:component-scan/> или <context:annotation-config/> в контексте, где этот боб существует.