在父上下文中声明Spring Bean与子上下文

我有一个spring bean(dao)对象,我通过下面的xml在我的ServletContext中实例化:

<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,我实例化一个自定义身份validation提供程序。 我想使用我的应用程序中使用我的dao也做我的安全上下文中的用户查找,但是当我运行:

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

我得到的错误说,没有这样的bean“userDao”。 这个bean在我的其他上下文中声明的bean中自动assembly,但不在我的安全上下文中。 根据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> 

所以我的问题是,我怎样才能访问我的我的SecurityContext中的我的ServletContext居住的DAO? 有我的道的范围修饰符,或者我可以以某种方式在我的身份validation提供程序在运行时获取ServletContext? 作为参考,这是我想如何在我的身份validation提供程序中使用它:

 public class UserAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { @Override protected UserDetails retrieveUser(String userName, UsernamePasswordAuthenticationToken authenticationToken) throws AuthenticationException { // use dao here 

感谢您向我解释这一点

更新:

继续我的调查,看来DispatcherServlet在哪里使用我的daos是一个子上下文,并且安全上下文在更高的地方。 因此,我的DispatcherServlet中的bean不能被父上下文看到。 我想答案是将我的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创build移到了spring-dao.xml,在我的spring-security.xml中,我现在正在做一个:

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

daos stil对于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-UserDetailsS​​ervice-to-use-User-Service-Dao

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

所以问题是我们需要确保dao存在于ApplicationContext(更高的弹簧容器)中。 为了确保发生这种情况,我将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> 

我认为这将确保启动的第一个上下文加载器将读取我的daoconfiguration(并创build我的dao豆),然后我的安全configuration。 由于dao bean是以这种方式创build的,因此我不再需要security.xml中的前一个“import resource =”spring-dao.xml“”语句。

在这个context-paramconfiguration之后,我创build了ContextLoaderListener。 这是一个比DispatcherServlet更高级别的容器,所以我想先把这个configuration文件读出来,然后创buildbean。 那么,任何子环境都可以访问它们。 这可能不是如何工作,因为DispatcherServlet可能甚至不会读取contextConfigLocation,但即使这样做,我也认为在这一点上,bean已经被声明,父母上下文拥有它们也太糟糕了。

现在,另一个伎俩…为了得到我的DAO,我不能 @Autowired它。 我不得不通过XML手动注入它:

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

当然,我在我的道路上制定了吸气和安装方法,瞧! 我不知道为什么@Autowired不在这里工作。 我认为这是devise。 也许这是SecurityContext特有的(它不会从其他上下文中提取),或者@Autowired通常只能从当前上下文中获取,或者因为我通过XML创build了bean,所以我还必须通过xml设置任何属性不是通过注释? (注释在我的顶级应用程序名称空间中启用和运行)。

无论如何..还是很多我不明白,但重要的一点是它终于工作。

如果你打算使用Spring MVC,你肯定需要理解Spring MVC的ApplicationContext层次结构 。 您还应该了解一些关于servlet容器中的基本组件和生命周期的内容 ,因为您似乎对listener和servlet如何工作也感到困惑。

简要解释你的情况:

  1. 您正在创build两个ApplicationContext:根上下文和DispatcherServlet上下文。 根上下文是由ContextLoaderListener根据contextConfigLocation中指定的文件创build的。 此上下文旨在包含组成应用程序核心逻辑的bean。 DispatcherServlet上下文在servlet启动时创build,并基于名为“webapp-servlet.xml”的文件。 此上下文旨在包含支持与其关联的DispatcherServlet实例的任何Bean,并且只应包含与视图相关的Bean。
  2. DispatcherServlet上下文成为根上下文的子节点。 这允许你的核心bean从根上下文被注入到视图层bean中。 可视性是单向的。 视图层bean不可用于核心bean,这是可取的。 这就是为什么您的DAO无法注入您的身份validation提供程序。 DAO在儿童的情况下。
  3. 基于注释的服务仅适用于声明的上下文中。 如果@Autowired对某个特定的bean不起作用,那是因为在这个bean所在的上下文中没有声明<context:component-scan/><context:annotation-config/>
Interesting Posts