用途
一般实现日志管理(自定义注解的方式)。
首先我们为什么需要做日志管理,在现实的上线中我们经常会遇到系统出现异常或者问题。这个时候就马上打开CRT或者SSH连上服务器拿日子来分析。受网络的各种限制。于是我们就想为什么不能直接在管理后台查看报错的信息呢。于是日志管理就出现了。
其次个人觉得做日志管理最好的是Aop,有的人也喜欢用拦截器。都可以,在此我重点介绍我的实现方式。
Aop有的人说拦截不到Controller。有的人说想拦AnnotationMethodHandlerAdapter截到Controller必须得拦截org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter。
首先Aop可以拦截到Controller的,这个是毋容置疑的其次须拦截AnnotationMethodHandlerAdapter也不是必须的。最起码我没有验证成功过这个。我的spring版本是4.0.3。
Aop之所以有的人说拦截不到Controller是因为Controller被jdk代理了。我们只要把它交给cglib代理就可以了。
第一步 定义两个注解:
package com.yj.aop;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*自定义注解 拦截Controller
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})//只能方法使用
@Retention(RetentionPolicy.RUNTIME)//表明注解可以变jvm编译
@Documented
public @interface SystemControllerLog {
String description() default "";
}
package com.yj.aop;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*自定义注解 拦截service
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemServiceLog {
String description() default "";
}
第二步 创建一个切点类
package com.yj.aop;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* 切点类
* @author jing
*
*/
@Aspect
@Component
public class SystemLogAspect {
//controller层切点
@Pointcut("@annotation(com.yj.aop.SystemControllerLog)")
public void controllerAspect(){};
//service层切点
@Pointcut("@annotation(com.yj.aop.SystemServiceLog)")
public void serviceAspect(){};
@Before("controllerAspect()")
public void deBefore(JoinPoint joinPoint){
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
// HttpSession session = request.getSession();
//请求的IP
String ip = request.getRemoteAddr();
try {
//*========控制台输出=========*//
System.out.println("=====前置通知开始=====");
System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
System.out.println("方法描述:" + getControllerMethodDescription(joinPoint));
System.out.println("请求人:" + "1111");
System.out.println("请求IP:" + ip);
System.out.println("=====前置通知结束=====");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 异常通知 用于拦截service层记录异常日志
*
* @param joinPoint
* @param e
*/
@AfterThrowing(pointcut = "serviceAspect()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//获取请求ip
String ip = request.getRemoteAddr();
try {
/*========控制台输出=========*/
System.out.println("=====异常通知开始=====");
System.out.println("异常代码:" + e.getClass().getName());
System.out.println("异常信息:" + e.getMessage());
System.out.println("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
System.out.println("方法描述:" + getServiceMthodDescription(joinPoint));
System.out.println("请求人:" + "请求人");
System.out.println("请求IP:" + ip);
System.out.println("请求参数:" + "请求参数");
System.out.println("=====异常通知结束=====");
} catch (Exception ex) {
e.printStackTrace();
}
}
/**
* 获取注解中对方法的描述信息 用于Controller层注解
*
* @param joinPoint 切点
* @return 方法描述
* @throws Exception
*/
public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
String description = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
description = method.getAnnotation(SystemControllerLog. class).description();
break;
}
}
}
return description;
}
/**
* 获取注解中对方法的描述信息 用于service层注解
*
* @param joinPoint 切点
* @return 方法描述
* @throws Exception
*/
public static String getServiceMthodDescription(JoinPoint joinPoint)
throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
String description = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
description = method.getAnnotation(SystemServiceLog. class).description();
break;
}
}
}
return description;
}
}
第三步 写配置文件,把Controller的代理权交给cglib
1、要明确,我们是在SpringMVC上aop监测,那么所有的报扫描注入都在SpringMVC的配置文件中完成,不要再spring的配置文件中完成,不然在开启代理后,发现还是没有起到任何作用。
2、扫描controller
<!-- 扫描controller(controller层注入) -->
<context:component-scan base-package="com.yj.controller"/>
3、当然你此AOP切点用到了servrice层的话 要加
<!-- 扫描service(service层注入) -->
<context:component-scan base-package="com.yj.service"/>
4、切点类扫描。(此扫描加不加都可以实现,具体区别你们可以百度)
<!--切点类路径-->
<context:component-scan base-package="com.ht.annotation" annotation-config="true"/>
5、在SpringMVC的配置文件中开启他的代理模式
<!--通知spring使用cglib而不是jdk的来生成代理方法 AOP可以拦截到Controller-->
<aop:aspectj-autoproxy proxy-target-class="true" />
第四步 使用
controller的使用
package com.yj.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.yj.aop.SystemControllerLog;
@Controller()
public class TextController {
@RequestMapping("text")
@SystemControllerLog(description="aop测试")
public void text(){
System.out.println("text 运行");
}
}
service的使用
//此处为AOP拦截Service记录异常信息。方法不需要加try-catch
@SystemServiceLog(description="aop测试")
public void text(){
System.out.println("text 运行");
}
第五步 用的到jar (这里我就写maven)
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.0</version>
</dependency>
参考:http://blog.csdn.net/czmchen/article/details/42392985
参考:http://blog.csdn.net/tianjun2012/article/details/47809739