在java开发中日志的管理有很多种。我一般会使用过滤器,或者是Spring的拦截器进行日志的处理。如果是用过滤器比较简单,只要对所有的.do提交 进行拦截,然后获取action的提交路径就可以获取对每个方法的调用。然后进行日志记录。使用过滤器的好处是可以自己选择性的对某一些方法进行过滤,记 录日志。但是实现起来有点麻烦。


另外一种就是使用Spring的AOP了。这种方式实现起来非常简单,只要配置一下配置文件就可以了。可是这种方式会拦截下所有的对action的 每个操作。使得效率比较低。不过想做详细日志这个方法还是非常好的。下面我就介绍一下使用Spring AOP进行日志记录的方式。

第一种。Spring AOP对普通类的拦截操作

首先我们要写一个普通类,此类作为日志记录类。 比如

1.  package chen.hui.log   
2.     
3.  public classs MyLog{   
4.         //在类里面写方法,方法名诗可以任意的。此处我用标准的before和after来表示   
5.        public void before(){   
6.                  System.out.println("被拦截方法调用之前调用此方法,输出此语句");   
7.        }   
8.        public void after(){   
9.                    System.out.println("被拦截方法调用之后调用此方法,输出此语句");   
10.        }   
11.  }




其次我们在写一个类作为被拦截类(Spring的AOP就是拦截这个类里面的方法)

1.  package chen.hui.log   
2.     
3.  public class Test{//此类中方法可以写任意多个。我只写一个   
4.            public void test(){   
5.                  Sytem.out.println("测试类的test方法被调用");   
6.            }   
7.  }



最后进行配置文件的编写。在Spring的配置文件中我们需要进行几句话的配置


1.  <bean id="testLog" class="chen.hui.log.MyLog"></bean> <!--将日志类注入到bean中。-->   
2.  <aop:config>   
3.      <aop:aspect id="b" ref="testLog"><!--调用日志类-->   
4.          <aop:pointcut id="log" expression="execution(* chen.hui.log.*.*(..))"/><!--配置在log包下所有的类在调用之前都会被拦截-->   
5.          <aop:before pointcut-ref="log" method="before"/><!--在log包下面所有的类的所有方法被调用之前都调用MyLog中的before方法-->   
6.          <aop:after pointcut-ref="log" method="after"/>><!--在log包下面所有的类的所有方法被调用之前都调用MyLog中的after方法-->   
7.      </aop:aspect>   
8.  </aop:config>



到此处整个程序完成,在MyLog类里面的before和after方法添加日志逻辑代码就可以完成日志的管理。以上是对普通类的管理,如果只想拦截某一个类。只要把倒数第二个 *  改成类名就可以了。

  第二:使用Spring AOP对action做日志管理

如果是想拦截action对action做日志管理,基本和上面差不多,但是要注意。以下几点

首先还是要写一个普通类,不过此类中的方法需要传入参数。 比如

1.  package chen.hui.log   
2.     
3.  import org.aspectj.lang.JoinPoint;   
4.     
5.  public classs MyLog{   
6.     
7.         //在类里面写方法,方法名诗可以任意的。此处我用标准的before和after来表示   
8.     
9.          //此处的JoinPoint类可以获取,action所有的相关配置信息和request等内置对象。   
10.     
11.        public void before(JoinPoint joinpoint){   
12.     
13.                  joinpoint.getArgs();//此方法返回的是一个数组,数组中包括request以及ActionCofig等类对象   
14.     
15.                  System.out.println("被拦截方法调用之前调用此方法,输出此语句");   
16.        }   
17.        public void after(JoinPoint joinpoint){   
18.     
19.                    System.out.println("被拦截方法调用之后调用此方法,输出此语句");   
20.        }   
21.  }



其次我们在写一个action类作为被拦截类(Spring的AOP就是拦截这个类里面的方法)


