自动装配和弹簧注射的问题

时间:2014-05-29 23:55:48

标签: java spring-mvc autowired code-injection

  

解决

最近我遇到了一个我正在尝试开发的Spring MVC应用程序的问题。 主要问题是我不知道为什么@Autowired注释不能正常工作,这可能是因为我有问题。我将在这里发布我的代码,以便您可以帮助我处理我的问题!非常感谢你们:

的web.xml

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

    <display-name>HelloWorld Application</display-name>
    <description>
        This is a simple web application with a source code organization
        based on the recommendations of the Application Developer's Guide.
    </description>

    <servlet>
        <servlet-name>webDispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>webDispatcher</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
    <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>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/applicationContext.xml
        </param-value>
    </context-param>

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

的applicationContext.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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <context:annotation-config />
    <context:spring-configured />
    <context:component-scan base-package="com.agrichem.server" />

    <bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="classpath:messages" />
        <property name="defaultEncoding" value="UTF-8" />
    </bean>
    <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
        p:location="WEB-INF/jdbc.properties" />

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
        p:url="${jdbc.databaseurl}" p:username="${jdbc.username}" p:password="${jdbc.password}" />

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation">
            <value>classpath:hibernate.cfg.xml</value>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${jdbc.dialect}</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
    </bean>

    <tx:annotation-driven />
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <bean id="securityDao"
        class="com.agrichem.server.model.repositories.impl.SecurityDaoImpl">
    </bean>
</beans>

webDispatcher-servlet.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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <context:annotation-config />
    <context:spring-configured />
    <context:component-scan base-package="com.agrichem.server" />

    <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

<!--    <import resource="spring-security-web.xml"/> -->

</beans>

SecurityDao.java

public interface SecurityDao {

    public boolean validateUser(User user);

    public User authenticateUser(User user);

    public User getUser (User user);

}

SecurityDaoImpl.java

@Repository("securityDao")
public class SecurityDaoImpl extends HibernateDao implements SecurityDao {

    public SecurityDaoImpl() {
        super();
    }

    @Override
    public boolean validateUser(User user) {
        Query query = openSession()
                .createQuery(
                        "from User u where u.login = :login and u.password = :password");

        query.setParameter("login", user.getLogin());
        query.setParameter("password", user.getPassword());

        return (query.list().size() > 0) ? true : false;
    }

    @Override
    public User authenticateUser(User user) {
        Query query = openSession()
                .createQuery(
                        "from User u where u.login = :login and u.password = :password");

        query.setParameter("login", user.getLogin());
        query.setParameter("password", user.getPassword());

        return (User) query.uniqueResult();
    }

    @Override
    public User getUser(User user) {
        Query query = openSession().createQuery(
                "from User u where u.login = :login");

        query.setParameter("login", user.getLogin());

        return (User) query.uniqueResult();
    }

}

WebSecurityConfig.java

@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth)
            throws Exception {

        auth.userDetailsService(new CustomUserDetailsService());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests().antMatchers("/home/logout.do").permitAll()
                .anyRequest().authenticated().and().formLogin()
                .loginPage("/home/login.do").permitAll()
                .failureUrl("/home/accessdenied.do").permitAll();

    }
}

CustomUserDetailsS​​ervice.java

@Configurable
@Transactional
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    @Qualifier("securityDao")
    private SecurityDao securityDAO;

    @Override
    public UserDetails loadUserByUsername(String arg0)
            throws UsernameNotFoundException {

        com.agrichem.server.model.security.User user = securityDAO
                .getUser(new com.agrichem.server.model.security.User(arg0, ""));

        User userDetails = new User(user.getLogin(), user.getPassword(),
                getGrantedAuthorities(user.getRoles()));

        return userDetails;

    }

    public static List<GrantedAuthority> getGrantedAuthorities(Set<Role> roles) {
        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

        for (Role role : roles) {
            authorities.add(new SimpleGrantedAuthority(role.getName()));
        }
        return authorities;
    }

    public SecurityDao getSecurityDAO() {
        return securityDAO;
    }

    public void setSecurityDAO(SecurityDao securityDAO) {
        this.securityDAO = securityDAO;
    }

}

在这一点上,当我尝试登录应用程序并且我要检查Dao访问数据库时,我得到'securityDao'属性为null。确切地位于以下行中的CustomUserDetailsS​​ervice中:com.agrichem.server.model.security.User user = securityDAO.getUser(new com.agrichem.server.model.security.User(arg0,“”));并且很明显我得到了一个N​​ullPointerException。

org.springframework.security.authentication.InternalAuthenticationServiceException
    at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:110)
    at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:132)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:177)
    at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:211)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NullPointerException
    at com.agrichem.server.services.security.CustomUserDetailsService.loadUserByUsername(CustomUserDetailsService.java:35)
    at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:102)
    ... 36 more

解决方案:

发现它!问题是在WebSecurityConfig中我做了以下事情:

@Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth)
            throws Exception {

        auth.userDetailsService(**new CustomUserDetailsService()**);
    }

然后CustemUserDetailsS​​ervice的新实例不在Spring Control中。

为了解决这个问题,我在CustomUserDetailsS​​ervice中添加了一个构造函数:

private SecurityDao securityDAO;

    public CustomUserDetailsService(SecurityDao securityDAO) {
        super();
        this.securityDAO = securityDAO;
    }

我以这种方式修改了WebSecurityConfig:

@Autowired
    private SecurityDao securityDao;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.userDetailsService(new CustomUserDetailsService(securityDao));
    }

非常感谢您的帮助!

1 个答案:

答案 0 :(得分:5)

尽管你已经解决了这个问题,但在Spring Dependency Injection和Inversion of Control理论方面,这个解决方案很难实现。

基本上,如果使用Spring,则不应使用new关键字来实例化对象。因为必须实例化所有对象并仅由Spring容器注入。

<强>的applicationContext.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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <context:annotation-config />
    <context:spring-configured />
    <context:component-scan base-package="com.agrichem.server" />

    <bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="classpath:messages" />
        <property name="defaultEncoding" value="UTF-8" />
    </bean>
    <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
        p:location="WEB-INF/jdbc.properties" />

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
        p:url="${jdbc.databaseurl}" p:username="${jdbc.username}" p:password="${jdbc.password}" />

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation">
            <value>classpath:hibernate.cfg.xml</value>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${jdbc.dialect}</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
    </bean>

    <tx:annotation-driven />
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <bean id="securityDao"
        class="com.agrichem.server.model.repositories.impl.SecurityDaoImpl">
    </bean>

    <bean id="customerService"
        class="com.agrichem.server.path.to.service.CustomUserDetailsService">
    </bean>
</beans>

<强> WebSecurityConfig.java

@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService customUserDetailsService

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth)
            throws Exception {

        auth.userDetailsService(customUserDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests().antMatchers("/home/logout.do").permitAll()
                .anyRequest().authenticated().and().formLogin()
                .loginPage("/home/login.do").permitAll()
                .failureUrl("/home/accessdenied.do").permitAll();

    }
}

你应该有CustomUserDetailsService的默认构造函数,它不会接受任何参数。所有@Autowired属性都应该由弹簧容器注入。

此外,您正在混合Spring Java Configuration和Spring XML Configuration,这很好,但如果您决定使用一种特定方法来定义bean,则会更好。