转载请注明出处: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******

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

Spring AOP+Log4j记录项目日志的更多相关文章

  1. 采用Spring AOP+Log4j记录项目日志

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6567672.html 项目日志记录是项目开发.运营必不可少的内容,有了它可以对系统有整体的把控,出现任何问题 ...

  2. Spring Boot 2.X(八):Spring AOP 实现简单的日志切面

    AOP 1.什么是 AOP ? AOP 的全称为 Aspect Oriented Programming,译为面向切面编程,是通过预编译方式和运行期动态代理实现核心业务逻辑之外的横切行为的统一维护的一 ...

  3. Spring+AOP+Log4j 用注解的方式记录指定某个方法的日志

    一.spring aop execution表达式说明 在使用spring框架配置AOP的时候,不管是通过XML配置文件还是注解的方式都需要定义pointcut"切入点" 例如定义 ...

  4. Spring AOP 实现写事件日志功能

    什么是AOP?AOP使用场景?AOP相关概念?Spring AOP组件?如何使用Spring AOP?等等这些问题请参考博文:Spring AOP 实现原理 下面重点介绍如何写事件日志功能,把日志保存 ...

  5. spring aop学习记录

    许多AOP框架,比较常用的是Spring AOP 与AspectJ.这里主要学习的Spring AOP. 关于AOP 日志.事务.安全验证这些通用的.散步在系统各处的需要在实现业务逻辑时关注的事情称为 ...

  6. spring AOP自定义注解 实现日志管理

    今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在appli ...

  7. ActiveMQ学习总结(6)——ActiveMQ集成Spring和Log4j实现异步日志

    我的团队和我正在创建一个由一组RESTful JSON服务组成的服务平台,该平台中的每个服务在平台中的作用就是分别提供一些独特的功能和/或数据.由于平台中产生的日志四散各处,所以我们想,要是能将这些日 ...

  8. 利用Spring AOP自定义注解解决日志和签名校验

    转载:http://www.cnblogs.com/shipengzhi/articles/2716004.html 一.需解决的问题 部分API有签名参数(signature),Passport首先 ...

  9. springboot—spring aop 实现系统操作日志记录存储到数据库

    原文:https://www.jianshu.com/p/d0bbdf1974bd 采用方案: 使用spring 的 aop 技术切到自定义注解上,针对不同注解标志进行参数解析,记录日志 缺点是要针对 ...

随机推荐

  1. 前端单页面富应用(SPA)的实现

    一. 什么是单页面富应用? 单页面应用:Single Page Application 概念:Web应用即使不刷新也在不同的页面间切换,解决浏览器前进.后退等机制被破坏等问题.并且页面访问会被浏览器保 ...

  2. CSS3动画详解(结合实例)

    一.使用CSS3动画代替JS动画 JS动画频繁操作DOM导致效率非常低 在频繁的操作DOM和CSS时,浏览器会不停的执行重排(reflow)和重绘(repaint) 可以避免占用JS主线程 这边就不细 ...

  3. 转 class和struct最本质的区别

    class和struct最本质的区别是class是引用类型,而struct是值类型,它们在内存中的分配情况有所区别. 什么是class? class(类)是面向对象编程的基本概念,是一种自定义数据结构 ...

  4. 转youhu科技的文章 勿怪 感激 感激

    资源加载 资源加载是加载模块中最为耗时的部分,其CPU开销在Unity引擎中主要体现在Loading.UpdatePreloading和Loading.ReadObject两项中,相信经常查看Prof ...

  5. Codeforces Round #420 (Div. 2) E. Okabe and El Psy Kongroo 矩阵快速幂优化dp

    E. Okabe and El Psy Kongroo time limit per test 2 seconds memory limit per test 256 megabytes input ...

  6. 重装win7系统并激活

    备份 大白菜制作启动盘 下载大白菜软件UEFI版(新电脑使用uefi版本,装机版支持的主板多) 选择默认安装 选择默认模式开始制作 下载iso镜像文件,复制到u盘(手动复制) 设置bios       ...

  7. 学习笔记32—python常见问题及解决办法

    1.Anaconda3 中 Spyder 无法打开/点击没有反应 应对方法 1).通过pip安装pyqt5:pip install pyqt5 2).输入以下命令:spyder --new-insta ...

  8. 学习笔记27—python中numpy.ravel() 和 flatten()函数

    简介 首先声明两者所要实现的功能是一致的(将多维数组降位一维).这点从两个单词的意也可以看出来,ravel(散开,解开),flatten(变平).两者的区别在于返回拷贝(copy)还是返回视图(vie ...

  9. lumerical中DEVICE和MODE模块的交互使用(真的很干货!!可以自信的说网上绝对找不到比我更详细的步骤了)

    几个脚本文件很重要! Lumerical仿真流程: 一.DEVICE: (1).建模并且运行完之后,在脚本提示符下键入以下脚本行以运行plotDopingProfile.lsf如图1(文件名如果索引不 ...

  10. ThinkPHP 日志(如何学好一门技术,教学视频和文档的优缺)

    ThinkPHP 日志(如何学好一门技术,教学视频和文档的优缺) 一.总结 一句话总结:教学视频中介绍的只是基础的最常用的使用,那些不常用的那些视频里面都不会介绍,因为需求小,所以还是需要好好去把参考 ...