zoukankan      html  css  js  c++  java
  • Spring AOP+Log4j记录项目日志

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6567672.html 

    项目日志记录是项目开发、运营必不可少的内容,有了它可以对系统有整体的把控,出现任何问题都有踪迹可寻。

    如果用纯OOP思想进行日志处理,会发现每个逻辑部分总会混入日志处理的代码,显得纯OOP思想的设计不伦不类。如果日志的类型需求有变动,则需要去每个逻辑单元中修改Java代码。需求再变更的话这将是一个非常繁琐的工作。因此,日志处理应该是项目中单独的一部分,我们在进行系统开发时,不应该再来考虑日志处理。而AOP可以让我们更加专注于项目的业务编码,无需顾虑日志问题。

    首先简单介绍下AOP(Aspect Oriented Programming):

    AOP是OOP的延续,是一种分散关注的编程方法,将“关注”封装在切面中,实现了调用者与被调用者之间的解耦合。

    分散关注:将通用需求功能从不相关的类中分离出来,同时能够使得多个类共享一个行为,一旦行为发生改变,不必修改很多类,只需要修改这个行为就可以。

    面向对象是纵向结构的,它能够使系统的逻辑单元更加清晰。

    面向切面是横切结构的,它针对业务逻辑层的切面进行提取。比如切面完成一个功能,这一功能却在每个模块中都有涉及,他就像刀切豆腐一样切进系统,能够对系统完成同一控制。

    疑虑:donet程序部署在服务器就能运行,而Java程序却多一道工序,非得部署在容器里面才能运行呢?J2EE为什么要除非J2EE容器和J2EE应用系统呢?

    答案:J2EE容器实际上是分离一般应用系统中通用的部分。像事务、安全、数据库连接池等等这些功能,将这些分离出来做成一个通用的框架。这些功能机制的设计开发有一定的难度,同时运行的稳定性和快速性都非常重要,必须经过长时间调试和运行经验积累而成,慢慢才形成了像Tomcat、JBoss、WebLogic等J2EE容器服务产品。简单来说,J2EE中分出的容器,就是将大多数软件中都会用到的东西拿了出来,时间长了慢慢的就成了产品。

    从J2EE系统划分为容器和应用系统两个方面,我们可以看到一种分散关注的思路。

    实现过程:

    1.涉及的jar包:

    spring.jar

    log4j-1.2.16.jar

    aspectjrt.jar

    aspectjweaver.jar

    commons-logging.jar

    2.面向切面的Log类:

    import org.apache.log4j.Logger;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    
    public class LogAspect {
        Logger logger=Logger.getLogger(LogAspect.class);
        String logStr=null;
        /**
         * 前置通知:在某连接点之前执行的通知,但这个通知不能阻止连接点前的执行
         * @param jp 连接点:程序执行过程中的某一行为
         */
        public void doBefore(JoinPoint jp){
            logStr=jp.getTarget().getClass().getName()+"类的"
                    +jp.getSignature().getName()+"方法开始执行******Start******";
            logger.info(logger);
        }
        /**
         * 环绕通知:包围一个连接点的通知,可以在方法的调用前后完成自定义的行为,也可以选择不执行。
         * 类似web中Servlet规范中Filter的doFilter方法。
         * @param pjp 当前进程中的连接点
         * @return
         */
        public Object doAround(ProceedingJoinPoint pjp){
            long Time=System.currentTimeMillis();
            Object result=null;
            try {
                result=pjp.proceed();
            } catch (Throwable e) {
                e.printStackTrace();
                logStr="方法:"+pjp.getTarget().getClass()+"."+pjp.getSignature().getName()+"()";
                logStr=logStr+"错误信息如下:["+e+"]";
                logger.info(logStr);
            }
            return result;
        }
        /**
         * 后置通知
         * @param jp
         */
        public void doAfter(JoinPoint jp){
            logStr=jp.getTarget().getClass().getName()+"类的"
                    +jp.getSignature().getName()+"方法执行结束******End******";
            logger.info(logStr);            
        }
    }

    3.spring配置文件ApplicationContext.xml中配置AOP相关日志

    <!--AOP类日志  -->
        <bean id="logAspect" class="yan.joanna.log.LogAspect"></bean>
        <aop:config>
            <aop:aspect id="aspect" ref="logAspect">
                <!--对哪些方法进行日志记录,此处屏蔽action内的set get方法  -->
                <aop:pointcut id="logService" expression="(execution(* yan.joanna.*.*.*(..)) ) and (!execution(* yan.joanna.action.*.set*(..)) ) and (!execution(* yan.joanna.action.*.get*(..)) )" />
                <aop:before pointcut-ref="logService" method="doBefore"/>
                <aop:after pointcut-ref="logService" method="doAfter"/>
                <aop:around pointcut-ref="logService" method="doAround"/>
            </aop:aspect>
        </aop:config>
        <!-- 配置Action -->
        <bean id="UserAction" class="yan.joanna.action.UserAction" scope="prototype">
            <property name="userDAO" ref="UserDAO"></property>
            <property name="maindeviceDAO" ref="MaindeviceDAO"></property>
            <property name="amountDAO" ref="AmountDAO"></property>
            <property name="deviceUsingDAO" ref="DeviceUsingDAO"></property>
        </bean>

    4.log4j的log4j.properties文件的主要配置

    log4j.rootLogger = info, stdout, R
    
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.Target=System.out 
    
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern = %p %d{yyyy-MM-dd HH:mm:ssS} || %c{1} || %m%n
    
    log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.R.File=d:/UTrainFileLib/logs/utrain.log
    log4j.appender.R.Append=true
    
    log4j.appender.R.layout=org.apache.log4j.PatternLayout  
    log4j.appender.R.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] [%t] (%F:%L) ->%m %n
    log4j.appender.R.Threshold=INFO
    log4j.appender.R.DatePattern='.'yyyy-MM-dd

    5.在开发或者运行初期,我们可能想打印一些业务逻辑,参数值等,并控制它的打印级别

    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    public class JYLog {
        private static final Log log = LogFactory.getLog(JYLog.class);
        
        public static void printLog(String msg){
            if(log.isInfoEnabled()){
                log.info(msg);
            }
        }
        
        public static void errorLog(String msg,Exception e){
            log.error(msg, e);
        }
        
        public static void errorLog(String msg){
            log.error(msg);
        }
    }

    6.业务日志的打印,eg:UserAction中的登录方法:

      /**
         * 登录
         * @throws IOException 
         */
        public void login() throws IOException{
            HttpServletRequest req=ServletActionContext.getRequest();
            HttpServletResponse resp=ServletActionContext.getResponse();
            req.setCharacterEncoding("UTF-8");
            resp.setCharacterEncoding("UTF-8");
            String tel=req.getParameter("tel");
            JYLog.printLog("login()-登录-Timestamp-"+new Timestamp(System.currentTimeMillis())+
                    ";tel-"+tel);
            
            PrintWriter out=resp.getWriter();
            JSONObject json=new JSONObject();
            JSONObject dataJson=new JSONObject();
            String message="";
            int errorcode=0;
            
            if(!"".equals(tel)){
                User user=userDAO.findByAccount(tel);
                if(user==null){
                    userDAO.save(new User(tel, new Timestamp(System.currentTimeMillis()),new Timestamp(System.currentTimeMillis()), 1));
                    user=userDAO.findByAccount(tel);
                    amountDAO.save(new Amount(user, 100,0));    
                }else{
                    userDAO.updateLoginTime(user);
                }
                dataJson.put("id", user.getId());
                dataJson.put("account", user.getAccount());
                dataJson.put("type", user.getType());
                message="登录成功";
                errorcode=0;
            }else{
                message="手机号不合法";
                errorcode=10002;
            }
            
            json.put("data", dataJson);
            json.put("message", message);
            json.put("errorcode", errorcode);
            out.print(json);
            out.flush();
            out.close();
            JYLog.printLog("login()-登录-json-"+json.toString());
        }

    7.日志打印文件内容部分显示:

    [yan.joanna.log.JYLog]-[INFO] [http-bio-59500-exec-56] (JYLog.java:11) ->login()-登录-Timestamp-2017-04-01 08:10:08.972;tel-15515123456 
    2017-04-01 08:10:08 [yan.joanna.log.LogAspect]-[INFO] [http-bio-59500-exec-56] (LogAspect.java:14) ->org.apache.log4j.Logger@10fb78e 
    2017-04-01 08:10:08 [yan.joanna.log.LogAspect]-[INFO] [http-bio-59500-exec-56] (LogAspect.java:34) ->yan.joanna.dao.UserDAO类的findByAccount方法执行结束******End****** 
    2017-04-01 08:10:08 [yan.joanna.log.LogAspect]-[INFO] [http-bio-59500-exec-56] (LogAspect.java:14) ->org.apache.log4j.Logger@10fb78e 
    2017-04-01 08:10:08 [yan.joanna.log.LogAspect]-[INFO] [http-bio-59500-exec-56] (LogAspect.java:34) ->yan.joanna.dao.UserDAO类的updateLoginTime方法执行结束******End****** 
    2017-04-01 08:10:09 [yan.joanna.log.JYLog]-[INFO] [http-bio-59500-exec-56] (JYLog.java:11) ->login()-登录-json-{"data":{"id":68,"account":"15515123456","type":1},"message":"登录成功","errorcode":0} 
    2017-04-01 08:10:09 [yan.joanna.log.LogAspect]-[INFO] [http-bio-59500-exec-56] (LogAspect.java:34) ->yan.joanna.action.UserAction类的login方法执行结束******End****** 

    如果此文对您有帮助,微信打赏我一下吧~

  • 相关阅读:
    操作符 Thinking in Java 第三章
    一切都是对象 Thinking in Java 第二章
    JS获取URL中参数值(QueryString)的4种方法分享<转>
    对象导论 Thinking in Java 第一章
    Thinking in Java 笔记初衷
    JSON学习总结
    Codeforces Round #506 (Div. 3)
    2020 CCPC Wannafly Winter Camp Day1
    Educational Codeforces Round 81 (Rated for Div. 2)
    数论函数前缀和合集
  • 原文地址:https://www.cnblogs.com/Joanna-Yan/p/6567672.html
Copyright © 2011-2022 走看看