AOP后发现原来能注入的变量都没注入,一个很有意思的问题
今天要给系统增加日志功能,系统使用struts2+spring2.5+hibernate3.0框架开发。
我第一反应就是使用AOP,又快又方便。
我这么修改:
1、修改spring配置文件,增加如下内容:
<aop:aspectj-autoproxy/>
<bean id="actionTrack" class="com.sa.ActionTrack" />
配置文件原来就已经配置了
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="....
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd ..."
所以就免了。
而actionTrack就是我的日志跟踪类,如下:
@Aspect
public class ActionTrack
{
@Pointcut("execution(* com.xx..*.*Action.*(..))")
public void actionPointCut(){};
public Object roundLog(ProceedingJoinPoint pjp) throws Throwable
{
Signature sig = pjp.getSignature();
Object obj = pjp.getTarget();
String str="calling "+obj.getClass().toString() + " " + sig.getName();
System.out.println(str);
Object retVal = pjp.proceed();
str="calling over "+obj.getClass().toString() + " " + sig.getName();
return retVal;
}
@Before("target(com.xx.struts2.action.BaseAction)")
public void beforeLog(JoinPoint jp)
{
Signature sig = jp.getSignature();
Object obj = jp.getTarget();
String str="before calling "+obj.getClass().toString() + " " + sig.getName();
System.out.println(str);
//Object retVal = pjp.proceed();
//str="calling over "+obj.getClass().toString() + " " + sig.getName();
//return retVal;
}
@AfterThrowing(pointcut="target(com.xx.struts2.action.BaseAction) ",throwing="ex")
public void exceptionLog(Exception ex)
{
ex.printStackTrace();
}
}
然后启动tomcat,登录系统,查看日志,发现打印before calling xxxx " " xxx后就打印出异常,大概如下:
java.lang.NullPointerException
at com.xx.xxAction.list(GridProcessorAction.java:161)
at com.xx.xxAction$$FastClassByCGLIB$$21cf86ce.invoke(<generated>)
跟踪进去list方法发现如下代码
xxService.query(xxx);
中xxService是空指针,xxService是成员变量,自动注入的,如下:
@Resource(name="xxService")
private xxServiceImpl xxService;
其中xxServiceImpl是xxService的接口。
明明声明了自动注入,不应该为空啊,而且我把切面去了,就一切正常,真莫名其妙。
后来我发现这个xxAction的类开头并没有注解声明
@Repository("login") @Scope("prototype")
但是在没用切面前,它的属性却能正确注入,真的怪了。于是跟踪struts的配置文件,发现struts是这么写的
<action name="Login_*" class="com.xx.xxAction" method="{1}">
<result name="input">xx</result>
<result>xx</result>
</action>
按理说struts+spring时,这个class应该是写spring组件的ID,但这里却写具体类。从目前的配置看,也就是struts的所有action都不有Spring托管,但是Spring却能注入变量,真神奇了。
我把上面的配置改成
<action name="Login_*" class="login" method="{1}">
<result name="input">xxx</result>
<result>xx</result>
</action>
然后在xxAction的类开头加上注解,如下
@Repository("login") @Scope("prototype")
xxAction
然后再运行切面,一切正常,问题解决了。
但遗留下疑问,struts+spring是struts的action明明没有被spring托管,怎么会自动注入变量的。这个也是系统的一个设计缺陷