利用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...
		
	}	
}

这上面提供的大部分是框架性代码结构,里面可以自行补充丰富,欢迎拍砖讨论...

 

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