spring AOP自定义注解 实现日志管理
今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理。废话不多说,直接开始!!!
关于配置我还是的再说一遍。
在applicationContext-mvc.xml中要添加的
<mvc:annotation-driven />
     <!-- 激活组件扫描功能,在包com.gcx及其子包下面自动扫描通过注解配置的组件 -->
     <context:component-scan base-package="com.gcx" />
<!-- 启动对@AspectJ注解的支持 --> 
     <!-- proxy-target-class等于true是强制使用cglib代理,proxy-target-class默认是false,如果你的类实现了接口 就走JDK代理,如果没有,走cglib代理  -->
     <!-- 注:对于单利模式建议使用cglib代理,虽然JDK动态代理比cglib代理速度快,但性能不如cglib -->
<!--如果不写proxy-target-class="true"这句话也没问题-->
     <aop:aspectj-autoproxy proxy-target-class="true"/>
<!--切面-->
     <bean id="systemLogAspect" class="com.gcx.annotation.SystemLogAspect"></bean>
接下来开始编写代码。
创建日志类实体

  1 public class SystemLog {
  2     private String id;
  3
  4     private String description;
  5
  6     private String method;
  7
  8     private Long logType;
  9
 10     private String requestIp;
 11
 12     private String exceptioncode;
 13
 14     private String exceptionDetail;
 15
 16     private String params;
 17
 18     private String createBy;
 19
 20     private Date createDate;
 21
 22     public String getId() {
 23         return id;
 24     }
 25
 26     public void setId(String id) {
 27         this.id = id == null ? null : id.trim();
 28     }
 29
 30     public String getDescription() {
 31         return description;
 32     }
 33
 34     public void setDescription(String description) {
 35         this.description = description == null ? null : description.trim();
 36     }
 37
 38     public String getMethod() {
 39         return method;
 40     }
 41
 42     public void setMethod(String method) {
 43         this.method = method == null ? null : method.trim();
 44     }
 45
 46     public Long getLogType() {
 47         return logType;
 48     }
 49
 50     public void setLogType(Long logType) {
 51         this.logType = logType;
 52     }
 53
 54     public String getRequestIp() {
 55         return requestIp;
 56     }
 57
 58     public void setRequestIp(String requestIp) {
 59         this.requestIp = requestIp == null ? null : requestIp.trim();
 60     }
 61
 62     public String getExceptioncode() {
 63         return exceptioncode;
 64     }
 65
 66     public void setExceptioncode(String exceptioncode) {
 67         this.exceptioncode = exceptioncode == null ? null : exceptioncode.trim();
 68     }
 69
 70     public String getExceptionDetail() {
 71         return exceptionDetail;
 72     }
 73
 74     public void setExceptionDetail(String exceptionDetail) {
 75         this.exceptionDetail = exceptionDetail == null ? null : exceptionDetail.trim();
 76     }
 77
 78     public String getParams() {
 79         return params;
 80     }
 81
 82     public void setParams(String params) {
 83         this.params = params == null ? null : params.trim();
 84     }
 85
 86     public String getCreateBy() {
 87         return createBy;
 88     }
 89
 90     public void setCreateBy(String createBy) {
 91         this.createBy = createBy == null ? null : createBy.trim();
 92     }
 93
 94     public Date getCreateDate() {
 95         return createDate;
 96     }
 97
 98     public void setCreateDate(Date createDate) {
 99         this.createDate = createDate;
100     }
101 }

编写dao接口

1 package com.gcx.dao;
2
3 import com.gcx.entity.SystemLog;
4
5 public interface SystemLogMapper {
6 int deleteByPrimaryKey(String id);
7
8 int insert(SystemLog record);
9
10 int insertSelective(SystemLog record);
11
12 SystemLog selectByPrimaryKey(String id);
13
14 int updateByPrimaryKeySelective(SystemLog record);
15
16 int updateByPrimaryKey(SystemLog record);
17 }

编写service层

1 package com.gcx.service;
2
3 import com.gcx.entity.SystemLog;
4
5 public interface SystemLogService {
6
7 int deleteSystemLog(String id);
8
9 int insert(SystemLog record);
10
11 int insertTest(SystemLog record);
12
13 SystemLog selectSystemLog(String id);
14
15 int updateSystemLog(SystemLog record);
16 }

