面向切面編程,即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...
}
}
這上面提供的大部分是框架性代碼結構,裏面可以自行補充豐富,歡迎拍磚討論...