我已经创建了一个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.MyUserDetailsService.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"/>
但它不起作用!!!!
答案 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上下文加载器加载的任何内容),但不能反过来。