利用AOP功能和自帶註解和自定義註解完成一些期望的事情

面向切面編程,即AOP功能,可以很簡單完成一些自己期望的事情,在springboot項目中添加AOP功能很簡單,以Java自有的註解和用戶自定義的註解爲例,簡要介紹AOP的應用;

一,業務需要,

1,使用AOP功能以日誌方式打出各個service方面執行的相關信息,如方法名,參數,執行時間等;
2,開發用戶自定義的註解,用之統計用戶操作的一些行爲;

二,實現步驟;

1,引入依賴的 JAR 包

<!--依賴Jar包, 主要是AOP相關,其它Jar省-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
	<!-- <version>自定義用哪個版本<version> -->
</dependency>

2,業務需要的Bean對象,接口,接口實現,枚舉的定義

//用戶Log信息Bean對象: UserLogInfo.java
package com.xx.yy.zz.model;

public class UserLogInfo {
	private String className;
	private String methodName;
	private String paramList;
	private String userName;
	private String userIp;
	private String operateType;
	private Long executeTime;

	//...code...
	//getter/setter...
	
}
//接口類: UserLogInfoService.java
package com.xx.yy.zz.service;

import com.xx.yy.zz.model.UserLogInfo;
//more import...

public interface UserLogInfoService {
	
	public void saveUserLogInfo(UserLogInfo logInfo);
    //...more function...
	
}
//接口實現類: UserLogInfoServiceImpl.java
package com.xx.yy.zz.service.impl;
import com.xx.yy.zz.model.UserLogInfo;
import com.xx.yy.zz.service.UserLogInfoService;
//more import...

public class UserLogInfoServiceImpl implments UserLogInfoService {
	
	@Autowired
	private UserLogInfoDao userLogInfoDao; //DAO需另外定義
	
	public void saveUserLogInfo(UserLogInfo userLogInfo){
		//...code...		
		userLogInfoDao.insert(userLogInfo);
		
	}
	//...more function...
	
}

枚舉類省略,自行補充...

3,用戶自定義的註解開發

//用戶自定義註解對象: UserDefineLog.java
package com.xx.yy.zz.annotation;

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;
//more import...

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UserDefineLog {
	
	String userName() default "";
	String userIp() default "";
	String operateType() default OperateType.query;
	//OperateType爲用戶自定義的枚舉對象
	// ... more code...
	
}

4,功能性切面類定義

//切面類,功能性切面類
package com.xx.yy.zz.aop;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

//import com.alibaba.fastjson.JSON;
//import com.xx.yy.zz...

@Aspect
@Component
public class LogInfoAop {
	
	Logger logger = LoggerFactory.getLogger(LogInfoAop.class);
	
	@Autowired
	private UserLogInfoService userLogInfoService;
	
	//切面應用的包和相關方法
	@Pointcut("execution(* com.xx.yy.zz.service.impl.*.*(..))")
	private void pointCutMethodService(){		
	}
	
	//切面執行的業務邏輯,顯示執行相關的方法,參數,時間等
	@Around("pointCutMethodService()")
	public Object doAroundService(ProceedingJoinPoint joinPoint) throws Throwable{
		long startTime = System.nanoTime();
		Object object=joinPoint.proceed();
		long endTime = System.nanoTime();
		logger.info("調用Service方法:{}, 參數: {}, 耗時: {} 納秒, {}毫秒",
		joinPoint.getSignature().toString(),Array.toString(joinPoint.getArgs()),
		(endTime - startTime),(endTime - startTime)/1000000);
		return object;
		
	}
	
	//利用自定義註解完成一些事情,如用戶行爲的日誌統計
	//日誌切面應用的地方,即所有使用了自定義註解UserDefineLog的方法
	@Pointcut("@annotation(com.xx.yy.zz.annotation.UserDefineLog)")
	public void userLogPointCut(){		
	}
	
	//日誌切面執行的業務邏輯
	@Around("userLogPointCut()")
	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
		long startTime = System.currentTimeMillis();
		Object object = joinPoint.proceed();
		long funRunTime = System.currentTimeMillis() - startTime;
		saveUserLog(joinPoint,funRunTime);
		return object;		
	}
	
	//用戶保存日誌的業務方法
	private void saveUserLog(ProceedingJoinPoint joinPoint, long time){
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		Method method = signature.getMethod();
		
		UserLogInfo userLogInfo = new UserLogInfo();
		//獲取方法上應用的註解對象以及包含的信息
		UserDefineLog userDefineLog = method.getAnnotation(UserDefineLog.class);
		if (null != userDefineLog) {
			try {
				userLogInfo.setClassName(joinPoint.getTarget().getClass().getName());
				userLogInfo.setMethodName(signature.getName());
				userLogInfo.setParamList(Array.toString(joinPoint.getArgs())
				userLogInfo.setUserName(userLogInfo.userName());
				userLogInfo.setUserIp(userLogInfo.userIp());
				userLogInfo.setOperateType(userLogInfo.operateType());
				userLogInfo.setExecuteTime(time);				
				userLogInfoService.saveUserLogInfo(userLogInfo);				
			} catch(Exception e){
				logger.error("保存日誌信息異常,info: {}", e);
			}
		}
	}
	
}

5,自定義註解的應用

//controller層或service層,自定義註解UserLogInfo的應用
package com.xx.yy.zz.controller;

import java.util.List;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import com.xx.yy.zz.annotation.UserDefineLog;
//more import...

@RestController
@RequestMapping("/user")
public class UserController {
	
	//自定義註解UserLogInfo的應用
	@UserLogInfo(userName="張三", userIp="...", operateType=OperateType.query)
	@PostMapping("/query")
	public List<...> queryUser(){
		
		//...code...
		
	}	
}

這上面提供的大部分是框架性代碼結構,裏面可以自行補充豐富,歡迎拍磚討論...

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章