编写service实现类serviceImpl

1 package com.gcx.service.impl;
2
3 import javax.annotation.Resource;
4
5 import org.springframework.stereotype.Service;
6
7 import com.gcx.annotation.Log;
8 import com.gcx.dao.SystemLogMapper;
9 import com.gcx.entity.SystemLog;
10 import com.gcx.service.SystemLogService;
11
12 @Service("systemLogService")
13 public class SystemLogServiceImpl implements SystemLogService {
14
15 @Resource
16 private SystemLogMapper systemLogMapper;
17
18 @Override
19 public int deleteSystemLog(String id) {
20
21 return systemLogMapper.deleteByPrimaryKey(id);
22 }
23
24 @Override
25
26 public int insert(SystemLog record) {
27
28 return systemLogMapper.insertSelective(record);
29 }
30
31 @Override
32 public SystemLog selectSystemLog(String id) {
33
34 return systemLogMapper.selectByPrimaryKey(id);
35 }
36
37 @Override
38 public int updateSystemLog(SystemLog record) {
39
40 return systemLogMapper.updateByPrimaryKeySelective(record);
41 }
42
43 @Override
44 public int insertTest(SystemLog record) {
45
46 return systemLogMapper.insert(record);
47 }
48
49 }

到这里基本程序编写完毕
下面开始自定义注解

1 package com.gcx.annotation;
2
3 import java.lang.annotation.*;
4
5 @Target({ElementType.PARAMETER, ElementType.METHOD})
6 @Retention(RetentionPolicy.RUNTIME)
7 @Documented
8 public @interface Log {
9
10 /** 要执行的操作类型比如:add操作 **/
11 public String operationType() default "";
12
13 /** 要执行的具体操作比如:添加用户 **/
14 public String operationName() default "";
15 }

下面编写切面

