Shiro+Struts2+Spring3 加上@RequiresPermissions 后@Autowired失效
@ParentPackage("all") @Namespace("/project") public class ProjectAction extends BaseAction { public final static Logger logger = LoggerFactory .getLogger(ProjectAction.class); @Autowired(required=true) private ProjectService projectService;
?如上代码@Autowired注入不了
?
?
分析:
1、首先从如上代码可以看出 走的是struts2注解,而且使用了struts2?convention 插件,这个插件会扫描如下配置的actionPackages 寻找action
?
<filter> <filter-name>struts2</filter-name> <filter-classfilter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class> <init-param> <param-name>actionPackages</param-name> <param-value>cn.javass</param-value> </init-param>
?
?
2、但此时并没有把action交给spring,
3、接下来,因为集成了spring(有struts2-spring-plugin),所以要使用StrutsSpringObjectFactory创建bean,代码分析
?
@Override public Object buildBean(String beanName, Map<String, Object> extraContext, boolean injectInternal) throws Exception { Object o; if (appContext.containsBean(beanName)) { o = appContext.getBean(beanName); //拿不到bean } else { Class beanClazz = getClassInstance(beanName); o = buildBean(beanClazz, extraContext); //所以创建了一个 } if (injectInternal) { injectInternalBeans(o); } return o; }
?
/** * @param clazz * @param extraContext * @throws Exception */ @Override public Object buildBean(Class clazz, Map<String, Object> extraContext) throws Exception { Object bean; try { // Decide to follow autowire strategy or use the legacy approach which mixes injection strategies if (alwaysRespectAutowireStrategy) {//默认false // Leave the creation up to Spring bean = autoWiringFactory.createBean(clazz, autowireStrategy, false); injectApplicationContext(bean); return injectInternalBeans(bean); } else { bean = autoWiringFactory.autowire(clazz, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false); //只走构造器注入 bean = autoWiringFactory.applyBeanPostProcessorsBeforeInitialization(bean, bean.getClass().getName()); // We don't need to call the init-method since one won't be registered. bean = autoWiringFactory.applyBeanPostProcessorsAfterInitialization(bean, bean.getClass().getName()); return autoWireBean(bean, autoWiringFactory); } } catch (UnsatisfiedDependencyException e) { if (LOG.isErrorEnabled()) LOG.error("Error building bean", e); // Fall back return autoWireBean(super.buildBean(clazz, extraContext), autoWiringFactory); } }
?
?我们在shiro里使用如下代码 去代理shiro的代理:
?
<bean id="proxyCreator" value="true"/> </bean> <bean ref="securityManager"/> </bean>
?
?
//StrutsSpringObjectFactory的如下代码将执行处理器的预处理
bean = autoWiringFactory.applyBeanPostProcessorsBeforeInitialization(bean, bean.getClass().getName());
?
//DefaultAdvisorAutoProxyCreator的postProcessBeforeInstantiation:将去完成代理bean 因此此时将返回代理Bean
?
//接着StrutsSpringObjectFactory的autoWireBean(bean, autoWiringFactory); 进行注入 所以此时注入到的是代理对象,因此如果字段注入 将注入不了。
?
?
解决方案
?
1、不使用actionPackages ??而是 在类上加 ?@Controller @Scope 完全走spring ?
2、使用setter注入 而不是字段 如?
? private ProjectService projectService;?
?
? @Autowired(required=true)?
? public void setProjectService() {?
? }?
?
?