一、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(targetName.lastIndexOf(".")+1,targetName.length()));
String methodStr = method.toString().substring(0,method.toString().lastIndexOf("(") );
methodStr = methodStr.substring(methodStr.lastIndexOf(".")+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配置文件的写法,有几点需要注意:

引用crawl+的博客http://www.cnblogs.com/crawl/p/7940755.html中的描述如下:

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处理日志的实现比较简单,当然对于日志的统一处理也不止于这一种方式,还可以使用拦截器的方式,可以根据项目具体的应用环境选择合适的方式,有什么不当之处欢迎大家批评指正。

Spring AOP 自定义注解实现统一日志管理的更多相关文章

  1. spring AOP自定义注解方式实现日志管理

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

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

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

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

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

  4. (转)利用Spring AOP自定义注解解决日志和签名校验

    一.需解决的问题 部分API有签名参数(signature),Passport首先对签名进行校验,校验通过才会执行实现方法. 第一种实现方式(Origin):在需要签名校验的接口里写校验的代码,例如: ...

  5. Spring aop+自定义注解统一记录用户行为日志

    写在前面 本文不涉及过多的Spring aop基本概念以及基本用法介绍,以实际场景使用为主. 场景 我们通常有这样一个需求:打印后台接口请求的具体参数,打印接口请求的最终响应结果,以及记录哪个用户在什 ...

  6. 使用Spring Aop自定义注解实现自动记录日志

    百度加自己琢磨,以下亲测有效,所以写下来记录,也方便自己回顾浏览加深印象之类,有什么问题可以评论一起解决,不完整之处也请大佬指正,一起进步哈哈(1)首先配置文件: <!-- 声明自动为sprin ...

  7. Spring AOP 自定义注解获取http接口及WebService接口入参和出参

    注解方法实现过程中可以采用如下获取方式:—以下为例  HttpServletRequest request = ((ServletRequestAttributes) RequestContextHo ...

  8. SpringBoot系列(十三)统一日志处理,logback+slf4j AOP+自定义注解,走起!

    往期精彩推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 springBoot系列(三)配置文件详解 SpringBoot系列(四)we ...

  9. redis分布式锁-spring boot aop+自定义注解实现分布式锁

    接这这一篇redis分布式锁-java实现末尾,实现aop+自定义注解 实现分布式锁 1.为什么需要 声明式的分布式锁 编程式分布式锁每次实现都要单独实现,但业务量大功能复杂时,使用编程式分布式锁无疑 ...

随机推荐

  1. java事务(一)——事务特性

    事务 什么是事务?事务通俗的讲就是要做的事,在计算机术语中一般指访问或更新数据库中数据的一个工作单元.说起事务,那么就要提到事务的ACID特性,即原子性(atomicity).一致性(consiste ...

  2. leetcode 24. Swap Nodes in Pairs(链表)

    Given a linked list, swap every two adjacent nodes and return its head. For example,Given 1->2-&g ...

  3. Convolutional Neural Networks for Visual Recognition 8

    Convolutional Neural Networks (CNNs / ConvNets) 前面做了如此漫长的铺垫,现在终于来到了课程的重点.Convolutional Neural Networ ...

  4. 【遍历二叉树】01二叉树的前序遍历【Binary Tree Preorder Traversal】

    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 给定一个二叉树,返回他的前序遍历的 ...

  5. oracle数据库规划建议

    之前负责的项目有用到oracle的,oracle dba给过一些建议,自己整理了一下,写再这里做个备忘 数据库需求分析: 1. 创建的数据库名称为maildb,并且字符集为UTF8. 2. 提供可连接 ...

  6. Oracle RAC TAF 无缝failover

    理论背景: TAF( Transparent Application Failover ) allows oracle clients to reconnect to a surviving inst ...

  7. windows服务和进程的区别和联系

    Windows Service 是主要用于服务器环境而长期运行的应用程序, 这类程序不需要有用户界面或者任何模拟输出. 任何的用户消息通常都是记录在Windows 事件日志里.Windows Serv ...

  8. 人物-IT-马化腾:马化腾

    ylbtech-人物-IT-马化腾:马化腾 马化腾,1971年10月29日生于原广东省海南岛东方市八所港(今海南省东方市),祖籍广东省汕头市.腾讯公司主要创办人之一.现任腾讯公司董事会主席兼首席执行官 ...

  9. MVC4.0 里的分析器错误

    这种错误有很多,今天碰到了,代码段写在if里就回出错,应该是认冲了吧 @if (Web.Common.UserInfo.CurrentUserInfo != null)                ...

  10. ES6学习之字符串的扩展

    字符的Unicode表示法 \uxxxx可以表示一个双字节的字符(xxxx表示字符编码,范围在0000---FFFF),超出此范围用两个双字节表示. console.log("\u0061& ...