在Spring 4中区分应用程序上下文

时间:2015-05-10 23:12:37

标签: spring spring-mvc spring-security spring-data-jpa

我的应用程序中有一个登录服务,实现了UserDetailsS​​ervice:

@Service
@Transactional
public class LoginService implements UserDetailsService {

 @Autowired
 UserService userService;

  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

    Assert.notNull(username);

    UserDetails result = userService.loadUserDetailsByUsername(username);
    Assert.notNull(result);

    // WARNING: The following sentences prevent lazy initialisation problems!
    Assert.notNull(result.getAuthorities());
    result.getAuthorities().size();

    return result;

  }
}

应用程序因上下文初始化中遇到错误异常而死亡。跟踪的开始是:

Error creating bean with name 'org.springframework.security.filterChains': Cannot resolve reference to bean 'org.springframework.security.web.DefaultSecurityFilterChain#0' while setting bean property 'sourceList' with key [0] ...

结局是:

Cannot resolve reference to bean 'loginService' while setting bean property 'userDetailsService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'loginService' is defined

因此无法找到 loginService

我的 web.xml 是:

<?xml version="1.0" encoding="UTF-8"?>
<web-app
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">

<display-name>SimpleSpringProject</display-name>
<description>All you need!</description>

<!-- Loads Spring Security config file -->
<!--
    contextConfigLocation is the context parameter where we provide the spring security beans configuration file name.
    It is used by ContextLoaderListener to configure authentication in our application
-->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/spring-*.xml</param-value>     
</context-param>



<!-- Spring Security -->
<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>


<!-- Creates the Spring Container shared by all Servlet and Filters -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>



<!-- Handles Spring requests -->        
<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/webmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

在contextConfigLocation中,我正在加载3个文件: spring-security.xml spring-datasource.xml spring-jpa.xml

弹簧security.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/security
        http://www.springframework.org/schema/security/spring-security.xsd">

  <security:http auto-config="true" use-expressions="true">

    <security:intercept-url pattern="/user/**" access="hasRole('ROLE_ADMIN')" />
    <security:intercept-url pattern="/role/**" access="hasRole('ROLE_ADMIN')" />

    <security:form-login 
        login-processing-url="/login"
        login-page="/loginForm" 
        default-target-url="/" 
        authentication-failure-url="/loginForm?error" 
        username-parameter="username"
        password-parameter="password" />

    <security:logout logout-url="/logout" logout-success-url="/" delete-cookies="JSESSIONID" />
    <security:csrf />

  </security:http>

  <security:authentication-manager>
    <security:authentication-provider user-service-ref="loginService"></security:authentication-provider>
  </security:authentication-manager>
</beans>

弹簧jpa.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/data/jpa
        http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

  <jpa:repositories base-package="com.ssp" />

</beans>

弹簧datasource.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">

<!-- Enable @Transactional annotation -->
<tx:annotation-driven transaction-manager="transactionManager"/>

<!-- MySQL Datasource with Commons DBCP connection pooling -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/simplesp" />
    <property name="username" value="root" />
    <property name="password" value="betis000" />
    <property name="testOnBorrow" value="true"/>
    <property name="testOnReturn" value="true"/>
    <property name="testWhileIdle" value="true"/>
    <property name="timeBetweenEvictionRunsMillis" value="1800000"/>
    <property name="numTestsPerEvictionRun" value="3"/>
    <property name="minEvictableIdleTimeMillis" value="1800000"/>
    <property name="validationQuery" value="SELECT 1"/>
</bean>

<!-- EntityManagerFactory -->
<bean
    id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

    <property name="persistenceUnitName" value="persistenceUnit" />
    <property name="dataSource" ref="dataSource" />
</bean>

<!-- Transaction Manager -->
<bean
    id="transactionManager"
    class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

</beans>

在DispatcherServlet中我正在加载 webmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

<!-- Enable annotation-based Spring MVC controllers (eg: @Controller annotation) -->
<mvc:annotation-driven />

<!-- Classpath scanning of @Component, @Service, etc annotated class -->
<context:component-scan base-package="com.ssp" />

<!-- Handles HTTP GET requests for /resources/** by efficiently serving 
    up static resources in the ${webappRoot}/resources directory -->
<mvc:resources mapping="/resources/**" location="/WEB-INF/resources/" />

<!-- Register "global" interceptor beans to apply to all registered HandlerMappings -->
<mvc:interceptors>
    <!-- Set the language in variable lang -->
    <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
        p:paramName="lang" />
</mvc:interceptors>

<!-- Resolve view name into jsp file located on /WEB-INF -->
<bean
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/" />
    <property name="suffix" value=".jsp" />
</bean>


<!-- Tiles -->
<bean id="tilesViewResolver"
    class="org.springframework.web.servlet.view.UrlBasedViewResolver">
    <property name="viewClass"
        value="org.springframework.web.servlet.view.tiles3.TilesView" />
</bean>
<bean id="tilesConfigurer"
    class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
    <property name="definitions">
        <list>
            <value>/WEB-INF/tiles/tiles-definitions.xml</value>
        </list>
    </property>
</bean>



<!-- Resolves localized messages*.properties and application.properties 
    files in the application to allow for internationalization. The messages*.properties 
    files translate messages which are part of the admin interface, the application.properties 
    resource bundle localizes all application specific messages such as entity 
    names and menu items. -->
<bean id="messageSource"
    class="org.springframework.context.support.ResourceBundleMessageSource"
    p:basenames="i18n/messages,i18n/application" />

<!-- Store preferred language configuration in a cookie -->
<bean id="localeResolver"
    class="org.springframework.web.servlet.i18n.CookieLocaleResolver"
    p:cookieName="locale" p:defaultLocale="en" />
</beans>

我想我的applicationContext有问题,因为如果删除 @Service 注释并在 spring-security.xml中定义bean LoginService

<bean id="loginService" class="com.ssp.service.LoginService" />

然后应用程序启动,当我提交登录时,其UserService为null,因此看起来LoginService的上下文与bean的上下文不同:

<context:component-scan base-package="com.ssp" />

如果有人想看到该应用的完整代码位于https://github.com/pedrogonzalezgutierrez/simplespringproject

2 个答案:

答案 0 :(得分:0)

我认为你需要使用userDetailsS​​erviceWrapper包装你的loginService,试试这个:

<bean id="loginService" class="path.to.LoginService" />
<bean id="preAuthenticationProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
    <property name="preAuthenticatedUserDetailsService">
        <bean id="userDetailsServiceWrapper" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
            <property name="userDetailsService" ref="loginService" />
        </bean>
    </property>
</bean>

<authentication-manager alias="authenticationManager">
    <authentication-provider ref="preAuthenticationProvider" />
</authentication-manager>

答案 1 :(得分:0)

经过越来越多的研究,我确信这是应用程序上下文的问题。似乎我的应用程序中有两个不同的上下文。其中一个由 contextConfigLocation 加载,另一个由 DispatcherServlet 加载。

只需将 DispatcherServlet 参数值保留为空,然后按 contextConfigLocation 加载所有配置。

我还将bean定义更新到版本3.2,除了需要4.0的Spring Security