在java开发中日志的管理有不少种。我通常会使用过滤器,或者是Spring的拦截器进行日志的处理。若是是用过滤器比较简单,只要对全部的.do提交 进行拦截,而后获取action的提交路径就能够获取对每一个方法的调用。而后进行日志记录。使用过滤器的好处是能够本身选择性的对某一些方法进行过滤,记 录日志。可是实现起来有点麻烦。
另一种就是使用Spring的AOP了。这种方式实现起来很是简单,只要配置一下配置文件就能够了。但是这种方式会拦截下全部的对action的 每一个操做。使得效率比较低。不过想作详细日志这个方法仍是很是好的。下面我就介绍一下使用Spring AOP进行日志记录的方式。 html
第一种。Spring AOP对普通类的拦截操做 java
首先咱们要写一个普通类,此类做为日志记录类。 好比 spring
- package chen.hui.log
-
- public classs MyLog{
- //在类里面写方法,方法名诗能够任意的。此处我用标准的before和after来表示
- public void before(){
- System.out.println("被拦截方法调用以前调用此方法,输出此语句");
- }
- public void after(){
- System.out.println("被拦截方法调用以后调用此方法,输出此语句");
- }
- }
其次咱们在写一个类做为被拦截类(Spring的AOP就是拦截这个类里面的方法) express
- package chen.hui.log
-
- public class Test{//此类中方法能够写任意多个。我只写一个
- public void test(){
- Sytem.out.println("测试类的test方法被调用");
- }
- }
最后进行配置文件的编写。在Spring的配置文件中咱们须要进行几句话的配置 数组
- <bean id="testLog" class="chen.hui.log.MyLog"></bean> <!--将日志类注入到bean中。-->
- <aop:config>
- <aop:aspect id="b" ref="testLog"><!--调用日志类-->
- <aop:pointcut id="log" expression="execution(* chen.hui.log.*.*(..))"/><!--配置在log包下全部的类在调用以前都会被拦截-->
- <aop:before pointcut-ref="log" method="before"/><!--在log包下面全部的类的全部方法被调用以前都调用MyLog中的before方法-->
- <aop:after pointcut-ref="log" method="after"/>><!--在log包下面全部的类的全部方法被调用以前都调用MyLog中的after方法-->
- </aop:aspect>
- </aop:config>
到此处整个程序完成,在MyLog类里面的before和after方法添加日志逻辑代码就能够完成日志的管理。以上是对普通类的管理,若是只想拦截某一个类。只要把倒数第二个 * 改为类名就能够了。 app
第二:使用Spring AOP对action作日志管理 测试
若是是想拦截action对action作日志管理,基本和上面差很少,可是要注意。如下几点 ui
首先仍是要写一个普通类,不过此类中的方法须要传入参数。 好比 this
- package chen.hui.log
-
- import org.aspectj.lang.JoinPoint;
-
- public classs MyLog{
-
- //在类里面写方法,方法名诗能够任意的。此处我用标准的before和after来表示
-
- //此处的JoinPoint类能够获取,action全部的相关配置信息和request等内置对象。
-
- public void before(JoinPoint joinpoint){
-
- joinpoint.getArgs();//此方法返回的是一个数组,数组中包括request以及ActionCofig等类对象
-
- System.out.println("被拦截方法调用以前调用此方法,输出此语句");
- }
- public void after(JoinPoint joinpoint){
-
- System.out.println("被拦截方法调用以后调用此方法,输出此语句");
- }
- }
其次咱们在写一个action类做为被拦截类(Spring的AOP就是拦截这个类里面的方法) spa
- package chen.hui.log
-
- public class LoginAction{//此类中方法能够写任意多个。我只写一个
- public void test(){
- Sytem.out.println("测试类的test方法被调用");
- }
- }
最后进行配置文件的编写。在Spring的配置文件中咱们须要进行几句话的配置
- <bean id="testLog" class="chen.hui.log.MyLog"></bean> <!--将日志类注入到bean中。-->
- <aop:config>
- <aop:aspect id="b" ref="testLog"><!--调用日志类-->
- <aop:pointcut id="log" expression="execution(* chen.hui.log.*.*(..))"/><!--配置在log包下全部的类在调用以前都会被拦截-->
- <aop:before pointcut-ref="log" method="before"/><!--在log包下面全部的类的全部方法被调用以前都调用MyLog中的before方法-->
- <aop:after pointcut-ref="log" method="after"/><!--在log包下面全部的类的全部方法被调用以前都调用MyLog中的after方法-->
- </aop:aspect>
- </aop:config>
除了参数外其余地方基本和普通类类似。
须要注意的是:普通类能够监控单一的类,而action在配置文件中只能到包名而不能到action的类名。否则会报错。就是说若是要记录日志就要记录全部的action而不能记录其中一个,这是我试了很久得出的结果。
前几天作项目时,在作系统日志这一块,都是在每一个方法里手写代码来添加,以为很繁琐,考虑到spring有aop的功能,便寻思着用AOP来作这个日志功能。
首先须要传入日志记录的具体操做名称,咱们能够用java的注解功能来带入参数,代码以下:
Java代码
- /**
- * 类的方法描述注解
- * @author LuoYu
- */
- @Target (ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Inherited
- public @interface Log {
-
- /** 要执行的操做类型好比:add操做 **/
- public String operationType() default "";
-
- /** 要执行的具体操做好比:【添加仓库】 **/
- public String operationName() default "";
-
- }
注解类编写好以后,就要考虑spring我切面的问题目了,首先咱们要建立一个切点,也就是须要插入的代码块,代码以下:
Java代码
- /**
- * 经过Spring AOP来添加系统日志
- * @author LuoYu
- */
- public class LogAspect extends BaseAction{
-
- private static final long serialVersionUID = -5063868902693772455L;
-
- private Log logger = LogFactory.getLog(LogAspect.class);
-
- @SuppressWarnings( { "rawtypes", "unchecked" } )
- public void doSystemLog(JoinPoint point) throws Throwable {
- Object[] param = point.getArgs();
- Method method = null;
- String methodName = point.getSignature().getName();
- if (!(methodName.startsWith("set") || methodName.startsWith("get")||methodName.startsWith("query"))){
- Class targetClass = point.getTarget().getClass();
- method = targetClass.getMethod(methodName, param[0].getClass());
- if (method != null) {
- boolean hasAnnotation = method.isAnnotationPresent(com.tlj.pcxt.common.logaop.Log.class);
- if (hasAnnotation) {
- com.tlj.pcxt.common.logaop.Log annotation = method.getAnnotation(com.tlj.pcxt.common.logaop.Log.class);
- String methodDescp = annotation.operationType()+annotation.operationName();
- if (logger.isDebugEnabled()) {
- logger.debug("Action method:" + method.getName() + " Description:" + methodDescp);
- }
- User appUser=(User) this.getHttpServletRequest().getSession().getAttribute("user");
- if(appUser!=null){
- try{
- com.tlj.pcxt.entity.admin.Log logInfo=new com.tlj.pcxt.entity.admin.Log();
- logInfo.setIp(this.getHttpServletRequest().getRemoteAddr());
- logInfo.setSubmitUser(appUser);
- logInfo.setContent(annotation.operationType()+","+appUser.getUserName()+
- "执行【"+annotation.operationName()+"】操做,影响数据的ID集合为["+getID(param[0])+"]");
- this.logService.save(logInfo);
- }catch(Exception ex){
- logger.error(ex.getMessage());
- }
- }
- }
- }
- }
- }
-
- /**
- * 经过java反射来从传入的参数object里取出咱们须要记录的id,name等属性,
- * 此处我取出的是id
- *@author 罗宇
- *@date 2013-4-11
- *@param obj
- *@return
- *@return String
- */
- public String getID(Object obj){
- if(obj instanceof String){
- return obj.toString();
- }
- PropertyDescriptor pd = null;
- Method method = null;
- String v = "";
- try{
- pd = new PropertyDescriptor("id", obj.getClass());
- method = pd.getReadMethod();
- v = String.valueOf(method.invoke(obj));
- }catch (Exception e) {
- e.printStackTrace();
- }
- return v;
- }
- }
切入代码编写好以后,须要在applicatioContext.xml里配置切入规则,也就是说要在哪些方法执行的时候来切入上面编写的代码:配置如 下:
Xml代码
- <aop:aspectj-autoproxy/>
- <bean id="logAspect" class="com.tlj.pcxt.common.logaop.LogAspect"/>
- <aop:config>
- <aop:aspect ref="logAspect">
- <aop:pointcut id="logPointCut" expression="
- (execution(* com.tlj.pcxt.service.*.*Impl.add*(..)))
- or (execution(* com.tlj.pcxt.service.*.*Impl.update*(..)))
- or (execution(* com.tlj.pcxt.service.*.*Impl.delete*(..)))
- "/>
- <aop:after pointcut-ref="logPointCut" method="doSystemLog"/>
- </aop:aspect>
- </aop:config>
在此我配置的时在方法执行以后插入代码块
Xml代码
- <aop:after pointcut-ref="logPointCut" method="doSystemLog"/>
而且是在全部以add,update,delete开头的方法才执行,其他的方法将再也不匹配。
调用方法以下,
Java代码
- @Log(operationType="add操做:",operationName="添加仓库房间")
- public void addWareHouseRoom(WareHouseRoom wareHouseRoom) throws ServiceException {
- try{
- this.getWareHouseRoomDao().save(wareHouseRoom);
- }catch (Exception e) {
- throw new ServiceException(e);
- }
- }
是在方法头前添加上面自定义的@Log注解,传入相关日志信息
另外,在LogAspect的doSystemLog方法里的
Java代码
- Object[] param = point.getArgs();
就是取出所匹配方法传入的参数,咱们记录日志所须要的相关参数就是从这个对象里取出来的,而且在该方法下面的代码会检查所匹配的方法是否有注解@log,若是没有,会直接跳出该方法,不作任何处理.