面向切面编程,即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...
}
}
这上面提供的大部分是框架性代码结构,里面可以自行补充丰富,欢迎拍砖讨论...