Spring AOP对日志记录、Exception日志记录等等
本文来自 http://www.javaeye.com/topic/71996
本人感觉还是很有借鉴意义,所以在此贴出,加以评论!
原文如下:
---------------------------------------------------------------------
利用spring aop对日志进行管理,还是采用对比的方式进行,
1. try {
2. employeInfoManageService.saveEmploye(vo, authForm.getLoginName());
3.
4. LogVO logVO = new LogVO(Constants.LOG_LEVEL_INFO,
5. Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName()
6. + "增加员工成功!");
7. logService.saveLog(logVO);
8. } catch (Exception e) {
9. log.error(e);
10. LogVO logVO = new LogVO(Constants.LOG_LEVEL_ERROR,
11. Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName()
12. + "增加员工失败!");
13. try {
14. logService.saveLog(logVO);
15. } catch (Exception e1) {
16. log.error(e1);
17. return messageForward("error", "alert.db.exception",
18. new Object[] {}); }
19. }
1. LogVO logVO = new LogVO(Constants.LOG_LEVEL_INFO,
2. Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName()
3. + "增加员工");
4. try {
5. employeInfoManageService.saveEmploye(vo, authForm.getLoginName(), logVO);
6. } catch (Exception e) {
7. log.error(e);
8. return messageForward("error", "alert.db.exception",
9. new Object[] {});
10. }
既然是应用到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的代码:
1. public void afterReturning(Object returnObj, Method method, Object[] args,
2. Object targetObj) throws Throwable {
3. if(method.getName().equals("saveLog")) return;
4. for(int i = 0; i < args.length; i++){
5. if(args[i] instanceof LogVO){
6. log.info("开始写入日志......");
7. writeLog((LogVO)args[i]);
8. }
9. }
10. }
11.
12. private void writeLog(LogVO vo){
13. try {
14. vo.setDescription(vo.getDescription() + "成功!");
15. logService.saveLog(vo);
16. } catch (RuntimeException e) {
17. log.error(e);
18. }
19.
20. public void setLogService(LogService logService) {
21. this.logService = logService;
22. }
1. public void afterThrowing(Method method,Object[] args,Object target,Exception e) throws Throwable {
2. if(method.getName().equals("saveLog")) return;
3. for(int i = 0; i < args.length; i++){
4. if(args[i] instanceof LogVO){
5. log.info开始写入日志......");
6. writeLog((LogVO)args[i]);
7. }
8. }
9. }
10.
11. private void writeLog(LogVO vo){
12. try {
13. vo.setDescription(vo.getDescription() + "失败!");
14. logThrowService.saveLog(vo);
15. } catch (RuntimeException e) {
16. log.error(e);
17. }
18. }
19.
20. public void setLogThrowService(LogService logThrowService) {
21. this.logThrowService = logThrowService;
22. }
1. public void afterThrowing(Method method,Object[] args,Object target,OrderException e) throws Throwable {
2. log.info("......");
3. //do something
4. }
则如果OrderException被抛出,就会到此方法中执行,而不会去写日志。
--------------------------------------------------------------------------------
其中的封装方式虽然一般,但是还是比较好的解决了问题!对于LogVO类我们可以把他继续扩展下去,比如设定访问用户,IP,seq文等.
本人感觉还是很有借鉴意义,所以在此贴出,加以评论!
原文如下:
---------------------------------------------------------------------
利用spring aop对日志进行管理,还是采用对比的方式进行,
修改前:
偶们的做法是在action里记录日志,注意这个日志是面向用户的日志,姑且称它为业务日志,至于后台日志,则在此文章中暂不考虑,基本是通过log4j打印到后台日志文件中。看下面一段代码:
1. try {
2. employeInfoManageService.saveEmploye(vo, authForm.getLoginName());
3.
4. LogVO logVO = new LogVO(Constants.LOG_LEVEL_INFO,
5. Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName()
6. + "增加员工成功!");
7. logService.saveLog(logVO);
8. } catch (Exception e) {
9. log.error(e);
10. LogVO logVO = new LogVO(Constants.LOG_LEVEL_ERROR,
11. Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName()
12. + "增加员工失败!");
13. try {
14. logService.saveLog(logVO);
15. } catch (Exception e1) {
16. log.error(e1);
17. return messageForward("error", "alert.db.exception",
18. new Object[] {}); }
19. } 
这段代码实际上已经将写日志的过程封装起来,开发者只需要传入3个参数:操作者、是前台系统还是后台系统、以及日志的错误等级,其它的如操作者机器IP, 日志时间等信息由系统统一设定,即使是这样,如果一个action里面有多个操作,代码看起来也非常臃肿,而且给开发者增加了工作量,既然有了aop,为 什么不利用一下?看下面改造的代码:
1. LogVO logVO = new LogVO(Constants.LOG_LEVEL_INFO,
2. Constants.LOG_TYPE_BACK, "用户:" + authForm.getLoginName()
3. + "增加员工");
4. try {
5. employeInfoManageService.saveEmploye(vo, authForm.getLoginName(), logVO);
6. } catch (Exception e) {
7. log.error(e);
8. return messageForward("error", "alert.db.exception",
9. new Object[] {});
10. } 
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"/> 
1. public void afterReturning(Object returnObj, Method method, Object[] args,
2. Object targetObj) throws Throwable {
3. if(method.getName().equals("saveLog")) return;
4. for(int i = 0; i < args.length; i++){
5. if(args[i] instanceof LogVO){
6. log.info("开始写入日志......");
7. writeLog((LogVO)args[i]);
8. }
9. }
10. }
11.
12. private void writeLog(LogVO vo){
13. try {
14. vo.setDescription(vo.getDescription() + "成功!");
15. logService.saveLog(vo);
16. } catch (RuntimeException e) {
17. log.error(e);
18. }
19.
20. public void setLogService(LogService logService) {
21. this.logService = logService;
22. } 
这段代码应该很清楚了,将logService注入到拦截log的advice里,进行正确操作的日志记录,而afterReturning方法里 的第一行判断是由于logService里的写日志的方法是以save开始的。所以,如果拦截器拦截到此方法,不需要记录日志。
正确的日志记录完,当然如果发生异常,我们需要记录操作的失败日志,当然了,我们也是通过aop来做,但是这次是通过实现exception advice来实现,代码如下:
1. public void afterThrowing(Method method,Object[] args,Object target,Exception e) throws Throwable {
2. if(method.getName().equals("saveLog")) return;
3. for(int i = 0; i < args.length; i++){
4. if(args[i] instanceof LogVO){
5. log.info开始写入日志......");
6. writeLog((LogVO)args[i]);
7. }
8. }
9. }
10.
11. private void writeLog(LogVO vo){
12. try {
13. vo.setDescription(vo.getDescription() + "失败!");
14. logThrowService.saveLog(vo);
15. } catch (RuntimeException e) {
16. log.error(e);
17. }
18. }
19.
20. public void setLogThrowService(LogService logThrowService) {
21. this.logThrowService = logThrowService;
22. } 
上面代码已经很好的说明了,如果发生exception的话,日志是怎么记录的,这里要提到的一点的是,异常的处理稍微有一些复杂,就拿本例的代码能看出 来,只要在service层有异常的时候,都会记录失败日志,实际上,很多时候,未必是这样,在某个模块,可能需要定义一种特殊的异常,而一旦这种异常发 生,则需要进入另外一个流程或者做一些特殊的处理,这个时候需要根据具体情况做一些变更,比如在上面代码我们加上:
1. public void afterThrowing(Method method,Object[] args,Object target,OrderException e) throws Throwable {
2. log.info("......");
3. //do something
4. } 
--------------------------------------------------------------------------------
其中的封装方式虽然一般,但是还是比较好的解决了问题!对于LogVO类我们可以把他继续扩展下去,比如设定访问用户,IP,seq文等.


浙公网安备 33010602011771号