SpringAOP自定义注解实现统一日志管理

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

SpringAOP⾃定义注解实现统⼀⽇志管理
⼀、AOP的基本概念:
AOP,⾯向切⾯编程,常⽤于⽇志,事务,权限等业务处理。

AOP是OOP的延续,是软件开发中的⼀个热点,也是Spring框架中的⼀个重要内容(Spring核⼼之⼀),是函数式编程的⼀种衍⽣范型。

利⽤AOP可以对业务逻辑的各个部分进⾏隔离,从⽽使得业务逻辑各部分之间的耦合度降低,提⾼程序的可重⽤性,同时提⾼了开发的效率。

⼆、AOP的⼏个特征:
(1)Aspect(切⾯):通常是⼀个类,⾥⾯可以定义切⼊点和通知
(2)JointPoint(连接点):程序执⾏过程中明确的点,⼀般是⽅法的调⽤
(3)Advice(通知):AOP在特定的切⼊点上执⾏的增强处理,有before,after,afterReturning,afterThrowing,around
(4)Pointcut(切⼊点):就是带有通知的连接点,在程序中主要体现为书写切⼊点表达式
(5)AOP代理:AOP框架创建的对象,代理就是⽬标对象的加强。

Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接⼝,后者基于⼦类
三、具体功能实例:
(1)⾸先引⼊spring AOP所需的jar包依赖:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.3</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.3</version>
</dependency>
(2)⾃定义注解类:
/**
* ⾃动⽇志监听注解类
* @author AoXiang
*
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysAutoLog {
String module() default "";
String methods() default "";
String description() default "";
}
(3)新建切⾯类:
/**
* ⽇志切⾯类
* @author AoXiang
*
*/
@Aspect
@Component
public class SysLogAopControl{
private Logger logger = LoggerFactory.getLogger(this.getClass());
private LocalVariableTableParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
@Autowired
private SysHandLogStub SysHandLogStub;
@Pointcut("@annotation(cn.tisson.tc.annotation.SysAutoLog)")
public void LogAspect() {}
@AfterThrowing(pointcut = "LogAspect()", throwing = "e")
public void doAfterThrowing(JoinPoint point, Throwable e) throws Exception {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes)ra;
HttpServletRequest request = sra.getRequest();
SysHandLogEntity sysLog = new SysHandLogEntity();
Map<String, Object> map = this.getMethodDescription(point);
sysLog.setModel(map.get("module").toString());
sysLog.setMethod("执⾏⽅法异常:-->" + map.get("methods").toString());
sysLog.setStatusDesc("执⾏⽅法异常:-->" + e);
sysLog.setArgs(map.get("args").toString());
sysLog.setIp(GetRemoteIpUtil.getRemoteIp(request));
sysLog.setCreateDate(new Date());
SysHandLogStub.update(sysLog);
}
@Around("LogAspect()")
public Object doAround(ProceedingJoinPoint point) {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes)ra;
HttpServletRequest request = sra.getRequest();
Object result = null;
try {
result = point.proceed();
SysHandLogEntity sysLog = new SysHandLogEntity();
Map<String, Object> map = this.getMethodDescription(point);
sysLog.setModel(map.get("module").toString());
sysLog.setMethod(map.get("methods").toString());
sysLog.setStatusDesc(map.get("description").toString());
sysLog.setArgs(map.get("args").toString());
sysLog.setIp(GetRemoteIpUtil.getRemoteIp(request));
sysLog.setCreateDate(new Date());
//⽤户信息
Subject subject = SecurityUtils.getSubject();
UserVo userVo = (UserVo)subject.getPrincipal();
if (userVo == null) {
userVo = (UserVo)ShiroSubject.getSessionVo();
}
if(userVo != null) {
sysLog.setUserRealName(userVo.getRealName());
}
SysHandLogStub.update(sysLog);
} catch (Throwable e) {
logger.error("异常信息:{}", e.getMessage());
throw new RuntimeException(e);
}
return result;
}
@SuppressWarnings("rawtypes")
public Map<String, Object> getMethodDescription(JoinPoint joinPoint) throws Exception {
Map<String, Object> map = new HashMap<String, Object>();
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class<?> targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
map.put("module", targetName.substring(stIndexOf(".")+1,targetName.length())); String methodStr = method.toString().substring(0,method.toString().lastIndexOf("(") );
methodStr = methodStr.substring(stIndexOf(".")+1,methodStr.length() );
map.put("methods", methodStr);
map.put("args", this.getArgs(method, arguments));
String desc = method.getAnnotation(SysAutoLog.class).description();
if (StringUtils.isEmpty(desc))
desc = "执⾏成功!";
map.put("description", desc);
break;
}
}
}
return map;
}
private String getArgs(Method method, Object[] arguments) {
StringBuilder builder = new StringBuilder("{");
String params[] = parameterNameDiscoverer.getParameterNames(method);
if(params.length==0) {
return "⽆参数";
}
for (int i = 0; i < params.length; i++) {
if(!"password".equals(params[i])) {
builder.append(params[i]).append(" : ").append(arguments[i]).append(";");
}
}
return builder.append("}").toString();
}
}
(4)配置springMVC.xml⽂件,启动AOP⽀持
<!-- 该⽂件只注⼊Controller 类 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- 设置使⽤注解的类所在的jar包 -->
<context:component-scan base-package="cn.test" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
注意,关于springMVC.xml配置⽂件的写法,有⼏点需要注意:
use-default-filters 属性的默认值为 true,即使⽤默认的 Filter 进⾏包扫描,⽽默认的 Filter 对标有 @Service,@Controller和@Repository 的注解的类进⾏扫描,因为前⾯说过,我们希望 SpringMVC 只来控制⽹站的跳转逻辑,所以我们只希望 SpringMVC 的配置扫描
@Controllerce 注解标注的类,不希望它扫描其余注解标注的类,所以设置了 use-default-filters 为 false,并使⽤ context:include-filter ⼦标签设置其只扫描带有 @Controller 注解标注的类。

在使⽤ use-default-filters 属性时要分清楚需要扫描哪些包,是不是需要使⽤默认的 Filter 进⾏扫描。

楼主稍微总结⼀下,即use-default-filters="false" 需要和 context:include-filter ⼀起使⽤,⽽不能和 context:exclude-filter 属性⼀起使⽤。

(5)使⽤⽅式
@ResponseBody
@SysAutoLog(description="测试⽅法")
@RequestMapping("testr")
public String test(HttpServletRequest request) throws Exception {}
只需要在⽅法上添加@SysAutoLog(description="")即我们⾃定义的注解即可,description是⽅法描述,这样在记录⽇志的时候可以⼀并记录下⽇志描述。

四、总结:
关于Spring AOP处理⽇志的实现⽐较简单,当然对于⽇志的统⼀处理也不⽌于这⼀种⽅式,还可以使⽤拦截器的⽅式,可以根据项⽬具体的应⽤环境选择合适的⽅式,有什么不当之处欢迎⼤家批评指正。

相关文档
最新文档