1 package com.gcx.annotation;
2
3 import java.lang.reflect.Method;
4 import java.util.Date;
5 import java.util.UUID;
6
7 import javax.annotation.Resource;
8 import javax.servlet.http.HttpServletRequest;
9 import javax.servlet.http.HttpSession;
10
11 import org.aspectj.lang.JoinPoint;
12 import org.aspectj.lang.ProceedingJoinPoint;
13 import org.aspectj.lang.annotation.After;
14 import org.aspectj.lang.annotation.AfterReturning;
15 import org.aspectj.lang.annotation.AfterThrowing;
16 import org.aspectj.lang.annotation.Around;
17 import org.aspectj.lang.annotation.Aspect;
18 import org.aspectj.lang.annotation.Before;
19 import org.aspectj.lang.annotation.Pointcut;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22 import org.springframework.stereotype.Component;
23
24 import com.gcx.entity.SystemLog;
25 import com.gcx.entity.User;
26 import com.gcx.service.SystemLogService;
27 import com.gcx.util.JsonUtil;
28
29 /**
30 * @author 杨建
31 * @E-mail: email
32 * @version 创建时间:2015-10-19 下午4:29:05
33 * @desc 切点类
34 */
35
36 @Aspect
37 @Component
38 public class SystemLogAspect {
39
40 //注入Service用于把日志保存数据库
41 @Resource //这里我用resource注解,一般用的是@Autowired,他们的区别如有时间我会在后面的博客中来写
42 private SystemLogService systemLogService;
43
44 private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect. class);
45
46 //Controller层切点
47 @Pointcut("execution (* com.gcx.controller..*.*(..))")
48 public void controllerAspect() {
49 }
50
51 /**
52 * 前置通知 用于拦截Controller层记录用户的操作
53 *
54 * @param joinPoint 切点
55 */
56 @Before("controllerAspect()")
57 public void doBefore(JoinPoint joinPoint) {
58 System.out.println("==========执行controller前置通知===============");
59 if(logger.isInfoEnabled()){
60 logger.info("before " + joinPoint);
61 }
62 }
63
64 //配置controller环绕通知,使用在方法aspect()上注册的切入点
65 @Around("controllerAspect()")
66 public void around(JoinPoint joinPoint){
67 System.out.println("==========开始执行controller环绕通知===============");
68 long start = System.currentTimeMillis();
69 try {
70 ((ProceedingJoinPoint) joinPoint).proceed();
71 long end = System.currentTimeMillis();
72 if(logger.isInfoEnabled()){
73 logger.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms!");
74 }
75 System.out.println("==========结束执行controller环绕通知===============");
76 } catch (Throwable e) {
77 long end = System.currentTimeMillis();
78 if(logger.isInfoEnabled()){
79 logger.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms with exception : " + e.getMessage());
80 }
81 }
82 }
83
84 /**
85 * 后置通知 用于拦截Controller层记录用户的操作
86 *
87 * @param joinPoint 切点
88 */
89 @After("controllerAspect()")
90 public void after(JoinPoint joinPoint) {
91
92 /* HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
93 HttpSession session = request.getSession(); */
94 //读取session中的用户
95 // User user = (User) session.getAttribute("user");
96 //请求的IP
97 //String ip = request.getRemoteAddr();
98 User user = new User();
99 user.setId(1);
100 user.setName("张三");
101 String ip = "127.0.0.1";
102 try {
103
104 String targetName = joinPoint.getTarget().getClass().getName();
105 String methodName = joinPoint.getSignature().getName();
106 Object[] arguments = joinPoint.getArgs();
107 Class targetClass = Class.forName(targetName);
108 Method[] methods = targetClass.getMethods();
109 String operationType = "";
110 String operationName = "";
111 for (Method method : methods) {
112 if (method.getName().equals(methodName)) {
113 Class[] clazzs = method.getParameterTypes();
114 if (clazzs.length == arguments.length) {
115 operationType = method.getAnnotation(Log.class).operationType();
116 operationName = method.getAnnotation(Log.class).operationName();
117 break;
118 }
119 }
120 }
121 //*========控制台输出=========*//
122 System.out.println("=====controller后置通知开始=====");
123 System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")+"."+operationType);
124 System.out.println("方法描述:" + operationName);
125 System.out.println("请求人:" + user.getName());
126 System.out.println("请求IP:" + ip);
127 //*========数据库日志=========*//
128 SystemLog log = new SystemLog();
129 log.setId(UUID.randomUUID().toString());
130 log.setDescription(operationName);
131 log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")+"."+operationType);
132 log.setLogType((long)0);
133 log.setRequestIp(ip);
134 log.setExceptioncode( null);
135 log.setExceptionDetail( null);
136 log.setParams( null);
137 log.setCreateBy(user.getName());
138 log.setCreateDate(new Date());
139 //保存数据库
140 systemLogService.insert(log);
141 System.out.println("=====controller后置通知结束=====");
142 } catch (Exception e) {
143 //记录本地异常日志
144 logger.error("==后置通知异常==");
145 logger.error("异常信息:{}", e.getMessage());
146 }
147 }
148
149 //配置后置返回通知,使用在方法aspect()上注册的切入点
150 @AfterReturning("controllerAspect()")
151 public void afterReturn(JoinPoint joinPoint){
152 System.out.println("=====执行controller后置返回通知=====");
153 if(logger.isInfoEnabled()){
154 logger.info("afterReturn " + joinPoint);
155 }
156 }
157
158 /**
159 * 异常通知 用于拦截记录异常日志
160 *
161 * @param joinPoint
162 * @param e
163 */
164 @AfterThrowing(pointcut = "controllerAspect()", throwing="e")
165 public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
166 /*HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
167 HttpSession session = request.getSession();
168 //读取session中的用户
169 User user = (User) session.getAttribute(WebConstants.CURRENT_USER);
170 //获取请求ip
171 String ip = request.getRemoteAddr(); */
172 //获取用户请求方法的参数并序列化为JSON格式字符串
173
174 User user = new User();
175 user.setId(1);
176 user.setName("张三");
177 String ip = "127.0.0.1";
178
179 String params = "";
180 if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
181 for ( int i = 0; i < joinPoint.getArgs().length; i++) {
182 params += JsonUtil.getJsonStr(joinPoint.getArgs()[i]) + ";";
183 }
184 }
185 try {
186
187 String targetName = joinPoint.getTarget().getClass().getName();
188 String methodName = joinPoint.getSignature().getName();
189 Object[] arguments = joinPoint.getArgs();
190 Class targetClass = Class.forName(targetName);
191 Method[] methods = targetClass.getMethods();
192 String operationType = "";
193 String operationName = "";
194 for (Method method : methods) {
195 if (method.getName().equals(methodName)) {
196 Class[] clazzs = method.getParameterTypes();
197 if (clazzs.length == arguments.length) {
198 operationType = method.getAnnotation(Log.class).operationType();
199 operationName = method.getAnnotation(Log.class).operationName();
200 break;
201 }
202 }
203 }
204 /*========控制台输出=========*/
205 System.out.println("=====异常通知开始=====");
206 System.out.println("异常代码:" + e.getClass().getName());
207 System.out.println("异常信息:" + e.getMessage());
208 System.out.println("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")+"."+operationType);
209 System.out.println("方法描述:" + operationName);
210 System.out.println("请求人:" + user.getName());
211 System.out.println("请求IP:" + ip);
212 System.out.println("请求参数:" + params);
213 /*==========数据库日志=========*/
214 SystemLog log = new SystemLog();
215 log.setId(UUID.randomUUID().toString());
216 log.setDescription(operationName);
217 log.setExceptioncode(e.getClass().getName());
218 log.setLogType((long)1);
219 log.setExceptionDetail(e.getMessage());
220 log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
221 log.setParams(params);
222 log.setCreateBy(user.getName());
223 log.setCreateDate(new Date());
224 log.setRequestIp(ip);
225 //保存数据库
226 systemLogService.insert(log);
227 System.out.println("=====异常通知结束=====");
228 } catch (Exception ex) {
229 //记录本地异常日志
230 logger.error("==异常通知异常==");
231 logger.error("异常信息:{}", ex.getMessage());
232 }
233 /*==========记录本地异常日志==========*/
234 logger.error("异常方法:{}异常代码:{}异常信息:{}参数:{}", joinPoint.getTarget().getClass().getName() + joinPoint.getSignature().getName(), e.getClass().getName(), e.getMessage(), params);
235
236 }
237
238 }