1.  package chen.hui.log   
2.     
3.  public class LoginAction{//此类中方法可以写任意多个。我只写一个   
4.      public void test(){   
5.          Sytem.out.println("测试类的test方法被调用");   
6.      }   
7.  }



最后进行配置文件的编写。在Spring的配置文件中我们需要进行几句话的配置


1.  <bean id="testLog" class="chen.hui.log.MyLog"></bean> <!--将日志类注入到bean中。-->   
2.        <aop:config>   
3.              <aop:aspect id="b" ref="testLog"><!--调用日志类-->   
4.              <aop:pointcut id="log" expression="execution(* chen.hui.log.*.*(..))"/><!--配置在log包下所有的类在调用之前都会被拦截-->   
5.              <aop:before pointcut-ref="log" method="before"/><!--在log包下面所有的类的所有方法被调用之前都调用MyLog中的before方法-->   
6.              <aop:after pointcut-ref="log" method="after"/><!--在log包下面所有的类的所有方法被调用之前都调用MyLog中的after方法-->   
7.        </aop:aspect>   
8.   </aop:config>
  1.  



除了参数外其他地方基本和普通类相似。

需要注意的是:普通类可以监控单一的类,而action在配置文件中只能到包名而不能到action的类名。不然会报错。就是说如果要记录日志就要记录所有的action而不能记录其中一个,这是我试了好久得出的结果。



前几天做项目时,在做系统日志这一块,都是在每个方法里手写代码来添加,觉得很繁琐,考虑到spring有aop的功能,便寻思着用AOP来做这个日志功能。

首先需要传入日志记录的具体操作名称,我们可以用java的注解功能来带入参数,代码如下:

 



Java代码  

java 日志pom java aop日志_runtime


1.  /**  
2.   * 类的方法描述注解  
3.   * @author LuoYu  
4.   */   
5.  @Target (ElementType.METHOD)   
6.  @Retention(RetentionPolicy.RUNTIME)   
7.  @Documented   
8.  @Inherited   
9.  public @interface Log {   
10.     
11.      /** 要执行的操作类型比如:add操作 **/   
12.      public String operationType() default "";   
13.        
14.      /** 要执行的具体操作比如:【添加仓库】 **/   
15.      public String operationName() default "";   
16.        
17.  }


 

 注解类编写好之后,就要考虑spring我切面的问题目了,首先我们要创建一个切点,也就是需要插入的代码块,代码如下:


Java代码  

java 日志pom java aop日志_java_02


