以往做项目的时候,用到了SPRING的AOP来做权限拦截。但项目里用的是Strut1,用的最多的Action是DispatchAction。所配置好一切以后,竟然发现不能有效的拦截DispatchAction里的各个方法。通过对DispatchAction源码的查看,发现原来DispatchAction是通过动态调用来执行各个不同的方法的~
代码如下:
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的代理实现有关系。
**头一次发帖!有不对的地方请指正。欢迎拍砖。
分享到:
相关推荐
- **实现**:Spring AOP机制主要通过动态代理实现,可以在不修改原有代码的情况下添加额外的功能。 - **好处**:增强了代码的扩展性和可读性。 3. **装饰器模式**: - **功能**:Spring利用装饰器模式为现有对象...
随后,本书的第6至7章介绍了Spring AOP(面向切面编程)的相关概念,以及如何在Spring中实现和使用面向切面编程,同时强调注解在AOP中的重要性。 第8章到第11章分别介绍了Spring对JDBC、Hibernate、JPA和MyBatis等...
2. **代理模式**:在AOP中,Spring通过动态代理技术实现横切关注点的织入,例如在方法调用前后插入日志记录或事务管理等功能。 3. **装饰者模式**:Spring使用装饰器模式来增强现有的bean功能,比如通过添加缓存...
同时,需要配置Spring的IoC(Inversion of Control)容器和AOP(Aspect Oriented Programming)支持。 3. **使用构造方法和setter方法进行对象注入**:在Spring框架中,依赖注入是核心特性之一,通过构造器或setter...
Spring作为核心框架,提供了依赖注入(DI)和面向切面编程(AOP),用于管理对象的生命周期和行为;SpringMVC则是Spring框架的一部分,专门处理Web请求和响应,实现了Model-View-Controller设计模式,使得业务逻辑与...
- **IOC与AOP**:介绍依赖注入(IOC)的概念及其优势,以及面向切面编程(AOP)的实现原理与应用场景。 - **Bean的作用域与生命周期**:讨论Bean的生命周期管理及不同作用域下的行为差异。 - **SpringBoot改进**:...
3. **控制器(Controller)**:控制器是模型和视图之间的桥梁,它接收用户的输入,调用模型进行处理,然后更新视图。控制器处理业务逻辑的细节,确保用户请求正确地传递到相应的地方。 早期的Web开发中,开发者直接...
Spring框架是企业级应用的常用选择,它涵盖了依赖注入、AOP(面向切面编程)、事务管理等多个方面,简化了复杂系统的构建。 异常处理是Java程序健壮性的保障。理解何时、如何抛出和捕获异常,能够有效防止程序在...
- **Spring框架**:企业级应用开发框架,简化了依赖注入和AOP(面向切面编程)。 课后答案可以帮助你验证对这些概念的理解,找出不足之处,加深对Java编程的掌握。同时,分享和讨论这些答案也能促进团队学习,共同...
- **多态**:子类重写父类的方法,根据对象的实际类型动态决定调用哪个版本的方法。 3. **封装**: - **访问修饰符**:public、protected、private等控制成员的访问级别。 - **getter/setter方法**:提供外部...
5. **反射机制**:反射是Java动态性的重要体现,它允许程序在运行时检查类的信息,并可以动态创建对象和调用方法。在高级Java课程中,反射常用于配置文件的读取、插件机制的实现等。 6. **设计模式**:设计模式是...