У меня есть объект spring bean (dao), который я создаю в своем ServletContext с помощью следующего xml:
<bean id="userDao" class="com.company.dao.impl.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
Этот bean объявлен внутри моего файла webapp-servlet.xml и используется моим приложением в ServletContext.
Я также использую SpringSecurity. Я понимаю, что это работает в другом контексте (SecurityContext).
В моем приложении есть webapp-security.xml, где я создаю собственный поставщик проверки подлинности. Я хотел бы использовать мое dao, которое используется в моем приложении, чтобы также выполнять поиск пользователя в моем контексте безопасности, но когда я запускаю:
<bean id="userAuthenticationProvider" class="com.company.security.UserAuthenticationProvider">
<property name="userDao" ref="userDao" />
</bean>
Я получаю ошибки, говоря, что нет такого bean "userDao". bean является автообновленным в beans, объявленным в моем другом контексте, но не внутри моего контекста безопасности. В соответствии с документами spring, я считаю, что в web.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
спасибо, что объяснили это мне
UPDATE:
Продолжая мое исследование, кажется, что DispatcherServlet, где я использую мои daos, представляет собой дочерний контекст, а контекст безопасности - где-то выше. Следовательно, beans в моем DispatcherServlet не может быть замечен родительскими контекстами. Я думаю, что ответ заключается в том, чтобы каким-то образом переносить объявления bean в контексте родительского приложения, но я не уверен, как это сделать. Вот мой web.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, а в моем spring -security.xml теперь я делаю:
<import resource="spring-dao.xml" />
Даос-прежнему остается видимым в контексте DispatcherServlet и невидимым для моего SecurityContext.
ОТВЕТИЛ:
Хорошо, я понял это. Вот несколько полезных ссылок:
http://static.springsource.org/spring-security/site/faq.html#faq-method-security-in-web-context
Итак, проблема заключалась в том, что мы должны убедиться, что dao существует в ApplicationContext (выше spring). Чтобы это произошло, я изменил свой web.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 beans), а затем мою конфигурацию безопасности. Поскольку dao beans создается таким образом, я удалил предыдущий оператор import import = "spring -dao.xml" в файле security.xml, потому что он больше не понадобится.
Сразу после этой конфигурации context-param я создал ContextLoaderListener. Это контейнер более высокого уровня spring, чем DispatcherServlet, поэтому я решил, что первым первым будет читать эти файлы конфигурации, и тогда он создаст beans. Затем любой дочерний контекст будет иметь к ним доступ. Возможно, это не так, как это работает, поскольку DispatcherServlet может даже не читать contextConfigLocation, но даже если это так, я понял, что на данный момент beans уже будет объявлен, что слишком плохо, родительский контекст им владеет.
Теперь, для другого трюка... чтобы получить мой DAO, я не мог @Autowired его. Мне пришлось вручную вводить его через XML:
<bean id="userAuthenticationProvider" class="com.company.app.security.UserAuthenticationProvider">
<property name="userDao" ref="userDao" />
</bean>
Конечно, я использовал методы getter и setter на моем dao и voila! Я не знаю, почему @Autowired не работает здесь. Я предполагаю это по дизайну. Возможно, это особенно относится к SecurityContext (он не будет тянуть из других контекстов), или, возможно, @Autowired вообще вытягивает только из текущего контекста, или, может быть, потому, что я создал bean через XML, я также должен установить любые свойства через xml, а не через аннотации? (аннотации включены и работают в моем пространстве имен приложений верхнего уровня).
В любом случае.. все еще много не понимаю, но важно то, что он наконец работает.