Sping-AOP中获取目标对象上的方法名,参数列表,方法上的注解

 

 

Spring Boot使用AOP实现日志后台管理模块的日志数据添加

自己定义一个注解:

package com.cy.pj.common.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiredLog {
	String value() default "operation";
}

在需要被记录的业务层方法上添加注解,这里以改变用户的状态为例:

    @RequiredLog("禁用启用")
	@Override
	public int validById(Integer id, Integer valid, String modifiedUser) {
		//1.合法性验证
		if(id == null || id < 0) {
			throw new IllegalArgumentException("参数不合法:id" + id);
		}
		if(valid != 1 && valid != 0) {
			throw new IllegalArgumentException("参数不合法");
		}
		if(StringUtils.isEmpty(modifiedUser)) {
			throw new ServiceException("修改用户名不能为空");
		}
		//2.执行禁用或启用操作
		int rows = 0;
		try {
			rows = sysUserDao.validById(id, valid, modifiedUser);
		} catch (Throwable e) {
			e.printStackTrace();
			throw new ServiceException("底层正在维护中");
		}
		
		//3.判定结果并返回
		if(rows == 0) {
			throw new ServiceException("记录可能已经不存在");
		}
		return rows;
	}

创建日志切面处理类,用于输出业务开始时间,结束时间,以及将用户行为信息录入数据库。

类上面添加@Slf4j(添加lombok依赖),然后使用log.info("...")打印日志。

在定义AOP的类中,要写@Aspect,表示这是个切面

还要加上@Component,让此AOP交给Spring 管理

Spring中通过切入点表达式定义具体切入点,其常用AOP切入点表达式定义及说明:

Sping-AOP中获取目标对象上的方法名,参数列表,方法上的注解_第1张图片

这里用@annotation表达式,@annotaion表达式应用于方法级别,实现细粒度的切入点表达式定义。

@Pointcut("@annotation(com.cy.pj.common.annotation.RequiredLog)")

 在@Around修饰的环绕通知方法中(满足切入点表达式的核心业务方法执行之前和之后执行的一个操作)获取目标方法的属性信息步骤如下(基于CGLIB库的动态代理):

  • 获取类的字节码对象,通过字节码对象获取方法信息:
Class targetCls = jp.getTarget().getClass();
  • 获取方法签名(通过此签名获取目标方法信息)
MethodSignature ms = (MethodSignature)jp.getSignature();
  •   JDK动态代理通过方法标签获取到的方法是service接口 的方法

  public abstract int com.cy.pj.sys.service.SysUserService.validById(java.lang.Integer,java.lang.Integer,java.lang.String)

System.out.println(ms.getMethod());
  •  CGLIB动态代理通过方法标签获取到的方法是service接口实现类的方法

 public int com.cy.pj.sys.service.impl.SysUserServiceImpl.validById(java.lang.Integer,java.lang.Integer,java.lang.String) 


  • 获取目标方法上的注解指定的操作名称CGLIB动态代理

 

RequiredLog requiredLog = ms.getMethod().getAnnotation(RequiredLog.class);
String operation = requiredLog.value();

 如果是基于JDK的动态代理,就不能通过上述方法获取到方法上的注解,因为获取到的是接口上的方法,通过反射机制,获取不到的字节码文件方法上的注解,报空指针异常

Spring boot2.x 中AOP现在默认使用的CGLIB代理,假如需要使用JDK动态代理可以在配置文件(applicatiion.properties)中进行如下配置: 

spring.aop.proxy-target-class=false
  • 获取目标方法上的注解指定的操作名称 JDK动态代理
Method targetMethod=
targetCls.getDeclaredMethod(ms.getName(),ms.getParameterTypes());
RequiredLog requiredLog=targetMethod.getAnnotation(RequiredLog.class);
String operation=requiredLog.value();
System.out.println("targetMethod="+targetMethod);
  • 取目标方法名(目标类型+方法名)
String targetClsName = targetCls.getName();
//String methodName = ms.getMethod().getName(); 也能获取到目标方法的方法名
String targetObjectMethodName = targetClsName + "." + ms.getName();

 

  • 获取请求参数
String params = Arrays.toString(jp.getArgs());

 封装用户行为日志

SysLog sysLog = new SysLog();
sysLog.setIp(ip);
sysLog.setUsername(username);
sysLog.setTime(time);
sysLog.setOperation(operation);
sysLog.setMethod(targetObjectMethodName);
sysLog.setParams(params);

调用业务层对象方法(insertObject)将日志写入到数据层

sysLogService.insertObject(sysLog);

 

 

Entity对象类实现

定义实体对象(POJO)封装从数据库查询、插入的数据实现ORM映射

@Data(添加lombok依赖)注解在类上,会为类的所有属性自动生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法。

@Data
public class SysLog implements Serializable {
	private static final long serialVersionUID = -8799081241453681134L;
	private Integer id;
	//用户名
	private String username;
	//用户操作
	private String operation;
	//请求方法
	private String method;
	//执行时长ms
	private Long time;
	//IP地址
	private String ip;
	//创建时间
	private Date createdTime;
	private String params;
}

Dao实现

package com.cy.pj.sys.dao;

import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import com.cy.pj.sys.entity.SysLog;

@Mapper
public interface SysLogDao {
	
	int insertObject(SysLog entity);
}

Mapper文件实现:

  1. 基于Dao接口创建映射文件
  2. 基于Dao方法在映射文件中创建映射元素建映射元素




	
	
		insert into sys_logs
		(username,operation,method,params,time,ip,createdTime)
		values
		(#{username},#{operation},#{method},#{params},#{time},#{ip},now())
	

 

Serviec接口:SysLogService

package com.cy.pj.sys.service;


import com.cy.pj.sys.entity.SysLog;

public interface SysLogService {
	
	int insertObject(SysLog entity);
}

Service接口实现类:SysLogServiceImpl

package com.cy.pj.sys.service.impl;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.cy.pj.common.exception.ServiceException;
import com.cy.pj.common.vo.PageObject;
import com.cy.pj.sys.dao.SysLogDao;
import com.cy.pj.sys.entity.SysLog;
import com.cy.pj.sys.service.SysLogService;

@Service
public class SysLogServiceImpl implements SysLogService{
	@Autowired
	private SysLogDao sysLogDao;

	@Override
	public int insertObject(SysLog entity) {
		int rows = sysLogDao.insertObject(entity);
		return rows;
	}
}

 





你可能感兴趣的:(Spring-AOP笔记)