最近项目里需要加一些系统非业务功能,和一些框架外的地方性拓展。为此我们想到使用spring的切面方式进行增加。考虑到aspectj使用起来比较简单,而且以前也有使用的经验,因此决定还是采用它。可悲剧的是当我们将其加上后,项目在启动阶段就报错了。
环境:项目使用的是struts2+spring2.5+hibernate3
1.当开始报错后,我们将所有相关代码注释掉,单单加上<aop:aspectj-autoproxy/>的配置后,项目就报错了,虽然不同,主要报对象的循环注入问题,在度娘上找了好久给出的答案为:spring的2.X版本中可能存在这类问题,解决方法一般为:
a.升级spring的版本为新的版本,有人说是由于spirng的早期框架不够完善导致,没有采用该方案,由于项目比较大,不好轻易替换原有框架jar包。
b.覆盖spring的源码,报循环引用的错误,主要是由于容器中的setAllowRawInjectionDespiteWrapping默认设置为false导致,我们可以采用如下方式修改:
写一个自己的容器类,继承xmlwebapplicationcontext,然后将setAllowRawInjectionDespiteWrapping设置为true
public class AllowRawInjectDespisteWrappingApplicationContext extends
XmlWebApplicationContext {
protected DefaultListableBeanFactory createBeanFactory() {
DefaultListableBeanFactory beanFactory = super.createBeanFactory();
beanFactory.setAllowRawInjectionDespiteWrapping(true);
return beanFactory;
}
}
修改web.xml配置文件,增加容器参数:
<context-param>
<param-name>contextClass</param-name>
<param-value>com.jb.framework.AllowRawInjectDespisteWrappingApplicationContext</param-value>
</context-param>
完成上述操作后,确实不在报循环引用的错误了。但是将系统其它实例加进去后,还是报错。
2.主要报错为,不能为子类做代理,原因是说没有一个无参的构造函数,经检查发现,我们的被代理对象全部都含有默认的构造函数,而且错误日志中提示的类名$proxy32也不是我们系统中的类。无奈下,通过跟踪源码发现,当我们使用两种切面方式作用于同一个类时,就会出现这种错误,项目中事务管理我们采用过的是:
org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator而我们附加的功能采用的是:org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
当这两种方式同时生效时,会对一个类做2次或多次代理,这时就会出现上面的提示和错误。
既然知道了问题所在,那么解决起来就简单了,我们将事务管理的切片也改为了aspectj的方式来实现,至此问题解决。