我这里写的比较全,前置通知,环绕通知,后置通知,异常通知,后置饭后通知,都写上了,在我们实际编写中不写全也没事,我习惯上把记录日志的逻辑写在后置通知里面,我看网上也有些在前置通知里面的,但我感觉写在后置通知里比较好。
下面开始在controller中加入自定义的注解!!

1 package com.gcx.controller;
2
3 import org.springframework.beans.factory.annotation.Autowired;
4 import org.springframework.stereotype.Controller;
5 import org.springframework.web.bind.annotation.RequestMapping;
6
7 import com.gcx.annotation.Log;
8 import com.gcx.service.UserService;
9
10 @Controller
11 @RequestMapping("userController")
12 public class UserController {
13
14 @Autowired
15 private UserService userService;
16
17 @RequestMapping("testAOP")
18 @Log(operationType="add操作:",operationName="添加用户")
19 public void testAOP(String userName,String password){
20 userService.addUser(userName, password);
21 }
22 }

下面编写测试类

1 @Test
2 public void testAOP1(){
3 //启动Spring容器
4 ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"classpath:applicationContext-mvc.xml","classpath:applicationContext-dataSource.xml"});
5 //获取service或controller组件
6 UserController userController = (UserController) ctx.getBean("userController");
7 userController.testAOP("zhangsan", "123456");
8 }
9


数据库数据:

我原本想写两个切点,一个是service层,一个是controller层,service层是用来记录异常信息的日志,而controller层的是用来记录功能的日志,运行结果如下。     
这样做的话不知道在实际的项目中运行效率好不好,在这里请看到博客的大牛给点建议!!
spring AOP自定义注解 实现日志管理的更多相关文章
- 利用Spring AOP自定义注解解决日志和签名校验
		
转载:http://www.cnblogs.com/shipengzhi/articles/2716004.html 一.需解决的问题 部分API有签名参数(signature),Passport首先 ...
 - (转)利用Spring AOP自定义注解解决日志和签名校验
		
一.需解决的问题 部分API有签名参数(signature),Passport首先对签名进行校验,校验通过才会执行实现方法. 第一种实现方式(Origin):在需要签名校验的接口里写校验的代码,例如: ...
 - 通过AOP自定义注解实现日志管理
		
