程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> spring AOP自定義注解方式實現日志管理,springaop

spring AOP自定義注解方式實現日志管理,springaop

編輯:JAVA綜合教程

spring AOP自定義注解方式實現日志管理,springaop


今天繼續實現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 } View Code

     編寫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 } View Code

    編寫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 } View Code

   編寫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 } View Code

到這裡基本程序編寫完畢

下面開始自定義注解

復制代碼
 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層的是用來記錄功能的日志,運行結果如下。    

這樣做的話不知道在實際的項目中運行效率好不好,在這裡請看到博客的大牛給點建議!!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved