目录
- 前言
- BeanNameAutoProxyCreator 自动代理实现
- AOP标签之Aspect实现
- 继承DelegatingRequestProcessor (非AOP实现)
[一]、前言
一个N年前的SSH(Spring2.0.3+Struts1+Hibernate3)框架的项目,需要增加一个记录系统操作日志的功能,这时自然而然想到利用Spring的AOP特性来实现,但在实际实现过程中还是遇到了不小的问题,本文主要是记录这些问题的解决办法和不同实现方法的使用场景及其优缺点。
实例演示中:LonginAction 继承 Action ,UserAccountMainAction 继承 DispatchAction
[二]、BeanNameAutoProxyCreator 自动代理实现
1.适用场景
- Spring 配置文件中命名规范的配置简单,否则很麻烦
- 对于继承Struts1的Action、DispatchAction 的类都可以拦截成功
- 过滤规则单一(不能根据package、方法名、参数 等自定义过滤)
2.实例演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<bean name="loggerAdvice" class="com.micmiu.tutorial.spring.aop.LoggerBeforeAdvice"> </bean> <bean name="loggerAutoProxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"> <list> <!-- 配置文件中控制层的类都是以*Action结尾命名--> <value>*Action</value> <value>*Login</value> <value>*Logout</value> </list> </property> <property name="interceptorNames"> <list> <value>loggerAdvice</value> </list> </property> </bean> |
LoggerBeforeAdvice.java 需要实现Advice接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
package com.micmiu.tutorial.spring.aop; import org.apache.log4j.Logger; import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; /** * Created * User: <a href="http://micmiu.com">micmiu</a> * Date: 7/3/2014 * Time: 0:00 */ public class LoggerBeforeAdvice implements MethodBeforeAdvice { /** * Logger for this class */ private static final Logger LOGGER = Logger.getLogger(LoggerBeforeAdvice.class); /** * @param method * @param objects * @param o * @throws Throwable */ public void before(Method method, Object[] objects, Object o) throws Throwable { StringBuilder sb = new StringBuilder(">>>> Advice logger \r\n"); sb.append(" [start ] : " + System.currentTimeMillis() + " \r\n"); sb.append(" [class ] : " + o.getClass().getSimpleName() + " \r\n"); sb.append(" [method] : " + method.getName() + " \r\n"); for (Object obj : objects) { if (null == obj) { continue; } sb.append(" params : " + obj + " \r\n"); } sb.append(" [end ]: " + System.currentTimeMillis() + " <<<<"); LOGGER.info(sb.toString()); } } |
直接继承Action的日志记录如下:
1 2 3 4 5 6 7 8 |
INFO - LoggerBeforeAdvice.before(44) | >>>> Advice logger [start ] : 1404368843729 [class ] : LoginAction [method] : execute params : ActionConfig[path=/Login,input=/login.jsp,name=loginForm,scope=session,type=org.springframework.web.struts.DelegatingActionProxy,validate=true,cancellable=false params : org.apache.catalina.connector.RequestFacade@72d37f4b params : org.apache.catalina.connector.ResponseFacade@1b4a4fd2 [end ]: 1404368843729 <<<< |
继承DispachAction的日志记录如下:
1 2 3 4 5 6 7 8 |
INFO - LoggerBeforeAdvice.before(44) | >>>> Advice logger [start ] : 1404368850018 [class ] : UserAccountMainAction [method] : execute params : ActionConfig[path=/UserAccountMainAction,parameter=method,scope=session,type=org.springframework.web.struts.DelegatingActionProxy,validate=true,cancellable=false params : org.apache.catalina.connector.RequestFacade@72d37f4b params : org.apache.catalina.connector.ResponseFacade@1b4a4fd2 [end ]: 1404368850018 <<<< |
[二]、AOP标签之Aspect实现
1.适用场景
- 拦截表达式灵活,可以根据package、方法、参数、返回值 等等进行过滤
- 对于Struts1的Action继承类可以拦截,但是继承DispatchAction的类拦截失败(解决办法是:继承DispatchAction的类需要重写下 父类的 execute 方法才能被拦截),这个原因是因为:如果是通过反射技术调用的方法是不能被拦截到,否则就可以被拦截,而DispatchAction 正是通过反射来调用具体方法的。
2.实例演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?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: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.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd" default-lazy-init="true"> <!-- 其他省略..... --> <bean name="aopLogger" class="com.micmiu.tutorial.spring.aop.LoggerAopBefore" /> <aop:config> <aop:pointcut id="pointAction" expression="execution(* actions..*.*(..))" /> <aop:aspect id="aspectLogger" ref="aopLogger" > <aop:before method="before" pointcut-ref="pointAction" /> </aop:aspect> </aop:config> <!-- 其他省略.... --> </beans> |
LoggerAopBefore.java 无需实现接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
package com.micmiu.tutorial.spring.aop; import org.apache.log4j.Logger; import org.aspectj.lang.JoinPoint; /** * Created * User: <a href="http://micmiu.com">micmiu</a> * Date: 7/1/2014 * Time: 11:14 */ public class LoggerAopBefore { private Logger logger = Logger.getLogger(this.getClass().getName()); public void before(JoinPoint jointPoint) throws Throwable { StringBuilder sb = new StringBuilder(">>>> AOP logger \r\n"); sb.append(" [start ] : " + System.currentTimeMillis() + " \r\n"); for (Object o : jointPoint.getArgs()) { if (null != o) { sb.append(" [method ] : " + o + " \r\n"); } } sb.append(" [Signature] :" + jointPoint.getSignature().getDeclaringTypeName() + "." + jointPoint.getSignature().getName()); sb.append(" [end ]: " + System.currentTimeMillis() + " <<<<"); logger.info(sb.toString()); } } |
所有 DispatchAction的实现类需要重写父类的 execute 方法:
1 2 3 4 |
@Override public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { return super.execute(mapping, form, request, response); } |
直接继承Action的日志记录如下:
1 2 3 4 5 6 |
INFO - LoggerAopBefore.before(28) | >>>> AOP logger [start ] : 1404371203156 [method ] : ActionConfig[path=/Login,input=/login.jsp,name=loginForm,scope=session,type=org.springframework.web.struts.DelegatingActionProxy,validate=true,cancellable=false [method ] : org.apache.catalina.connector.RequestFacade@68b0019f [method ] : org.apache.catalina.connector.ResponseFacade@7b3aa36a [Signature] :actions.LoginAction.execute [end ]: 1404371203159 <<<< |
继承DispachAction的日志记录如下:
1 2 3 4 5 6 |
INFO - LoggerAopBefore.before(28) | >>>> AOP logger [start ] : 1404371206786 [method ] : ActionConfig[path=/UserAccountMainAction,parameter=method,scope=session,type=org.springframework.web.struts.DelegatingActionProxy,validate=true,cancellable=false [method ] : org.apache.catalina.connector.RequestFacade@68b0019f [method ] : org.apache.catalina.connector.ResponseFacade@7b3aa36a [Signature] :actions.UserAccountMainAction.execute [end ]: 1404371206786 <<<< |
[四]、继承DelegatingRequestProcessor (非AOP实现)
struts-config.xml 配置文件中增加:
1 2 3 |
<controller> <set-property property="processorClass" value="com.micmiu.tutorial.spring.support.ExtDelegatingRequestProcessor"/> </controller> |
ExtDelegatingRequestProcessor.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
package com.micmiu.tutorial.spring.support; import org.apache.log4j.Logger; import org.apache.struts.action.Action; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.actions.DispatchAction; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * 扩展 DelegatingRequestProcessor 实现Action操作日志记录 * User: <a href="http://micmiu.com">micmiu</a> * Date: 7/3/2014 * Time: 15:10 */ public class ExtDelegatingRequestProcessor extends org.springframework.web.struts.DelegatingRequestProcessor { static Logger logger = Logger.getLogger(ExtDelegatingRequestProcessor.class); @Override protected ActionForward processActionPerform(HttpServletRequest request, HttpServletResponse response, Action action, ActionForm form, ActionMapping mapping) throws IOException, ServletException { String methodname = "execute"; // 判断DispatchAction是否是所传过来的Action指向对象的父类 // 如果是,则根据请求参数,取得将要执行的方法名称,并且通过反射技术取得这个方法,采用AOP切入! // 如果不是的话,则证明是执行的是Action的execute方法,返回execute的方法的对象。 if (DispatchAction.class.isAssignableFrom(action.getClass())) { methodname = request.getParameter(mapping.getParameter());//根据struts配置文件中dispatchAction的Parameter取得要执行的方法名称 } StringBuilder sb = new StringBuilder(">>>> DelegatingRequestProcessor logger \r\n"); sb.append(" [start ] : " + System.currentTimeMillis() + " \r\n"); sb.append(" [class ] : " + action.getClass() + " \r\n"); sb.append(" [method ] : " + methodname + " \r\n"); sb.append(" [request ] : " + request + " \r\n"); sb.append(" [response] : " + response + " \r\n"); sb.append(" [end ]: " + System.currentTimeMillis() + " <<<<"); logger.info(sb.toString()); return super.processActionPerform(request, response, action, form, mapping); } } |
Action 和DispatchAction 的 操作日志如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
INFO - ExtDelegatingRequestProcessor.processActionPerform(44) | >>>> DelegatingRequestProcessor logger [start ] : 1404372629760 [class ] : class actions.LoginAction [method ] : execute [request ] : org.apache.catalina.connector.RequestFacade@4896c002 [response] : org.apache.catalina.connector.ResponseFacade@2117e889 [end ]: 1404372629760 <<<< INFO - ExtDelegatingRequestProcessor.processActionPerform(44) | >>>> DelegatingRequestProcessor logger [start ] : 1404372674762 [class ] : class actions.UserAccountMainAction [method ] : displayUserAccountMainScreen [request ] : org.apache.catalina.connector.RequestFacade@44397d4e [response] : org.apache.catalina.connector.ResponseFacade@1a51aee0 [end ]: 1404372674762 <<<< |
本文介绍到此介绍。
—————– EOF @Michael Sun —————–
原创文章,转载请注明: 转载自micmiu – 软件开发+生活点滴[ http://www.micmiu.com/ ]
本文链接地址: http://www.micmiu.com/j2ee/spring/spring-aop-struts1-action/
你那有简单的案例么?能否给一下
我这样配过之后,并没有起到作用 😥