Spring使用aop将日志(包括异常信息)输入到日志文件
2017-08-08 15:35
471 查看
Spring使用aop将日志(包括异常信息)输入到日志文件
首先介绍一下aop的知识吧。(第一次真正接触aop是在配置权限管理的时候,因为本人不喜欢jsp,把java代码嵌套到jsp中,总觉得这没有真正做到MVC的思想,代码模块化不够,扯远了)
注,一下有些是从别人的地方copy过来的,只是添加个人理解而已
切面(Aepect):横切关注点(跨越应用程序多个模块的功能)被模块化的对象;
通知(Advice):切面必须要完成的工作;
目标(Target):被通知的对象;
代理(Proxy):像目标对象应用通知之后创建的对象;
连接点(Joinpoint):程序执行的某个特殊位置,如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示的程序执行点;想对点表示的方位。
切点(pointcut):每个类都拥有多个连接点,即连接点是程序类中客观存在的事务;
AOP通过切点定位到特定的连接点。
AOP的主要编程对象是切面(aopect),而切面模块化横切关注点。
在应用AOP编程时,仍需要定义公共功能,但可以明确这个功能在哪里,以什么方式应用,并且不必修改受影响的类,这样的话横切关注点就被模块化到特殊的对象(切面)里。
AOP的好处:
每个事物逻辑位于一个位置,代码不分散,便于维护和升级;
业务模块更简洁,值包含核心业务代码
两种方式使用aop:一是使用aspectj注解,二是基于xml配置的aop
切面首先是IOC容器中的一个bean,即在切面类前加上标签@Component标签
切面还需要添加标签@Aspect标签,声明该类是一个切面
实现需要的通知,在方法之前添加如下的通知类型:
@Before:前置通知,在方法前通知;
@After :后置通知,在方法执行后通知;
@AfterRunning:返回通知,在方法返回结果之后通知;
@AfterThrowing:异常通知,在方法抛出异常之后通知;
@Around:环绕通知,围绕着方法执行;
切入点表达式的书写:
execution(* com.cn21.redisCluster.controller.*(..)) :第一个*表示任意的修饰符(public/private/protected)及任意的返回值(void/Object);第二个*表示任意的方法,‘..’表示任意数量的参数;
execution(public * com.cn21.redisCluster.controller.*Controller.*(..)):表示com.cn21.redisCluster.controller包下+以Controller结尾的+公共的方法(public)的方法;
execution(public void com.cn21.redisCluster.controller.*Controller.*(..)):表示com.cn21.redisCluster.controller包下+以Controller结尾的+公共的方法(public)+返回类型是void的方法;
execution(public void com.cn21.redisCluster.controller.*Controller.*(int,..)):表示com.cn21.redisCluster.controller包下+以Controller结尾+公共的方法(public
1673c
)+返回类型是void的类+第一个参数是int的方法;
execution(public void com.cn21.redisCluster.controller.*Controller.*(int,int)):表示com.cn21.redisCluster.controller包下+以Controller结尾+公共的方法(public)+返回类型是void的类+第一个参数是int+第二个参数是int的方法;
可以在方法中声明一个类型为JoinPoint的参数,然后就可以访问链接细节,如方法名称和参数值;
日志如下
-----------2017-08-08 10:25:02------------
前置通知的方法是: uploadPic 该方法的参数有:<[org.springframework.web.multipart.support.DefaultMultipartHttpServletRequest@1f2cb93, da, org.springframework.web.multipart.commons.CommonsMultipartFile@188a87e, 1, 6, 2, 1]>
-----------2017-08-08 10:25:02------------
后置通知的是方法是: uploadPic
[B@12258d0
-----------2017-08-08 10:32:26------------
beforMethod is exexuting the method : uploadPic 该方法的参数有:<[org.springframework.web.multipart.support.DefaultMultipartHttpServletRequest@12c5f3c, da, org.springframework.web.multipart.commons.CommonsMultipartFile@1dc07ad, 1, 6, 2, 1]>
-----------2017-08-08 10:32:26------------
afterMethod is exexuting the method : uploadPic
-----------2017-08-08 10:32:26------------
远程请求URL[http://localhost:8099/huiku/upload/uploadPic.do]
接口方法:[com.huiku.controller.PictureRepertoryController.uploadPic]
详细错误信息:java.lang.ArithmeticException: / by zero
at com.huiku.controller.PictureRepertoryController.uploadPic(PictureRepertoryController.java:53)
at com.huiku.controller.PictureRepertoryController$$FastClassBySpringCGLIB$$d94d6e27.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:43)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:58)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
at com.huiku.controller.PictureRepertoryController$$EnhancerBySpringCGLIB$$94b113a8.uploadPic(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:222)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:814)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:969)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:871)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:845)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
at org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:151)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:211)
at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at org.mortbay.jetty.Server.handle(Server.java:313)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:506)
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:844)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:644)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:381)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:396)
at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:442)
最近把刚开发的代码部署到服务器,因为使用的是本地web和Junit测试接口,那是没问题的,但其实接口是给安卓用的,他那边一测试就报错。由于之前没有把异常信息输入到日志文件(第一次把单独开发的后台部署到远程服务器,没有经验),所以没法查看哪里出错了。今天才想到使用日志把异常日志使用普通的log4j记录日志,使用普通的日志记录信息,需要在每个方法要使用日志的都要使用这句话private
static
final
Log log = LogFactory.getLog(JYLog.class);这样破坏了代码的完整性,而且日志代码的可重复使用性太差。所以就想像配置权限过滤器一样,配置日志aop。
首先介绍一下aop的知识吧。(第一次真正接触aop是在配置权限管理的时候,因为本人不喜欢jsp,把java代码嵌套到jsp中,总觉得这没有真正做到MVC的思想,代码模块化不够,扯远了)注,一下有些是从别人的地方copy过来的,只是添加个人理解而已
AOP(Aspect-Oriented Programming,面向切面编程)
切面(Aepect):横切关注点(跨越应用程序多个模块的功能)被模块化的对象;通知(Advice):切面必须要完成的工作;
目标(Target):被通知的对象;
代理(Proxy):像目标对象应用通知之后创建的对象;
连接点(Joinpoint):程序执行的某个特殊位置,如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示的程序执行点;想对点表示的方位。
切点(pointcut):每个类都拥有多个连接点,即连接点是程序类中客观存在的事务;
AOP通过切点定位到特定的连接点。
AOP的主要编程对象是切面(aopect),而切面模块化横切关注点。
在应用AOP编程时,仍需要定义公共功能,但可以明确这个功能在哪里,以什么方式应用,并且不必修改受影响的类,这样的话横切关注点就被模块化到特殊的对象(切面)里。
AOP的好处:
每个事物逻辑位于一个位置,代码不分散,便于维护和升级;
业务模块更简洁,值包含核心业务代码
两种方式使用aop:一是使用aspectj注解,二是基于xml配置的aop
1、基于AspectJ注解
(1)Maven引入依赖包
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.1</version> </dependency>
(2)在spring配置文件中添加aop的命名空间,同时配置使得项目支持Aop,配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!--使Spring支持自动检测组件,如注解的Controller --> <context:component-scan base-package="com.parry.redisCluster.*" /> <!--*************** 支持aop **************** --> <aop:aspectj-autoproxy proxy-target-class="true" /> </beans>
(3)实现一个日志切面
切面首先是IOC容器中的一个bean,即在切面类前加上标签@Component标签切面还需要添加标签@Aspect标签,声明该类是一个切面
实现需要的通知,在方法之前添加如下的通知类型:
@Before:前置通知,在方法前通知;
@After :后置通知,在方法执行后通知;
@AfterRunning:返回通知,在方法返回结果之后通知;
@AfterThrowing:异常通知,在方法抛出异常之后通知;
@Around:环绕通知,围绕着方法执行;
切入点表达式的书写:
execution(* com.cn21.redisCluster.controller.*(..)) :第一个*表示任意的修饰符(public/private/protected)及任意的返回值(void/Object);第二个*表示任意的方法,‘..’表示任意数量的参数;
execution(public * com.cn21.redisCluster.controller.*Controller.*(..)):表示com.cn21.redisCluster.controller包下+以Controller结尾的+公共的方法(public)的方法;
execution(public void com.cn21.redisCluster.controller.*Controller.*(..)):表示com.cn21.redisCluster.controller包下+以Controller结尾的+公共的方法(public)+返回类型是void的方法;
execution(public void com.cn21.redisCluster.controller.*Controller.*(int,..)):表示com.cn21.redisCluster.controller包下+以Controller结尾+公共的方法(public
1673c
)+返回类型是void的类+第一个参数是int的方法;
execution(public void com.cn21.redisCluster.controller.*Controller.*(int,int)):表示com.cn21.redisCluster.controller包下+以Controller结尾+公共的方法(public)+返回类型是void的类+第一个参数是int+第二个参数是int的方法;
可以在方法中声明一个类型为JoinPoint的参数,然后就可以访问链接细节,如方法名称和参数值;
import java.util.Arrays; import java.util.List; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Aspect //该标签把LoggerAspect类声明为一个切面 @Order(1) //设置切面的优先级:如果有多个切面,可通过设置优先级控制切面的执行顺序(数值越小,优先级越高) @Component //该标签把LoggerAspect类放到IOC容器中 public class LoggerAspect { /** * 定义一个方法,用于声明切入点表达式,方法中一般不需要添加其他代码 * 使用@Pointcut声明切入点表达式 * 后面的通知直接使用方法名来引用当前的切点表达式;如果是其他类使用,加上包名即可 */ @Pointcut("execution(public * com.parry.redisCluster.controller.*Controller.*(..))") public void declearJoinPointExpression(){} /** * 前置通知 * @param joinPoint */ @Before("declearJoinPointExpression()") //该标签声明次方法是一个前置通知:在目标方法开始之前执行 public void beforMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); List<Object> args = Arrays.asList(joinPoint.getArgs()); System.out.println("this method "+methodName+" begin. param<"+ args+">"); } /** * 后置通知(无论方法是否发生异常都会执行,所以访问不到方法的返回值) * @param joinPoint */ @After("declearJoinPointExpression()") public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println("this method "+methodName+" end."); } /** * 返回通知(在方法正常结束执行的代码) * 返回通知可以访问到方法的返回值! * @param joinPoit */ @AfterReturning(value="declearJoinPointExpression()",returning="result") public void afterReturnMethod(JoinPoint joinPoint,Object result){ String methodName = joinPoint.getSignature().getName(); System.out.println("this method "+methodName+" end.result<"+result+">"); } /** * 异常通知(方法发生异常执行的代码) * 可以访问到异常对象;且可以指定在出现特定异常时执行的代码 * @param joinPoint * @param ex */ @AfterThrowing(value="declearJoinPointExpression()",throwing="ex") public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){ String methodName = joinPoint.getSignature().getName(); System.out.println("this method "+methodName+" end.ex message<"+ex+">"); } /** * 环绕通知(需要携带类型为ProceedingJoinPoint类型的参数) * 环绕通知包含前置、后置、返回、异常通知;ProceedingJoinPoin 类型的参数可以决定是否执行目标方法 * 且环绕通知必须有返回值,返回值即目标方法的返回值 * @param joinPoint */ @Around(value="declearJoinPointExpression()") public Object aroundMethod(ProceedingJoinPoint point){ Object result = null; String methodName = point.getSignature().getName(); try { //前置通知 System.out.println("The method "+ methodName+" start. param<"+ Arrays.asList(point.getArgs())+">"); //执行目标方法 result = point.proceed(); //返回通知 System.out.println("The method "+ methodName+" end. result<"+ result+">"); } catch (Throwable e) { //异常通知 System.out.println("this method "+methodName+" end.ex message<"+e+">"); throw new RuntimeException(e); } //后置通知 System.out.println("The method "+ methodName+" end."); return result; } }
2、基于XML配置的AOP
(1)在spring配置文件中添加aop的命名空间,配置如下:(注意,这里是要把aop的xml代码放到spring*.xml文件中,不然可能会出现没有日志输出,我之前放到application*.xml,一直没有日志输出,原来就是因为application是在spring的子容器中,网上怎么解释,我忘记了,也没有链接,改放到spring*.xml文件就有了)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!--使Spring支持自动检测组件,如注解的Controller --> <context:component-scan base-package="com.huiku.*" /> <!--*************** 支持aop **************** --> <aop:aspectj-autoproxy proxy-target-class="true" /> <bean id="LogAspect" class="com.huiku.utils.LogAspect"></bean> <!-- 配置AOP --> <aop:config> <!-- 配置切点表达式 --> <aop:pointcut id="pointcut" expression="execution(* com.huiku.*.*.*(..))" /> <!-- 配置切面及配置 --> <aop:aspect order="3" ref="LogAspect"> <!-- 前置通知 --> <aop:before method="beforMethod" pointcut-ref="pointcut"/> <!-- 后置通知 --> <aop:after method="afterMethod" pointcut-ref="pointcut"/> <!-- 返回通知 --> <aop:after-returning method="afterReturnMethod" pointcut-ref="pointcut" returning="result"/> <!-- 异常通知 --> <aop:after-throwing method="afterThrow" pointcut-ref="pointcut" throwing="ex"/> </aop:aspect> </aop:config></beans>
(2)实现切面类:
package com.huiku.utils; /** * Created by 凌 on 2017/8/7. */ import java.io.*; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import java.util.List; import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.aspectj.lang.JoinPoint; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; public class LogAspect { private final static Log log = LogFactory.getLog(LogAspect.class); private final String filePath="log/lo4j.txt"; /** * 前置通知 在某连接点之前执行的通知,但这个通知不能阻止连接点前的执行 * @param joinPoint 连接点:程序执行过程中的某一行为 */ public void beforMethod(JoinPoint joinPoint)throws IOException{ String methodName = joinPoint.getSignature().getName(); List<Object> args = Arrays.asList(joinPoint.getArgs()); WriteErrorToLog4J("beforMethod is exexuting the method :"+methodName+", and the params of the method are:<"+ args+">"); System.out.println("beforMethod is exexuting the method : "+methodName+", and the params of the method are:<"+ args+">"); } /** * 后置通知(无论方法是否发生异常都会执行,所以访问不到方法的返回值) * @param joinPoint */ public void afterMethod(JoinPoint joinPoint)throws IOException{ String methodName = joinPoint.getSignature().getName(); WriteErrorToLog4J("afterMethod is exexuting the method : " + methodName); System.out.println("afterMethod is exexuting the method : " + methodName); } /** * 返回通知(在方法正常结束执行的代码) * 返回通知可以访问到方法的返回值! * @param joinPoint */ public void afterReturnMethod(JoinPoint joinPoint,Object result)throws IOException{ String methodName = joinPoint.getSignature().getName(); WriteErrorToLog4J("afterMethod is exexuting the method : "+methodName+",and returns the result is <"+result+">"); System.out.println("afterMethod is exexuting the method : "+methodName+",and returns the result is <"+result+">"); } /** * 异常通知(方法发生异常执行的代码) * 可以访问到异常对象;且可以指定在出现特定异常时执行的代码,使用在方法aspect()上注册的切入点 * @param joinPoint * @param ex */ public void afterThrow(JoinPoint joinPoint, Exception ex){ String methodName = joinPoint.getSignature().getName(); //判断日志输出级别 if(log.isInfoEnabled()){ log.info("异常通知: " + joinPoint + "\t" + ex.getMessage()); } //详细错误信息 String errorMsg = ""; StackTraceElement[] trace = ex.getStackTrace(); for (StackTraceElement s : trace) { errorMsg += "\tat " + s + "\r\n"; } System.out.println("具体异常信息:"+errorMsg); System.out.println("产生异常的方法名为: " + joinPoint + "\t" + ex.getMessage()); System.out.println("异常信息结束!!!"); //写入异常日志 writeLog(errorMsg,joinPoint,ex); } // 把正常信息信息写进日志里面 public void WriteErrorToLog4J(String message)throws IOException { SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { FileWriter fw = new FileWriter(filePath, true);//如果追加方式用true BufferedWriter bw = new BufferedWriter(fw); String messageStr=new String(message.getBytes("utf-8")); bw.append("-----------"+sdf.format(new Date())+"------------\r\n");// 往已有的文件上添加字符串 bw.append(messageStr+"\n "); bw.flush(); bw.close(); fw.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * * @param detailErrMsg 详细错误信息 * @param joinPoint 方法名称 * @Description: 日志异常 * @author: Ma * @createTime: 2016-10-14 */ public void writeLog(String detailErrMsg,JoinPoint joinPoint,Exception ex){ HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder. getRequestAttributes()).getRequest(); //获取请求的URL StringBuffer requestURL = request.getRequestURL(); //获取参 数信息 String queryString = request.getQueryString(); //封装完整请求URL带参数 if(queryString != null){ requestURL .append("?").append(queryString); } String cla=joinPoint.getTarget().getClass().getName();//action String method=joinPoint.getSignature().getName();//method try{ SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //创建输出异常log日志 // File file =new File(filePath); // //if file doesnt exists, then create it // if(!file.exists()){ // file.createNewFile(); // } FileWriter fw = new FileWriter(filePath, true); BufferedWriter bw = new BufferedWriter(fw); // FileOutputStream out=new FileOutputStream(file,false); //日志具体参数 StringBuffer sb=new StringBuffer(); sb.append("-----------"+sdf.format(new Date())+"------------\r\n"); sb.append("远程请求URL["+requestURL+"]\r\n"); sb.append("接口方法:["+cla+"."+method+"]\r\n"); sb.append("详细错误信息:"+ex+"\r\n"); sb.append(detailErrMsg+"\r\n"); // sb.toString().getBytes("utf-8") bw.append(new String(sb.toString().getBytes("utf-8"))+"\r\n");//注意需要转换对应的字符集 bw.close(); fw.close(); }catch(IOException e){ e.printStackTrace(); } } }为什么要用bw.append(messageStr)而不是用bw.write()呢?是因为,bw.write()会把log.txt原来的日志全覆盖掉,但bw.append()是每次从日志文件的最后插入新的日志信息,还要注意的是,异常信息需要使用utf-8的字符格式,因为日志中可能会有中文,否则会出现中文乱码的
日志如下
-----------2017-08-08 10:25:02------------
前置通知的方法是: uploadPic 该方法的参数有:<[org.springframework.web.multipart.support.DefaultMultipartHttpServletRequest@1f2cb93, da, org.springframework.web.multipart.commons.CommonsMultipartFile@188a87e, 1, 6, 2, 1]>
-----------2017-08-08 10:25:02------------
后置通知的是方法是: uploadPic
[B@12258d0
-----------2017-08-08 10:32:26------------
beforMethod is exexuting the method : uploadPic 该方法的参数有:<[org.springframework.web.multipart.support.DefaultMultipartHttpServletRequest@12c5f3c, da, org.springframework.web.multipart.commons.CommonsMultipartFile@1dc07ad, 1, 6, 2, 1]>
-----------2017-08-08 10:32:26------------
afterMethod is exexuting the method : uploadPic
-----------2017-08-08 10:32:26------------
远程请求URL[http://localhost:8099/huiku/upload/uploadPic.do]
接口方法:[com.huiku.controller.PictureRepertoryController.uploadPic]
详细错误信息:java.lang.ArithmeticException: / by zero
at com.huiku.controller.PictureRepertoryController.uploadPic(PictureRepertoryController.java:53)
at com.huiku.controller.PictureRepertoryController$$FastClassBySpringCGLIB$$d94d6e27.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:43)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:58)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
at com.huiku.controller.PictureRepertoryController$$EnhancerBySpringCGLIB$$94b113a8.uploadPic(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:222)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:814)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:969)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:871)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:845)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
at org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:151)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:211)
at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at org.mortbay.jetty.Server.handle(Server.java:313)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:506)
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:844)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:644)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:381)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:396)
at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:442)
相关文章推荐
- Spring.net AOP异常记入单独日志文件
- linux 使用 syslog 服务,将出错信息输入到 “/var/log/message” 系统日志文件中去
- 通过spring aop记录日志信息(异常)
- spring aop 切面记录log4j日志 之around记录异常信息
- springboot学习(7)springboot使用AOP打印日志信息
- Spring.Net AOP 学习之旅: 使用 Throws Advice 处理异常
- 使用spring配置文件实现AOP
- 使用Spring AOP 的@AspectJ记录日志
- 使用Shell向syslog日志文件写入信息
- 使用spring aop结合log4j做日志
- C# 程序出现错误或异常,将异常信息写入指定日志文件
- 第十三篇 在使用spring AOP中, Service中使用service出现的异常
- 检查存储结构-控制、REDO日志、表空间使用情况、数据文件等信息脚本--HTML
- Spring 使用Aop 做切面日志,和权限。
- ITCAST视频-Spring学习笔记(使用Spring配置文件实现AOP)
- 使用 AOP 记录可定制的日志信息
- 使用Spring配置文件实现AOP
- Spring Aop 日志管理及配置文件的详细配置
- struts2 与 spring 使用aop处理Action异常
- Windows Phone 实用开发技巧(22):使用日志记录当前信息与异常信息 推荐