- 浏览: 212443 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
jongde1:
Axure太难学了,分享mockplus工具,有兴趣可以去了解 ...
Axure RP 原型设计工具 -
di1984HIT:
这里面提到了好几种解决办法。
Spring AOP对日志记录、Exception日志记录 -
di1984HIT:
学习一下。
spring struts2 零配置 -
di1984HIT:
不错,不错啊
Struts2防止表单重复提交 -
di1984HIT:
kettle怎么样啊。
Kettle初探
Spring AOP对日志记录、Exception日志记录
利用spring aop对日志进行管理,还是采用对比的方式进行,
修改前:
偶们的做法是在action里记录日志,注意这个日志是面向用户的日志,姑且称它为业务日志,至于后台日志,则在此文章中暂不考虑,基本是通过log4j打印到后台日志文件中。看下面一段代码:
这段代码实际上已经将写日志的过程封装起来,开发者只需要传入3个参数:操作者、是前台系统还是后台系统、以及日志的错误等级,其它的如操作者机器IP, 日志时间等信息由系统统一设定,即使是这样,如果一个action里面有多个操作,代码看起来也非常臃肿,而且给开发者增加了工作量,既然有了aop,为 什么不利用一下?看下面改造的代码:
噢,aop:config的第一行是不是很熟悉啊,对,就是我们前面所配置的事务管理,这里,应该很清楚采用统一的aop配置的好处了吧。下面贴出logAfterAdvice的代码:
这段代码应该很清楚了,将logService注入到拦截log的advice里,进行正确操作的日志记录,而afterReturning方法里 的第一行判断是由于logService里的写日志的方法是以save开始的。所以,如果拦截器拦截到此方法,不需要记录日志。
正确的日志记录完,当然如果发生异常,我们需要记录操作的失败日志,当然了,我们也是通过aop来做,但是这次是通过实现exception advice来实现,代码如下:
上面代码已经很好的说明了,如果发生exception的话,日志是怎么记录的,这里要提到的一点的是,异常的处理稍微有一些复杂,就拿本例的代码能看出 来,只要在service层有异常的时候,都会记录失败日志,实际上,很多时候,未必是这样,在某个模块,可能需要定义一种特殊的异常,而一旦这种异常发 生,则需要进入另外一个流程或者做一些特殊的处理,这个时候需要根据具体情况做一些变更,比如在上面代码我们加上:
则如果OrderException被抛出,就会到此方法中执行,而不会去写日志。
--------------------------------------------------------------------------------
其中的封装方式虽然一般,但是还是比较好的解决了问题!对于LogVO类我们可以把他继续扩展下去,比如设定访问用户,IP,seq文等.
reference:http://www.360doc.com/editart2.aspx?articleid=271503637
**************
spring AOP 是基于面向切面的编程,它能够使得我们专注于我们的业务处理,将一些其他的东西由它来统一完成,程序的侵入性很小,所以被广泛应用,至于实现原理我就不多说了,两个字:"代理"!
下面说说标题所示的应用,记录日志,什么时候记录日志,都记录什么?想想,可不 就是在调用方法的时候写日志嘛,之前如果使用logger的话,都会在方法的开始写一个logger.info("xxxxxxxxxxxx");结束的 时候再写一个,这不是很麻烦吗,每次都要写。实际上这个时候我们就可以用aop来做,当方法进入的时候写一条日志,结束的时候再写一条,分别对应“前置通 知”和”后置通知“,如果我们都日志有新的写法,值需要修改控制日志的这个类,对程序没有丝毫影响,也就谈不上改动大量的代码了。下面开始:
1.引入aop的命名空间(其中有AOP的那部分):
2.书写记录日志的类:
上面这段代码实现了输出要调用的类名,方法已经参数。
3.配置xml文件:
注意:我这里配置的是拦截所有action的所有方法,可以根据自己的情况配置,同时也只配了一个”前置通知“before,如果要需要还可以配置其他的。
实现已经完毕了!
*****************
首先,需要将log4j先配置好在web.xml中加入解析器servlet的配置
之后,由于我项目当中配置了大量的service类,类名都以Service结尾,为了方便配置使用spring当中的BeanNameAutoProxyCreator类进行aop配置。
在spring配置文件中配置如下:
再来就是写Advice类了也就是配置中的LoggerAdvice,代码如下:
http://www.weishuzhai.com/learn-spring-part-three/
*********************************************************************
注解方式---spring的AOP拦截用户操作
配置文件:
实现代码:
**************************************************************************
xml方式---spring的AOP拦截用户操作
需要日志记录,将所有的web操作记录到数据库中,使用aop来记录日志,当然是一个好的选择,spring中集成aop记录日志的方式有多种(aop的配置方式有多种,注解、xml配置),这里只说一个xml配置的例子。
1、编写日志记录类
2、配置aop
1、编写日志记录类
2、配置aop
在applicationContext.xml中配置
基本配置就是这样的,这里需要配置<aop:config proxy-target-class="true" /> ,表示强制使用cglib代理,而不是java本身的代理,这个很重要,如果使用java自带的代理,则会抛出异常,提示说代理类无法转换为我们自己的类,这是因为默认的该属性为false,这种代理方式,需要实现接口的方式,代理返回的类可以转换为对应的接口类,但无法直接转换为类的实现,这种方式不推荐。
reference:http://blog.csdn.net/johnjobs/article/details/8667646
**********************************************************************************
**********************************************************************************
如果要在方法执行前或后或抛出异常后加上一个自己的拦截器,或者一个环绕拦截器,在拦截器中执行一些操作,比如执行一些数据库操作,记录一些信 息,这些操作通过调用一个服务类的方法来执行,这个方法也在spring事务管理拦截器的管理之下,那么这个记录方法需要在另一个事务中进行,而不是与被 拦截方法在同一个事务中,不然如果被拦截方法抛出异常需要回滚时,所作的记录也会被回滚,当然有时候确实需要同时回滚,那就要放在同一个事务中。
这和自己的拦截器和事务管理的拦截器的执行顺序有一定关系,spring事务管理拦截器是一个环绕通知,在被拦截方法执行前启动事务,执行后完成 事务,如果自己的拦截器被spring事务管理拦截器包围在里面,那么在自己的拦截器运行时,spring已经启动了一个事务,如果你的记录信息方法需要 与被拦截方法同在一个事务中,将你的记录信息方法的事务传播属性设为默认的REQUIRED就可以了;
如果你记录信息的方法需要单独的一个事务环境,那就要把事务传播属性设为REQUIRES_NEW了,这样spring事务管理器会新建一个事 务,并且新建一个session连接,因为一个数据库连接不可能同时有两个事务,记录信息完了提交事务并且把新建的session连接关闭,自己的拦截器 退出后继续执行被拦截的方法或它的事务处理。
相反如果自己的拦截器在spring事务管理拦截器的外面,那么记录信息的方法会在一个单独的事务中执行,并提交,不管它的事务传播属性是 REQUIRES_NEW还是REQUIRED,因为与被拦截方法的事务处理没有交叉,并且可以使用同一个session连接如果是 OpenSessionInViewFilter。
所以如果记录信息和被拦截方法要在不同事务中执行,分别提交,那么最好将自己的拦截器设在spring事务管理器拦截器的外面;如果需要将记录信 息和被拦截方法在同一个事务中处理,必须将自己的拦截器被包围在spring事务管理拦截器中,并且记录信息方法的事务传播属性为默认的 REQUIRED。
设置拦截器的执行顺序可以让拦截器处理类实现org.springframework.core.Ordered接口,在spring配置文件的 AOP设置中设定自己的拦截器和spring事务管理拦截器的执行顺序,将自己的拦截的序号排在spring事务管理的前面,就可以将该拦截器放到事务管 理拦截器的外面执行了,对于before通知方式会先于事务管理拦截器执行,对于after returning和after和after throwing通知方式会后于事务管理拦截器的执行,对于arount通知方式会包围事务管理拦截器执行。
下面是一个异常拦截器的例子。
有位朋友提到在spring异常拦截器中更新数据不能够提交,做了一下测试,测试环境基本是这样:一个用户登录的功能,spring对 service中的每个方法进行事务管理,在用户检测的service方法上同时加上一个异常拦截器,当用户不存在或密码不正确时用户检测方法会抛出异 常,异常拦截器捕获到该异常,同时记录一些日志。
spring配置文件相关:
service方法中的事务传播属性都设为要求新建事务,spring事务管理切面拦截器的order设为1,而log拦截器的order设为2,这意味 着这两个要同时执行时,先执行事务拦截器,后执行log拦截器,由于事务管理是一个环绕通知(around),实际上是log拦截器被包围在事务管理拦截 器中。
从中可以看出,log异常拦截器在用户登录的事务回滚之前截获异常,在记录日志时,日志记录的service方法也在spring的事务管理之 下,用户登录的事务还没有结束,根据REQUIRES_NEW特性,spring会新开一个事务,这时原来的数据库连接已经在一个事务中,一个连接不可能 同时有两个事务,所以同时新创建一个session连接(虽然我使用了OpenSessionInViewFilter,并且session是单例的), 日志记录就在新建的事务和session中进行,完了提交,并且会把新建的session连接关闭。
然后继续进行被中断的用户登录的事务管理操作,由于抛异常spring将用户登录的事务回滚。
这样能够实现预想的功能,但是如果我去掉指定的REQUIRES_NEW,那么log记录的操作会继续在用户登录的事务中进行,最后会被一起回滚。
如果把事务管理的order设为2,log拦截器的order设为1,也就是log拦截器在事务管理拦截器的外面,会在事务管理拦截器前后执行完了再执行log的异常拦截器。
可以看出,用户登录的事务和日志记录的事务是前后两个不相关的事务,并且在日志记录事务中并不需要新建session连接,而是直接用在 OpenSessionInViewFilter中创建的session。实际上这时也并不需要将propagation设为REQUIRES_NEW, 使用默认的REQUIRES也照样能够正常工作。
所以应该将该异常拦截器设在事务管理拦截器的外面,即使用Order接口排在前面。
reference:http://blog.csdn.net/zmhinzaghi/article/details/7091795
利用spring aop对日志进行管理,还是采用对比的方式进行,
修改前:
偶们的做法是在action里记录日志,注意这个日志是面向用户的日志,姑且称它为业务日志,至于后台日志,则在此文章中暂不考虑,基本是通过log4j打印到后台日志文件中。看下面一段代码:
try { employeInfoManageService.saveEmploye(vo, authForm.getLoginName()); LogVO logVO = new LogVO(Constants.LOG_LEVEL_INFO, Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName() + "增加员工成功!"); logService.saveLog(logVO); } catch (Exception e) { log.error(e); LogVO logVO = new LogVO(Constants.LOG_LEVEL_ERROR, Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName() + "增加员工失败!"); try { logService.saveLog(logVO); } catch (Exception e1) { log.error(e1); return messageForward("error", "alert.db.exception", new Object[] {}); } }
这段代码实际上已经将写日志的过程封装起来,开发者只需要传入3个参数:操作者、是前台系统还是后台系统、以及日志的错误等级,其它的如操作者机器IP, 日志时间等信息由系统统一设定,即使是这样,如果一个action里面有多个操作,代码看起来也非常臃肿,而且给开发者增加了工作量,既然有了aop,为 什么不利用一下?看下面改造的代码:
LogVO logVO = new LogVO(Constants.LOG_LEVEL_INFO, Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName() + "增加员工"); try { employeInfoManageService.saveEmploye(vo, authForm.getLoginName(), logVO); } catch (Exception e) { log.error(e); return messageForward("error", "alert.db.exception", new Object[] {}); }既然是应用到aop,当然少不了aop的配置了,看下面的配置代码:
1. <aop:config>
2. <aop:advisor pointcut="execution(* *..*Service.*(..))" advice-ref="txAdvice"/>
3. <aop:advisor pointcut="execution(* *..*Service.save*(..)) || execution(* *..*Service.update*(..)) || execution(* *..*Service.delete*(..))" advice-ref="logAfterAdvice"/>
4. </aop:config>
5.
6. <bean id="logAfterAdvice" class="com.fudannet.framework.aop.LogAfterAdvice"/>
噢,aop:config的第一行是不是很熟悉啊,对,就是我们前面所配置的事务管理,这里,应该很清楚采用统一的aop配置的好处了吧。下面贴出logAfterAdvice的代码:
public void afterReturning(Object returnObj, Method method, Object[] args, Object targetObj) throws Throwable { if(method.getName().equals("saveLog")) return; for(int i = 0; i < args.length; i++){ if(args[i] instanceof LogVO){ log.info("开始写入日志......"); writeLog((LogVO)args[i]); } } } private void writeLog(LogVO vo){ try { vo.setDescription(vo.getDescription() + "成功!"); logService.saveLog(vo); } catch (RuntimeException e) { log.error(e); } public void setLogService(LogService logService) { this.logService = logService; }
这段代码应该很清楚了,将logService注入到拦截log的advice里,进行正确操作的日志记录,而afterReturning方法里 的第一行判断是由于logService里的写日志的方法是以save开始的。所以,如果拦截器拦截到此方法,不需要记录日志。
正确的日志记录完,当然如果发生异常,我们需要记录操作的失败日志,当然了,我们也是通过aop来做,但是这次是通过实现exception advice来实现,代码如下:
public void afterThrowing(Method method,Object[] args,Object target,Exception e) throws Throwable { if(method.getName().equals("saveLog")) return; for(int i = 0; i < args.length; i++){ if(args[i] instanceof LogVO){ log.info开始写入日志......"); writeLog((LogVO)args[i]); } } } private void writeLog(LogVO vo){ try { vo.setDescription(vo.getDescription() + "失败!"); logThrowService.saveLog(vo); } catch (RuntimeException e) { log.error(e); } } public void setLogThrowService(LogService logThrowService) { this.logThrowService = logThrowService; }
上面代码已经很好的说明了,如果发生exception的话,日志是怎么记录的,这里要提到的一点的是,异常的处理稍微有一些复杂,就拿本例的代码能看出 来,只要在service层有异常的时候,都会记录失败日志,实际上,很多时候,未必是这样,在某个模块,可能需要定义一种特殊的异常,而一旦这种异常发 生,则需要进入另外一个流程或者做一些特殊的处理,这个时候需要根据具体情况做一些变更,比如在上面代码我们加上:
public void afterThrowing(Method method,Object[] args,Object target,OrderException e) throws Throwable { log.info("......"); //do something }
则如果OrderException被抛出,就会到此方法中执行,而不会去写日志。
--------------------------------------------------------------------------------
其中的封装方式虽然一般,但是还是比较好的解决了问题!对于LogVO类我们可以把他继续扩展下去,比如设定访问用户,IP,seq文等.
reference:http://www.360doc.com/editart2.aspx?articleid=271503637
**************
spring AOP 是基于面向切面的编程,它能够使得我们专注于我们的业务处理,将一些其他的东西由它来统一完成,程序的侵入性很小,所以被广泛应用,至于实现原理我就不多说了,两个字:"代理"!
下面说说标题所示的应用,记录日志,什么时候记录日志,都记录什么?想想,可不 就是在调用方法的时候写日志嘛,之前如果使用logger的话,都会在方法的开始写一个logger.info("xxxxxxxxxxxx");结束的 时候再写一个,这不是很麻烦吗,每次都要写。实际上这个时候我们就可以用aop来做,当方法进入的时候写一条日志,结束的时候再写一条,分别对应“前置通 知”和”后置通知“,如果我们都日志有新的写法,值需要修改控制日志的这个类,对程序没有丝毫影响,也就谈不上改动大量的代码了。下面开始:
1.引入aop的命名空间(其中有AOP的那部分):
<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" 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">
2.书写记录日志的类:
package com.yjck.fm.util; import org.apache.log4j.Logger; import org.aspectj.lang.JoinPoint; public class LogUtil { Logger logger = Logger.getLogger(LogUtil.class); public void logAll(JoinPoint jp){ String methodName = jp.getSignature().getName(); logger.info(jp.getTarget().getClass().getName()+"---"+methodName); Object[] args = jp.getArgs(); for(int i=0;i<args.length;i++){ logger.info("params["+i+"]:"+ args[i].toString()); } } }
上面这段代码实现了输出要调用的类名,方法已经参数。
3.配置xml文件:
<!-- 日志管理aop --> <!-- 强制使用cglib代理,如果不设置,将默认使用jdk的代理,但是jdk的代理是基于接口的 --> <aop:config proxy-target-class="true" /> <aop:config> <aop:aspect id="myAspect" ref="logUtil"> <aop:pointcut expression="execution(* com.yjck.fm.*.action.*.*(..))" id="logPointCut"/> <aop:before method="logAll" pointcut-ref="logPointCut"/> </aop:aspect> </aop:config> <!-- 日志记录类 --> <bean id="logUtil" class="com.yjck.fm.util.LogUtil"></bean>
注意:我这里配置的是拦截所有action的所有方法,可以根据自己的情况配置,同时也只配了一个”前置通知“before,如果要需要还可以配置其他的。
实现已经完毕了!
*****************
首先,需要将log4j先配置好在web.xml中加入解析器servlet的配置
<context-param> <param-name>log4jConfigLocation</param-name> <param-value>/WEB-INF/classes/log4j.properties</param-value> </context-param> <servlet> <servlet-name>log4j</servlet-name> <servlet-class> org.springframework.web.util.Log4jConfigServlet </servlet-class> <load-on-startup>2</load-on-startup> </servlet> <listener> <listener-class> org.springframework.web.util.Log4jConfigListener </listener-class> </listener>
之后,由于我项目当中配置了大量的service类,类名都以Service结尾,为了方便配置使用spring当中的BeanNameAutoProxyCreator类进行aop配置。
在spring配置文件中配置如下:
<bean class="cn.aresoft.fw.log.LoggerAdvice" id="loggerAdvice"/> <bean class= "org.springframework.aop.framework .autoproxy.BeanNameAutoProxyCreator" > <!-- 始终以CGLib技术动态代理--> <!-- <property name="optimize"><value>true</value></property> --> <!-- 配置开关 这句不加getBean()方法获得bean是会报类型转换异常--> <property name="proxyTargetClass"><value>true</value></property> <property name="interceptorNames"> <list> <value>loggerAdvice</value> </list> </property> <property name="beanNames"> <list> <value>*Service</value> </list> </property> </bean>
再来就是写Advice类了也就是配置中的LoggerAdvice,代码如下:
public class LoggerAdvice implements MethodBeforeAdvice, AfterReturningAdvice,ThrowsAdvice { public void before(Method method, Object[] args, Object target)throws Throwable { Logger logger = Logger.getLogger(target.getClass()); logger.debug("+Class : "+ target.getClass().getName()); logger.debug("+Method : "+ method.getName()); } public void afterReturning(Object retuVal, Method method, Object[] args,Object target) throws Throwable { Log log = LogFactory.getLog(target.getClass()); //do log } public void afterThrowing(Method method,Object[] args, Object target,Exception ex){ Logger logger = Logger.getLogger(target.getClass()); logger.error("数据处理时发生异常",ex); } }
http://www.weishuzhai.com/learn-spring-part-three/
*********************************************************************
注解方式---spring的AOP拦截用户操作
配置文件:
<!-- 操作日志切面声明 --> <bean id="logAspect" class="com.tq365.service.sys.log.SystemLogAspect"/> <aop:config> <aop:aspect ref="logAspect"> </aop:aspect> </aop:config>
实现代码:
/** * 系统操作日志切面 * * @author archie2010 * since 2011-3-17 下午02:44:03 */ @Aspect public class SystemLogAspect { // int与long之Class会自动转为其封装类型之Class private static final String integerClazz = "class java.lang.Integer"; private static final String longClazz = "class java.lang.Long"; @Resource private SystemLogService systemLogService; private Logger logger = Logger.getLogger(this.getClass().getName()); @Pointcut("execution(* com.tq365.service..*.*(..))") public void myAspect() { }; @AfterThrowing(pointcut = "myAspect()", throwing = "e") public void doAfterThrowing(JoinPoint jp, Throwable e) { System.out.println("出现异常:" + e.getMessage()); System.out.println(e.getClass().getName()); System.out.println("异常所在类:" + jp.getTarget().getClass().getName()); System.out.println("" + jp.getSignature().getName() + "方法 throw exception"); // logger.error("错误! error级别的!!!"+e.getMessage()); logger.error("Oops===" + jp.getTarget().getClass().getName() + "中的" + jp.getSignature().getName() + "方法抛出" + e.getClass().getName() + "异常"); System.out.println("参数:"); ; if (jp.getArgs() != null && jp.getArgs().length > 0) { for (int i = 0; i < jp.getArgs().length; i++) { System.out.println(jp.getArgs()[i].toString()); logger.error("参数:--" + jp.getArgs()[i].toString()); } } } @SuppressWarnings("unchecked") @After("@annotation(com.tq365.sys.annotation.SystemLogAnnotation)") public void doAfter(JoinPoint jp) { System.out.println("----------后置通知"); System.out.println("方法所在类:" + jp.getTarget().getClass().getName()); System.out.println("" + jp.getSignature().getName() + "方法"); String methodName = jp.getSignature().getName(); // 操作日志对象----------------- SystemLog sysLog = new SystemLog(); // 操作参数----------------- String descArgs = "参数"; if (jp.getArgs() != null && jp.getArgs().length > 0) { for (int i = 0; i < jp.getArgs().length; i++) { if(jp.getArgs()[i]!=null){ //System.out.println(jp.getArgs()[i].toString()); descArgs += jp.getArgs()[i].toString()+","; }else{ descArgs +="null"+","; } } System.out.println("------参数" + descArgs); } sysLog.setOperateArgs(descArgs); String des = null;//方法描述 if (!(methodName.startsWith("set") || methodName.startsWith("get"))) { Class targetClass = jp.getTarget().getClass(); //方法不定向参数Clazz... Class[] claszs = new Class[jp.getArgs().length]; for (int i = 0; i < jp.getArgs().length; i++) { //System.out.println(jp.getArgs()[i]); if(jp.getArgs()[i]!=null){ System.out.println(jp.getArgs()[i].getClass()); if (jp.getArgs()[i].getClass().toString().equals(integerClazz)) { claszs[i] = int.class; } else if (jp.getArgs()[i].getClass().toString().equals( longClazz)) { claszs[i] = long.class; }else{ claszs[i] =jp.getArgs()[i].getClass(); } }else if(jp.getArgs()[i]==null){ claszs[i] = String.class; } } Method method=null; try { method = targetClass.getMethod(methodName, claszs); } catch (SecurityException e) { } catch (NoSuchMethodException e) { } //若方法为空(描述无法获得则des=null) if(method!=null){ System.out.println(method.getAnnotation(SystemLogAnnotation.class) .description()); des = method.getAnnotation(SystemLogAnnotation.class).description(); } } // 获得Session HttpSession session = ServletActionContext.getRequest().getSession(); // 取到当前的操作用户 User appUser = (User) session.getAttribute("USER"); if (appUser != null) { System.out.println("用户已经存在Session中"); // 操作日志对象 sysLog.setUid(appUser.getUserId()); sysLog.setUsername(appUser.getFullName()); } HttpServletRequest request = ServletActionContext.getRequest(); String ip = request.getRemoteAddr(); sysLog.setOperateTime(DateUtil.getCurrentTime()); sysLog.setOperateDes(methodName +"->"+ des); sysLog.setIp(ip); systemLogService.save(sysLog); System.out.println("----------保存操作日志"); } }
**************************************************************************
xml方式---spring的AOP拦截用户操作
需要日志记录,将所有的web操作记录到数据库中,使用aop来记录日志,当然是一个好的选择,spring中集成aop记录日志的方式有多种(aop的配置方式有多种,注解、xml配置),这里只说一个xml配置的例子。
1、编写日志记录类
2、配置aop
1、编写日志记录类
@SuppressWarnings("unchecked") public class LogService { public void logAll(JoinPoint jp){ System.out.println("in LogService, method logAll invoked."); System.out.println("========================"); StringBuilder sb = new StringBuilder(); sb.append("method:" + jp.getSignature().getName()); HttpServletRequest request = ServletActionContext.getRequest(); Iterator<Entry<String, Object>> iter = request.getParameterMap().entrySet().iterator(); boolean isFirst = true; sb.append(" paras:"); while(iter.hasNext()){ Entry<String, Object> entry = iter.next(); if(isFirst){ isFirst = false; }else{ sb.append("#"); } sb.append(entry.getKey() + "="); Object[] allValue = (Object[]) entry.getValue(); for(int i = 0; i < allValue.length; i++){ if(i != 0){ sb.append(","); } sb.append(allValue[i].toString()); } } System.out.println(sb.toString()); System.out.println("========================"); } }
2、配置aop
在applicationContext.xml中配置
</aop:config> <bean id="logService" class="com.cjnetwork.cms.service.LogService"></bean> <aop:config> <aop:aspect id="myAspect" ref="logService"> <aop:pointcut expression="execution(* com.cjnetwork.cms.action.*.*(..))" id="logPointCut"/> <aop:before method="logAll" pointcut-ref="logPointCut"/> </aop:aspect> </aop:config> <bean id="logService" class="com.cjnetwork.cms.service.LogService"></bean> <aop:config proxy-target-class="true" />
基本配置就是这样的,这里需要配置<aop:config proxy-target-class="true" /> ,表示强制使用cglib代理,而不是java本身的代理,这个很重要,如果使用java自带的代理,则会抛出异常,提示说代理类无法转换为我们自己的类,这是因为默认的该属性为false,这种代理方式,需要实现接口的方式,代理返回的类可以转换为对应的接口类,但无法直接转换为类的实现,这种方式不推荐。
reference:http://blog.csdn.net/johnjobs/article/details/8667646
**********************************************************************************
**********************************************************************************
如果要在方法执行前或后或抛出异常后加上一个自己的拦截器,或者一个环绕拦截器,在拦截器中执行一些操作,比如执行一些数据库操作,记录一些信 息,这些操作通过调用一个服务类的方法来执行,这个方法也在spring事务管理拦截器的管理之下,那么这个记录方法需要在另一个事务中进行,而不是与被 拦截方法在同一个事务中,不然如果被拦截方法抛出异常需要回滚时,所作的记录也会被回滚,当然有时候确实需要同时回滚,那就要放在同一个事务中。
这和自己的拦截器和事务管理的拦截器的执行顺序有一定关系,spring事务管理拦截器是一个环绕通知,在被拦截方法执行前启动事务,执行后完成 事务,如果自己的拦截器被spring事务管理拦截器包围在里面,那么在自己的拦截器运行时,spring已经启动了一个事务,如果你的记录信息方法需要 与被拦截方法同在一个事务中,将你的记录信息方法的事务传播属性设为默认的REQUIRED就可以了;
如果你记录信息的方法需要单独的一个事务环境,那就要把事务传播属性设为REQUIRES_NEW了,这样spring事务管理器会新建一个事 务,并且新建一个session连接,因为一个数据库连接不可能同时有两个事务,记录信息完了提交事务并且把新建的session连接关闭,自己的拦截器 退出后继续执行被拦截的方法或它的事务处理。
相反如果自己的拦截器在spring事务管理拦截器的外面,那么记录信息的方法会在一个单独的事务中执行,并提交,不管它的事务传播属性是 REQUIRES_NEW还是REQUIRED,因为与被拦截方法的事务处理没有交叉,并且可以使用同一个session连接如果是 OpenSessionInViewFilter。
所以如果记录信息和被拦截方法要在不同事务中执行,分别提交,那么最好将自己的拦截器设在spring事务管理器拦截器的外面;如果需要将记录信 息和被拦截方法在同一个事务中处理,必须将自己的拦截器被包围在spring事务管理拦截器中,并且记录信息方法的事务传播属性为默认的 REQUIRED。
设置拦截器的执行顺序可以让拦截器处理类实现org.springframework.core.Ordered接口,在spring配置文件的 AOP设置中设定自己的拦截器和spring事务管理拦截器的执行顺序,将自己的拦截的序号排在spring事务管理的前面,就可以将该拦截器放到事务管 理拦截器的外面执行了,对于before通知方式会先于事务管理拦截器执行,对于after returning和after和after throwing通知方式会后于事务管理拦截器的执行,对于arount通知方式会包围事务管理拦截器执行。
下面是一个异常拦截器的例子。
有位朋友提到在spring异常拦截器中更新数据不能够提交,做了一下测试,测试环境基本是这样:一个用户登录的功能,spring对 service中的每个方法进行事务管理,在用户检测的service方法上同时加上一个异常拦截器,当用户不存在或密码不正确时用户检测方法会抛出异 常,异常拦截器捕获到该异常,同时记录一些日志。
spring配置文件相关:
<!-- 事务管理 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <!-- 事务通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="get*" read-only="true"/> <tx:method name="*" propagation="REQUIRES_NEW" rollback-for="Exception"/> </tx:attributes> </tx:advice> <!-- aop代理设置 --> <aop:config proxy-target-class="true"> <aop:pointcut id="txPointcut" expression="execution(* com.hbs..*Service.*(..))"/> <aop:pointcut id="logPointcut" expression="execution(* com.hbs.customer..*Service.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" order="1"/> <aop:aspect id="logAspect" ref="logInterceptor" order="2" > <aop:after-throwing pointcut-ref="logPointcut" method="serviceIntercept" /> </aop:aspect> </aop:config> <!-- log拦截器类 --> <bean id="logInterceptor" class="com.hbs.eventlog.EventLogInterceptor"> <property name="service" ref="logService"></property> </bean>
service方法中的事务传播属性都设为要求新建事务,spring事务管理切面拦截器的order设为1,而log拦截器的order设为2,这意味 着这两个要同时执行时,先执行事务拦截器,后执行log拦截器,由于事务管理是一个环绕通知(around),实际上是log拦截器被包围在事务管理拦截 器中。
从中可以看出,log异常拦截器在用户登录的事务回滚之前截获异常,在记录日志时,日志记录的service方法也在spring的事务管理之 下,用户登录的事务还没有结束,根据REQUIRES_NEW特性,spring会新开一个事务,这时原来的数据库连接已经在一个事务中,一个连接不可能 同时有两个事务,所以同时新创建一个session连接(虽然我使用了OpenSessionInViewFilter,并且session是单例的), 日志记录就在新建的事务和session中进行,完了提交,并且会把新建的session连接关闭。
然后继续进行被中断的用户登录的事务管理操作,由于抛异常spring将用户登录的事务回滚。
这样能够实现预想的功能,但是如果我去掉指定的REQUIRES_NEW,那么log记录的操作会继续在用户登录的事务中进行,最后会被一起回滚。
如果把事务管理的order设为2,log拦截器的order设为1,也就是log拦截器在事务管理拦截器的外面,会在事务管理拦截器前后执行完了再执行log的异常拦截器。
可以看出,用户登录的事务和日志记录的事务是前后两个不相关的事务,并且在日志记录事务中并不需要新建session连接,而是直接用在 OpenSessionInViewFilter中创建的session。实际上这时也并不需要将propagation设为REQUIRES_NEW, 使用默认的REQUIRES也照样能够正常工作。
所以应该将该异常拦截器设在事务管理拦截器的外面,即使用Order接口排在前面。
reference:http://blog.csdn.net/zmhinzaghi/article/details/7091795
评论
3 楼
di1984HIT
2014-04-24
这里面提到了好几种解决办法。
2 楼
迪伦少校
2013-12-27
能否将你的代码共享一下看看呢?不胜感激!
1 楼
Jekey
2013-07-30
发表评论
-
Replace constructor-arg by annotation
2013-05-24 04:34 1103replace constructor-arg by anno ... -
spring struts2 零配置
2013-05-23 18:04 6861.ssh(struts2.3.8+spring3.2+hei ... -
使用Spring进行统一日志管理 + 统一异常管理
2013-03-15 16:23 1228使用Spring进行统一日志管理 + 统一异常管理 统一日志 ... -
Spring 配置(事务和日志)
2013-03-15 16:11 1851Spring的那些配置(事务和日志) Spring整合Iba ... -
Spring 自定义注解实现操作日志记录功能
2013-03-15 09:55 2345Spring 自定义注解实现操作日志记录功能 最近项目组长分 ... -
Struts2防止表单重复提交
2013-03-14 10:18 916Struts2防止表单重复提交 最近开发中涉及到了表单重复提 ... -
Spring事务配置的五种方式
2013-03-05 10:08 736Spring事务配置的五种方式 前段时间对Spring的事 ... -
spring 异常与事务
2013-03-01 11:21 1829Service层捕获异常,并抛出RuntimeExceptio ... -
如何将基于 Struts、Spring 和 Hibernate 的应用从 Tomcat 迁移到 WebSphere Application Server
2012-12-21 10:28 1191引言 现在很多的企业都 ... -
Spring 事务管理高级应用难点剖析: 第 3 部分
2011-04-26 17:29 804Spring 事务管理高级应用 ... -
Spring 事务管理高级应用难点剖析: 第 2 部分
2011-04-26 17:20 924Spring 事务管理高级应用 ... -
Spring 事务管理高级应用难点剖析: 第 1 部分
2011-04-26 17:05 799Spring 事务管理高级应用难点剖析: 第 1 部分 简介 ...
相关推荐
本节将详细介绍如何使用Spring AOP实现流程日志跟踪,主要关注于如何通过AOP拦截特定的类和方法来进行日志记录。 ##### 3.1 配置Spring AOP 在Spring配置文件中定义切面和切入点表达式是非常关键的一步。一般来说...
使用Spring AOP进行日志记录不仅可以提供对方法调用的详细信息,还可以帮助追踪代码执行流程,调试问题,以及监控系统性能。此外,Spring AOP还可以与其他通知类型一起使用,如after advice(在方法执行后运行)、...
在Spring框架中,AOP(面向切面编程)是一种强大的工具,它允许程序员将关注点分离,例如日志记录、事务管理、权限检查等,从核心业务逻辑中解耦出来。本篇主要探讨的是如何利用Spring AOP的注解来实现这些功能,...
Spring AOP,全称Aspect-Oriented Programming(面向切面编程),是Spring框架的重要组成部分,它为应用程序提供了声明式的企业级服务,如日志、事务管理等。在本项目中,我们将探讨如何通过配置文件实现Spring AOP...
在Spring Boot应用中,AOP(面向切面编程)是一种强大的工具,用于实现代码的解耦和模块化,尤其适用于处理横切关注点,如日志记录、事务管理、安全控制等。本教程将深入探讨如何利用Spring Boot的AOP特性来实现日志...
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种强大的方式来实现代码的横切关注点,如日志记录、事务管理、性能监控等。在这个"spring aop API示例"中,我们将深入探讨如何利用Spring AOP的四...
在实际开发中,Spring AOP广泛应用于日志记录、事务管理、性能监控等方面。例如,可以通过声明式方式定义切面,实现事务的自动管理: ```java @Aspect @Component public class TransactionAspect { @Around(...
在Spring MVC框架中,AOP通常用于实现日志记录、事务管理、性能监控等功能。本篇文章将深入探讨如何在Spring MVC中配置和使用基于注解的AOP。 一、Spring AOP基础知识 1. **切面(Aspect)**:切面是关注点的模块...
在Spring框架中,AOP(面向切面编程)是一种强大的设计模式,它允许开发者将关注点分离,将横切关注点(如日志、事务管理)从核心业务逻辑中解耦出来。本篇我们将深入探讨如何使用注解的方式来实现Spring AOP开发。 ...
### Spring框架+SpringAOP动态代理 #### 一、Spring AOP 动态代理概述 在探讨Spring AOP(Aspect-Oriented Programming,面向切面编程)中的动态代理之前,我们首先简要回顾一下AOP的基本概念。面向切面编程是一种...
Spring注解AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的一个重要特性,它使得开发者可以在不修改原有代码的情况下,通过添加注解来实现横切关注点,如日志、事务管理等。下面我们将深入探讨...
由于Spring容器管理着所有对象,因此可以在任何需要的地方应用AOP,无需对原始代码做过多改动。同时,AOP可以和Spring的其他特性如声明式事务管理结合使用,使得事务处理更加便捷。 总结来说,Spring AOP提供了一种...
Spring AOP是Spring框架的一部分,它允许开发者在不修改源代码的情况下,对应用程序中的特定行为进行横切关注点的处理,如日志记录、事务管理、安全性检查等。AOP通过切面(Aspect)和通知(Advice)的概念,实现了...
在Spring框架中,AOP(面向切面编程)是一种强大的设计模式,它允许开发者将关注点分离,将横切关注点(如日志、事务管理、权限检查等)与核心业务逻辑解耦。本篇文章将深入探讨Spring AOP中的5种增强方法,以及如何...
AOP是Spring框架提供的一种强大的功能,它允许我们在不修改源代码的情况下,对应用程序进行横向关注点的插入,如日志记录、事务管理、性能监控等。在描述中提到的“进行日志记录”就是AOP的一个典型应用。 日志记录...
在Spring MVC框架中,AOP(面向切面编程)是一种强大的工具,允许我们在不修改源代码的情况下,插入横切关注点,例如日志记录、事务管理等。本篇将深入探讨如何利用AOP和自定义注解来实现日志记录功能。 首先,我们...
在本文中,我们将探讨如何使用 Spring AOP 实现日志管理,并使用自定义注解方式来记录日志信息。这种方式可以灵活地实现日志管理,提高系统的可维护性和可扩展性。 首先,我们需要在 applicationContext-mvc.xml ...
在本案例中,"aop+exception"的测试代码可能涉及到如何在Spring框架中使用AOP来处理异常。 首先,让我们深入了解一下AOP。Spring AOP是Spring框架的一个重要组成部分,它允许开发者定义“切面”,即跨越多个对象的...
Spring AOP,全称为Aspect Oriented Programming(面向切面编程),是Spring框架的重要组成部分,它为应用程序提供了一种模块化和声明式的方式来处理交叉关注点,如日志、事务管理、性能监控等。AOP的核心概念是切面...
AOP是Spring框架的核心特性,它允许我们在不修改业务代码的情况下,通过“切面”(aspect)来插入额外的功能,如日志、安全检查和事务管理。在Spring中,AOP主要是通过代理模式实现的,有JDK动态代理和CGLIB两种方式...