Shiro+Struts2+Spring3 加上@RequiresPermissions 后@Autowired失效
今天一iteye网页在问答频道提问【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" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true"/> </bean> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" 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() {
}