依赖注入使用spring注释驱动的组件自动装配Null

时间:2015-02-25 06:29:33

标签: spring spring-mvc dependency-injection spring-security spring-annotations

我已经创建了一个spring-mvc应用程序。配置如下所示:

dispatcher-servlet.xml

<beans ... >
   <mvc:annotation-driven />
   <context:annotation-config />
   <aop:aspectj-autoproxy/>

   <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>

   <context:component-scan base-package="my.server.controller" />
   <context:component-scan base-package="my.server.dao" />
   <context:component-scan base-package="my.server.service" />
 ......
</beans>

的applicationContext.xml

<beans ...>
   ...
   <bean id="myUserDetailsService" class="my.server.service.MyUserDetailsService" autowire="byType"/>
</beans>

security.xml文件

<beans:beans ...>
   <http pattern="/css/**" security="none"/>
   <http pattern="/login.jsp*" security="none"/>
   <http auto-config='true'>
       <http-basic />
       <logout />
       <intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
       <intercept-url pattern="/**" access="ROLE_USER" />
   </http>

   <authentication-manager>
      <authentication-provider user-service-ref="myUserDetailsService" >
         <password-encoder hash="bcrypt" />    
      </authentication-provider>
   </authentication-manager>

</beans:beans>

security.xml applicationContext.xml web.xml中的以下行加载:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml, /WEB-INF/security.xml</param-value>
</context-param>

my.server.dao.UserDao.java

@Component
public interface UserDao {
   JUser findByUserName(String username);
}

my.server.dao.UserDaoMemory.java

@Component("userDao")
public class UserDaoMemory implements UserDao {

   private static List<JUser> myUsers = new ArrayList<>();

   static {
       myUsers.add(new JUser("ali", "123","ROLE_USER"));
   }

   @SuppressWarnings("unchecked")
   @Override
   public JUser findByUserName(String username) {

       List<JUser> users = new ArrayList<>();
       users = myUsers;

       if (users.size() > 0) {
           return users.get(0);
       } else {
           return null;
       }

   }

}

my.server.service.MyUserDetailsS​​ervice.java

@Service
public class MyUserDetailsService implements UserDetailsService {

   @Autowired
   private UserDao userDao;

   @Override
   public UserDetails loadUserByUsername(final String throws UsernameNotFoundException {

       System.out.println("MyUserDetailsService#loadUserByUsername,   userDao:"+userDao);
       JUser user = userDao.findByUserName(username);
       List<GrantedAuthority> authorities = buildUserAuthority(user.getUserRoles());

       return buildUserForAuthentication(user, authorities);

   }

   // Converts my.server.entity.JUser user to
   // org.springframework.security.core.userdetails.User
   private User buildUserForAuthentication(JUser user,
        List<GrantedAuthority> authorities) {
    return new User(user.getUsername(),
            user.getPassword(), user.isEnabled(),
            true, true, true, authorities);
   }

   private List<GrantedAuthority> buildUserAuthority(Set<JRole> userRoles) {

       Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();

       // Build user's authorities
       for (JRole userRole : userRoles) {
           setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
       }

       List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);

       return Result;
   }

   public UserDao getUserDao() {
       return userDao;
   }



}

我的问题出在MyUserDetailsServie,其中loadUserByUsername(..)被调用; userDao尚未自动装配,且为null

MyUserDetailsService#loadUserByUsername,   userDao:null

一个可能的解决方案是更改applicationContext.xml,例如(autowire="byName"):

<bean id="myUserDetailsService" class="my.server.service.MyUserDetailsService" autowire="byName"/>    

但它不起作用!!!!

1 个答案:

答案 0 :(得分:1)

您的上下文设置方式存在一些冲突。

applicationContext.xml(父上下文)通常用于定义您已正确完成的所有共享组件(例如存储库,安全性,服务,处理程序......)。

您的servlet上下文(例如,dispatcher-servlet.xml)是子上下文,并且可以查看父上下文中定义的所有内容。因此,您应该将组件的范围限制为servlet上下文的控制器,这意味着您应该只扫描您的控制器,但是您正在扫描所有内容。

<context:component-scan base-package="my.server.controller" />
<context:component-scan base-package="my.server.dao" />
<context:component-scan base-package="my.server.service" />

它应该只是

<context:component-scan base-package="my.server.controller" />

您可以将所有这些移动到您的applicationContext

<mvc:annotation-driven />
<context:annotation-config />
<aop:aspectj-autoproxy/> 

除非你专门为这个servlet上下文使用它们。

无论如何,回到问题,因为子上下文正在扫描服务/ dao类,它会找到这些,但它们没有正确配置。

  

所以我在哪里扫描my.server.dao

将它们放入applicationContext.xml中,将来随着应用程序复杂性的增加而变成类似于repositoryContext的东西。

从技术上讲,如果您愿意,可以将所有内容转储到servlet上下文中,但除了servlet上下文之外,每次定义“根”上下文时,都会产生作用域问题。子上下文中的所有内容(例如servlet上下文)都可以看到父上下文中的组件(例如,由web.xml上下文加载器加载的任何内容),但不能反过来。