前言: 通过自定义注解和AOP结合的方式,实现日志的记录功能 大致流程:项目运行->用户操作调用业务处理类->通过自定义的注解(我理解为一个切点)->进入到AOP切面类(在这里可以获 ...
 - spring AOP自定义注解方式实现日志管理
		
今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在appli ...
 - Spring aop+自定义注解统一记录用户行为日志
		
写在前面 本文不涉及过多的Spring aop基本概念以及基本用法介绍,以实际场景使用为主. 场景 我们通常有这样一个需求:打印后台接口请求的具体参数,打印接口请求的最终响应结果,以及记录哪个用户在什 ...
 - Spring AOP 自定义注解实现统一日志管理
		
一.AOP的基本概念: AOP,面向切面编程,常用于日志,事务,权限等业务处理.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容(Spring核心之一),是函数式编程 ...
 - 【Spring】每个程序员都使用Spring(四)——Aop+自定义注解做日志拦截
		
一.前言 上一篇博客向大家介绍了Aop的概念,对切面=切点+通知 .连接点.织入.目标对象.代理(jdk动态代理和CGLIB代理)有所了解了.理论很强,实用就在这篇博客介绍. 这篇博客中,小编向大家介 ...
 - 使用Spring Aop自定义注解实现自动记录日志
		
百度加自己琢磨,以下亲测有效,所以写下来记录,也方便自己回顾浏览加深印象之类,有什么问题可以评论一起解决,不完整之处也请大佬指正,一起进步哈哈(1)首先配置文件: <!-- 声明自动为sprin ...
 - Spring AOP 自定义注解获取http接口及WebService接口入参和出参
		
注解方法实现过程中可以采用如下获取方式:—以下为例 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHo ...
 
随机推荐
- 【翻译】std::list::remove - C++ Reference
			
公有成员函数 std::list::remove void remove(const value_type& val); 删除与给定值相等的元素 从容器中删除所有与 val 值相等的元素.li ...
 - Email移动的原理
			
1.从数据库中得到被移动邮件的uid: 2.选择移动邮件所属folder,即SelectFolder; 3.调用copymessage(path,vmime::net::messageset::byU ...
 - Git 基础 —— 安装 配置 别名 对象
			
Git 基础学习系列 Git 基础 -- 安装 配置 别名 对象 Git 基础 -- 常用命令 Git 基础 -- 常见使用场景 Git基础 -- Github 的使用 Git 安装 Git下载地址 ...
 - 阿里云Linux服务器初探
			
阿里云Linux服务器初探 阿里云Linux服务器初探 因为钱包的关系,本人买了一个660元2年的1核1GB的小服务器(centos是Linux的发行版),在当初是用2核4GB(内存)的时候使用的是w ...
 - PYTHON HTML.PARSER库学习小结--转载
			
前段时间,一朋友让我做个小脚本,抓一下某C2C商城上竞争对手的销售/价格数据,好让他可以实时调整自己的营销策略.自己之前也有过写爬虫抓某宝数据的经历,实现的问题不大,于是就答应了.初步想法是利用pyh ...
 - Qt_QString::split测试
			
1. #define GID_PREFIX "dr_" QString str = "dr__awedr4"; QString str1; QStringLis ...
 - angular5 表单元素 checkbox radio 组讲解
			
一.checkedbox 1.ngModel绑定方式 <input [(ngModel)]="item.checked" value="item.checked&q ...
 - 机器学习 Matplotlib库入门
			
2017-07-21 15:22:05 Matplotlib库是一个优秀的python的数据可视化的第三方类库,其中的pyplot支持了类似matlab的图像输出操作.matplotlib.pyplo ...
 - Java 集合-Set接口和三个子类实现
			
2017-10-31 19:20:45 Set 一个不包含重复元素的 collection.无序且唯一. HashSet LinkedHashSet TreeSet HashSet是使用哈希表(has ...
 - Phalcon框架数据库读写分离的实现方法
			
Phalcon框架和Yaf类似,是一款用C实现的拓展级别的框架,不过其功能实现更加丰富,设计思路基于依赖注入.容器等方式,更符合现代框架思想.本文主要针对Phalcon框架数据库层的读写分离进行说明, ...