spring bean 的注册顺序及依赖注入问题

sunkaigoon 2017-03-29 12:42:55
各位好!
我用java spring mvc 做一个app的后台项目,遇到了一个问题。
我权限管理用的是shiro框架,自定义了一个realm,realm里面采用@Autowired注入了一个名为loginService的bean,同时realm注册到spring。LoginServiceImpl类实现了LoginService接口,并用@Service注解扫描注入LoginServiceImpl,名为loginService。当我启动项目时报错,提示注册realm失败,因为loginService这个bean不存在。

项目配置:
1、web.xml

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext_*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<servlet>
<servlet-name>cloudServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>cloudServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>


2、applicationContext_shiro.xml

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="cacheManager" ref="cacheManager"/>
<property name="sessionMode" value="native"/>
<property name="realm" ref="hfrealm"/>
<property name="sessionManager" ref="hfsessionManager"/>
</bean>
<bean id="hf_session_listener" class="com.hf.hfmo.shiro.hf_session_listener"></bean>
<bean id="hfsessionManager" class="com.hf.hfmo.shiro.SessionManager">
<property name="globalSessionTimeout" value="86400000" />
<property name="sessionListeners" ref="hf_session_listener">
</property>
<property name="sessionValidationInterval" value="3600000"></property>
</bean>
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> </bean>
<bean id="hfrealm" class="com.hf.hfmo.shiro.OrientDbRealm">
<property name="name" value="OrientDbRealm"/>
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.AllowAllCredentialsMatcher">
</bean>
</property>
</bean>
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor"/>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
<bean id="secureRemoteInvocationExecutor" class="org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor">
<property name="securityManager" ref="securityManager"/>
</bean>

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/consumer/login"/>
<property name="successUrl" value="/s/index"/>
<property name="unauthorizedUrl" value="/s/unauthorized"/>
<property name="filterChainDefinitions">
<value>
/favicon.ico = anon
/logo.png = anon
/index.html = anon
/shiro.css = anon
/consumer/login = anon
/consumer/regist = anon
/messages/** = authc
/information/** = anon
# allow WebStart to pull the jars for the swing app:
/*.jar = anon
# everything else requires authentication:
/** = authc
</value>
</property>
</bean>
</beans>

3、realm
@Component
public class OrientDbRealm extends AuthorizingRealm {

private Logger logger = Logger.getLogger(OrientDbRealm.class);

@Autowired
private LoginService loginService;

@Override
protected AuthenticationInfo doGetAuthenticationInfo(
final AuthenticationToken token)
throws AuthenticationException {
final HFUsernamePasswordToken credentials = (HFUsernamePasswordToken) token;
final String username = credentials.getUsername();
if (username == null) {
logger.warn("Userame is null");
return null;
}
HashMap<String,Object> map = new HashMap<String,Object>();
map.put("telephone", username);
map.put("pwd", new String(credentials.getPassword()));
//final User user = userRepository.findByEmailAndActive(email, true);
User user = loginService.findUser(map);
if (user == null) {
//throw new UnknownAccountException("Account does not exist");
logger.warn("Account does not exist");
return null;
}
return new SimpleAuthenticationInfo(username, credentials.getPassword(),
ByteSource.Util.bytes(username), getName());
}

@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// TODO Auto-generated method stub
return null;
}

}


4、错误内容:
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.hf.consumer.login.LoginService com.hf.hfmo.shiro.OrientDbRealm.loginService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.hf.consumer.login.LoginService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:571)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
... 42 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.hf.consumer.login.LoginService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1326)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1072)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:967)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:543)
... 44 more


是不是因为我的applicationContext_shiro.xml在dispatcher-servlet.xml之前加载,那么当注册realm时尚未对@Service标记的bean进行注册,所以realm内用@Autowired注入时找不到bean。难道spring不会等所有的bean都注册完了再进行依赖注入吗?请问我这里怎么处理比较好?
能不能推荐一些这方面的比较好的文章,十分感谢!
...全文
830 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
chenhua141 2018-06-08
  • 打赏
  • 举报
回复
这个要看你有没有先注册了LoginService的实现类,如果没有,直接在applicationContext.xml注册LoginService就可以了.
huahua035 2017-06-13
  • 打赏
  • 举报
回复
这种情况,属于xml配置的bean和annotation的bean混用,造成父Bean初始化化,子Bean还没有初始化的情况
huahua035 2017-06-13
  • 打赏
  • 举报
回复
OrientDbRealm 实现InitializingBean 接口
sunkaigoon 2017-04-25
  • 打赏
  • 举报
回复
最后还是配置文件扫描顺序原因。context-param的配置文件先扫描,那么先注册这些配置文件中的bean。而注解扫描配置在applicationContext_shiro.xml里面,这个文件是最后被扫描的,所以注解扫描自动注册的bean在一开始或者说在注册context-param的配置文件中声明的bean是还不存在,所以会报错。
月明星稀灬 2017-03-29
  • 打赏
  • 举报
回复
@Autowired 按类型注入 @Resource 按bean名注入,显然你在xml里面配置了bean指定了bean的名称,所以你注入的时候要配合@Resource注解使用
李德胜1995 2017-03-29
  • 打赏
  • 举报
回复
引用 4 楼 sunkaigoon 的回复:
@pany1209 就是这个问题,我觉得是不是在加载shiro配置文件时开始注册realm,此时还没有加载dispatcher.xml导致@Service没有进行自动扫描。如果是这样的话,我这里是不是就不能用这个service了
你的@component和@service扫描的配置看一下。。。
月明星稀灬 2017-03-29
  • 打赏
  • 举报
回复
要不然清个缓存试一试?
月明星稀灬 2017-03-29
  • 打赏
  • 举报
回复
引用 4 楼 sunkaigoon 的回复:
@pany1209 就是这个问题,我觉得是不是在加载shiro配置文件时开始注册realm,此时还没有加载dispatcher.xml导致@Service没有进行自动扫描。如果是这样的话,我这里是不是就不能用这个service了
感觉你这个配置文件里面的bean的名字都有点乱啊,随便取的名字?
sunkaigoon 2017-03-29
  • 打赏
  • 举报
回复
@pany1209 就是这个问题,我觉得是不是在加载shiro配置文件时开始注册realm,此时还没有加载dispatcher.xml导致@Service没有进行自动扫描。如果是这样的话,我这里是不是就不能用这个service了
李德胜1995 2017-03-29
  • 打赏
  • 举报
回复
@Autowired默认按类型装配,默认要求依赖的对象必须存在,@Resource如果没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,也会按照类型匹配。。。。。应该检查一下service是否有扫描到吧
sunkaigoon 2017-03-29
  • 打赏
  • 举报
回复
@xiekuntarena 其一: 自动扫描是这样的 @Service(value="loginService") public class LoginServiceImpl implements LoginService{} 这种用@Autowired应当没有问题。 其二: 我刚刚将@Autowired改成@Resource和@Resource(name="loginService")还是报错,找不到bean 其三: @Autowired private LoginService loginService; 这种自动注入在其它类中也用了,没有报错。 所以感觉不是这个问题。。。

67,513

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