浏览 6290 次
锁定老帖子 主题:Spring的AOP动态调用的反思
精华帖 (0) :: 良好帖 (2) :: 新手帖 (5) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-02-26
代码如下: public abstract class DispatchAction extends BaseAction /* */ { /* 98 */ protected static Log log = LogFactory.getLog(DispatchAction.class); /* */ protected Class clazz; /* */ protected HashMap methods; /* */ protected Class[] types; /* */ /* */ public DispatchAction() /* */ { /* 105 */ this.clazz = super.getClass(); /* */ /* 113 */ this.methods = new HashMap(); /* */ /* 119 */ this.types = new Class[] { ActionMapping.class, ActionForm.class, HttpServletRequest.class, HttpServletResponse.class }; /* */ } /* */ /* */ public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) /* */ throws Exception /* */ { //首先执行这里,程序的入口 /* 145 */ if (isCancelled(request)) { /* 146 */ ActionForward af = cancelled(mapping, form, request, response); /* */ /* 148 */ if (af != null) { /* 149 */ return af; /* */ } /* */ /* */ } /* */ /* 154 */ String parameter = getParameter(mapping, form, request, response); //获取strut配置文件中的parameter的参数--通常为method /* */ /* 157 */ String name = getMethodName(mapping, form, request, response, parameter); /* */ /* 161 */ if (("execute".equals(name)) || ("perform".equals(name))) { /* 162 */ String message = messages.getMessage("dispatch.recursive", mapping.getPath()); /* */ /* 165 */ log.error(message); /* 166 */ throw new ServletException(message); /* */ } /* */ /* 170 */ return dispatchMethod(mapping, form, request, response, name); //根据method动态调用方法 /* */ } /* */ /* */ protected ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) /* */ throws Exception /* */ { /* 191 */ String message = messages.getMessage("dispatch.parameter", mapping.getPath(), mapping.getParameter()); /* */ /* 195 */ log.error(message); /* */ /* 197 */ throw new ServletException(message); /* */ } /* */ /* */ protected ActionForward cancelled(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) /* */ throws Exception /* */ { /* 219 */ return null; /* */ } /* */ /* */ protected ActionForward dispatchMethod(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String name) /* */ throws Exception /* */ { /* 244 */ if (name == null) { /* 245 */ return unspecified(mapping, form, request, response); /* */ } /* */ /* 249 */ Method method = null; /* */ try /* */ { /* 252 */ method = getMethod(name); /* */ } catch (NoSuchMethodException e) { /* 254 */ String message = messages.getMessage("dispatch.method", mapping.getPath(), name); /* */ /* 257 */ log.error(message, e); /* */ /* 259 */ String userMsg = messages.getMessage("dispatch.method.user", mapping.getPath()); /* */ /* 261 */ throw new NoSuchMethodException(userMsg); /* */ } /* */ /* 264 */ ActionForward forward = null; /* */ try /* */ { /* 267 */ Object[] args = { mapping, form, request, response }; /* */ /* 269 */ forward = (ActionForward)method.invoke(this, args); //这里就是通过动态的调用,来执行各个方法的 /* */ } catch (ClassCastException e) { /* 271 */ String message = messages.getMessage("dispatch.return", mapping.getPath(), name); /* */ /* 274 */ log.error(message, e); /* 275 */ throw e; /* */ } catch (IllegalAccessException e) { /* 277 */ String message = messages.getMessage("dispatch.error", mapping.getPath(), name); /* */ /* 280 */ log.error(message, e); /* 281 */ throw e; /* */ } /* */ catch (InvocationTargetException e) /* */ { /* 285 */ Throwable t = e.getTargetException(); /* */ /* 287 */ if (t instanceof Exception) { /* 288 */ throw ((Exception)t); /* */ } /* 290 */ String message = messages.getMessage("dispatch.error", mapping.getPath(), name); /* */ /* 294 */ log.error(message, e); /* 295 */ throw new ServletException(t); /* */ } /* */ /* 300 */ return forward; /* */ } /* */ /* */ protected String getParameter(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) /* */ throws Exception /* */ { /* 318 */ String parameter = mapping.getParameter(); /* */ /* 320 */ if (parameter == null) { /* 321 */ String message = messages.getMessage("dispatch.handler", mapping.getPath()); /* */ /* 324 */ log.error(message); /* */ /* 326 */ throw new ServletException(message); /* */ } /* */ /* 330 */ return parameter; /* */ } /* */ /* */ protected Method getMethod(String name) /* */ throws NoSuchMethodException /* */ { /* 344 */ synchronized (this.methods) { /* 345 */ Method method = (Method)this.methods.get(name); /* */ /* 347 */ if (method == null) { /* 348 */ method = this.clazz.getMethod(name, this.types); /* 349 */ this.methods.put(name, method); /* */ } /* */ /* 352 */ return method; /* */ } /* */ } /* */ /* */ protected String getMethodName(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String parameter) /* */ throws Exception /* */ { /* 374 */ return request.getParameter(parameter); /* */ } /* */ } 于是乎对spring的AOP进行测试,想看看到底是不是因为动态调用方法,所以才导致aop无法对DispatchAction 进行有效的拦截。 测试代码如下: 首先定义一个切入点 @Component("aspectDemo") @Aspect public class AspectDemo { // 定义切入点表达式 private final static String EXP = "execution(* cn.gs..*.*(..))"; @Around(EXP) public Object around(ProceedingJoinPoint point) throws Throwable { System.out.println("Around Before " + point.getSignature().getName()); // 调用目标对象的方法并获取返回值 Object o = point.proceed(point.getArgs()); System.out.println("Around After " + point.getSignature().getName()); return o; } } 接着是拦截类的方法 @Service("dynamicProxy") public class DynamicProxy { public Object withMethodToExecute(String name) throws Exception { // 调用了withMethodToExecute Method method = getMethod(name); Object obj = method.invoke(this, name); // 此处动态调用了method1 return obj; } public Object withMethodToExecute2(String name) throws Exception { // 调用了withMethodToExecute method1(""); //直接调用method1 return null; } public String method1(String methodName) { System.out.println(" execute method1"); return methodName; } public Method getMethod(String name) throws NoSuchMethodException { Method method = this.getClass().getMethod(name, String.class); return method; } } spring配置文件的设置,开启了自动扫描和动态代理 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <aop:aspectj-autoproxy/> <context:component-scan base-package="cn.gs"/> </beans> Junit的测试类如下 public class ManTest { static DynamicProxy dynamicProxy; @BeforeClass public static void setUpBeforeClass() throws Exception { try { ApplicationContext act = new ClassPathXmlApplicationContext("beans.xml"); dynamicProxy = (DynamicProxy) act.getBean("dynamicProxy"); } catch (RuntimeException e) { e.printStackTrace(); } } @Test public void testSay() throws Exception { dynamicProxy.withMethodToExecute("method1"); //动态调用method1 System.out.println("============================="); dynamicProxy.withMethodToExecute2("method1"); //直接调用method1 System.out.println("ok"); } } 打印结果 Around Before withMethodToExecute execute method1 Around After withMethodToExecute ============================= Around Before withMethodToExecute2 execute method1 Around After withMethodToExecute2 ok 结果发现无法是动态调用method1方法还是直接调用,都无法打印两遍,也就是说我所希望的打印结果应该是这样的 Around Before withMethodToExecute Around Before method1 execute method1 Around After method1 Around After withMethodToExecute ============================= Around Before withMethodToExecute2 Around Before method1 execute method1 Around After method1 Around After withMethodToExecute2 ok 事实证明,AOP是无法对方法里面的方法进行递归的拦截。也就是如果一个方法里有多个符合AOP所要拦截的方法的话,那么是无法拦截到里面的方法的。这应该跟AOP的代理实现有关系。 **头一次发帖!有不对的地方请指正。欢迎拍砖。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-02-27
其实有更深层次的原因:
AspectJ增强编译的字节码时,是不会修改你的方法实现的,凡是调用this.xxx的仍然是原来的方法;反射亦然 也有一个规避的方法:凡是用到this的地方,用从spring得到的对象代替 |
|
返回顶楼 | |
发表时间:2010-02-28
要想用到spring增强,必须用spring ioc里的proxy bean引用
而this引用到了具体实现proxy.target里具体bean了,所以得不到增强 |
|
返回顶楼 | |
发表时间:2010-03-01
为什么要递归拦截呢,我个人觉得权限不应该在action上拦截,应该拦截到业务层上就可以了。
|
|
返回顶楼 | |
发表时间:2010-03-02
在service上进行拦截合理。
|
|
返回顶楼 | |
发表时间:2010-03-02
AOP拦截不应该设在Action上,应该在业务逻辑层的方法上。
|
|
返回顶楼 | |
发表时间:2010-03-02
最后修改:2010-03-02
最简单就是做个web filter或者listener。当然在使用struts时可以使用intercepter,这个要看版本是否支持。
|
|
返回顶楼 | |
发表时间:2010-03-03
这点在《spring揭秘》一书中提到了,里面有讲到解决的办法。
|
|
返回顶楼 | |