Reputation: 31245
I have read a lot of questions about autowiring on Stackoverflow but I still cannot figure why my autowiring does not work.
I have a standard directory structure :
com.mycompany
|-controller
|-service
|-model
When I inject Services from Controllers, everything works fine. But when I try to give a custom implementation of UserDetailService
to spring security, it fails:
@Service
public class MyCustomUserDetailService implements UserDetailsService {
@Autowired
private UserService userService; //This attribute remains null
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
try {
User userByEmail = userService.findUserByEmail(email); //NullPointerException
return new UserDetailsAdapter(userByEmail);
} catch(NoResultException e) {
return null;
}
}
}
UserService
is a very simple Service, anotated with @Service
:
import org.springframework.stereotype.Service;
@Service
public class UserService {
[...]
}
Note : UserService is correctly autowired when instantiated from UserController :
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService service; //This one works!
Here is the dispatcher-servlet.xml (see the component-scan) :
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:component-scan base-package="com.mycompany"/>
<tx:annotation-driven/>
<mvc:annotation-driven/>
</beans>
And here is the relevant part of the Spring context :
<beans:bean id="customUserDetailService" class="com.mycompany.service.customUserDetailService"/>
<authentication-manager>
<authentication-provider user-service-ref="customUserDetailService">
</authentication-provider>
</authentication-manager>
Any idea?
Upvotes: 1
Views: 1259
Reputation: 10669
I'm pretty sure that your problem is related to the fact that the your bean is managed by the DispatcherServlet
context instead of the root context. By putting the <context:component-scan base-package="com.mycompany"/>
in the DispatcherServlet
context, all the beans scanned on these packages would be managed by the DispatcherServlet
context and are not visible by the root context which is the one that manage your MyCustomUserDetailService
bean.
The DispatcherServlet
is a child of the root context and that allows your core beans from the root context to be injected into the view-layer beans like controllers. The visibility is only one way, you can't inject beans from the DispatcherServlet
context into a bean manage by the root context, that's why it works in the UserController
but not in the MyCustomUserDetailService
.
Moving the <context:component-scan base-package="com.mycompany"/>
tag to the root context (Spring context) should do the trick.
Upvotes: 3