1.  /**  
2.   * 通过Spring AOP来添加系统日志  
3.   * @author LuoYu  
4.   */   
5.  public class LogAspect extends BaseAction{   
6.     
7.      private static final long serialVersionUID = -5063868902693772455L;   
8.     
9.      private Log logger = LogFactory.getLog(LogAspect.class);   
10.        
11.      @SuppressWarnings( { "rawtypes", "unchecked" } )   
12.      public void doSystemLog(JoinPoint point) throws Throwable {    
13.          Object[] param = point.getArgs();   
14.          Method method = null;   
15.          String methodName = point.getSignature().getName();    
16.          if (!(methodName.startsWith("set") || methodName.startsWith("get")||methodName.startsWith("query"))){   
17.              Class targetClass = point.getTarget().getClass();    
18.              method = targetClass.getMethod(methodName, param[0].getClass());   
19.              if (method != null) {   
20.                  boolean hasAnnotation = method.isAnnotationPresent(com.tlj.pcxt.common.logaop.Log.class);    
21.                  if (hasAnnotation) {   
22.                      com.tlj.pcxt.common.logaop.Log annotation = method.getAnnotation(com.tlj.pcxt.common.logaop.Log.class);    
23.                      String methodDescp = annotation.operationType()+annotation.operationName();   
24.                      if (logger.isDebugEnabled()) {    
25.                          logger.debug("Action method:" + method.getName() + " Description:" + methodDescp);    
26.                      }    
27.                      User appUser=(User) this.getHttpServletRequest().getSession().getAttribute("user");   
28.                      if(appUser!=null){    
29.                          try{    
30.                              com.tlj.pcxt.entity.admin.Log logInfo=new com.tlj.pcxt.entity.admin.Log();    
31.                              logInfo.setIp(this.getHttpServletRequest().getRemoteAddr());   
32.                              logInfo.setSubmitUser(appUser);   
33.                              logInfo.setContent(annotation.operationType()+","+appUser.getUserName()+   
34.                                      "执行【"+annotation.operationName()+"】操作,影响数据的ID集合为["+getID(param[0])+"]");   
35.                              this.logService.save(logInfo);    
36.                          }catch(Exception ex){    
37.                              logger.error(ex.getMessage());    
38.                          }    
39.                      }    
40.                  }    
41.              }    
42.          }    
43.      }   
44.        
45.      /**  
46.       * 通过java反射来从传入的参数object里取出我们需要记录的id,name等属性,  
47.       * 此处我取出的是id  
48.       *@author 罗宇  
49.       *@date 2013-4-11  
50.       *@param obj  
51.       *@return  
52.       *@return String  
53.       */   
54.      public String getID(Object obj){   
55.          if(obj instanceof String){   
56.              return obj.toString();   
57.          }   
58.          PropertyDescriptor pd = null;   
59.          Method method = null;   
60.          String v = "";   
61.          try{   
62.              pd = new PropertyDescriptor("id", obj.getClass());   
63.              method = pd.getReadMethod();    
64.              v = String.valueOf(method.invoke(obj));   
65.          }catch (Exception e) {   
66.              e.printStackTrace();   
67.          }   
68.          return v;   
69.      }   
70.  }


 

 切入代码编写好之后,需要在applicatioContext.xml里配置切入规则,也就是说要在哪些方法执行的时候来切入上面编写的代码:配置如 下:


Xml代码  

java 日志pom java aop日志_java 日志pom_03


1.  <aop:aspectj-autoproxy/>   
2.      <bean id="logAspect" class="com.tlj.pcxt.common.logaop.LogAspect"/>      
3.       <aop:config>    
4.          <aop:aspect ref="logAspect">    
5.              <aop:pointcut id="logPointCut" expression="   
6.                     (execution(* com.tlj.pcxt.service.*.*Impl.add*(..)))   
7.                  or (execution(* com.tlj.pcxt.service.*.*Impl.update*(..)))   
8.                  or (execution(* com.tlj.pcxt.service.*.*Impl.delete*(..)))   
9.              "/>    
10.              <aop:after pointcut-ref="logPointCut" method="doSystemLog"/>    
11.          </aop:aspect>    
12.      </aop:config>


 

在此我配置的时在方法执行之后插入代码块

 


Xml代码  

java 日志pom java aop日志_runtime_04


1.  <aop:after pointcut-ref="logPointCut" method="doSystemLog"/>
  1.   


 

 

并且是在所有以add,update,delete开头的方法才执行,其余的方法将不再匹配。

调用方法如下,

 

 


Java代码  

java 日志pom java aop日志_java_05

1.  @Log(operationType="add操作:",operationName="添加仓库房间")   
2.    public void addWareHouseRoom(WareHouseRoom wareHouseRoom) throws ServiceException {   
3.        try{   
4.            this.getWareHouseRoomDao().save(wareHouseRoom);   
5.        }catch (Exception e) {   
6.            throw new ServiceException(e);   
7.        }   
8.    }


 

 

 

是在方法头前添加上面自定义的@Log注解,传入相关日志信息

另外,在LogAspect的doSystemLog方法里的


Java代码  

java 日志pom java aop日志_java 日志pom_06


    1.  Object[] param = point.getArgs();


     

     就是取出所匹配方法传入的参数,我们记录日志所需要的相关参数就是从这个对象里取出来的,并且在该方法下面的代码会检查所匹配的方法是否有注解@log,如果没有,会直接跳出该方法,不做任何处理.