一、背景
在对一个老项目进行二期的开发时,发现很多实体类并没有这是创建时间、修改时间等属性,所以打算着实解决之。由于 DAO 层是使用的 JPA 来实现的,并且不想对 DAO 层进行大改刀,遂决定利用 AOP 进行封装以下 DAO 层的的所有 save() 方法。
二、实现
实现其实很简单,由于偷懒,不想去自定义注解,所以就写了个 AOP 来监测 DAO 层的所有方法,对其参数进行修改,利用的反射的原理,获得对应的 set 方法,然后用该方法对修改时间和修改人进行重新赋值,简版的实现逻辑很简单,源码如下:
import lombok.extern.log4j.Log4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.Timestamp; /** * @Author: Jet * @Description: 自定义 AOP 增强 DAO 层 save 方法 * (自动赋值修改时间和修改人) * @Date: 2017/12/26 9:31 */ @Component @Aspect @Log4j public class EnhanceSave { // 切点(设置在 DAO 层的) @Pointcut(value = "execution(* com.wailian.repository.*.save(..))") public void EnhanceSavePointCut(){} // 前置增强 @Before(value = "EnhanceSavePointCut()") public void before(JoinPoint joinPoint){ Object[] args = joinPoint.getArgs(); if (args.length == 1) { Object arg = args[0]; Class<?> aClazz = arg.getClass(); Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); StaffProfile loginStaff = principal == null ? new StaffProfile("001") : (StaffProfile) principal; Timestamp updateTime = new Timestamp(System.currentTimeMillis()); //反射获取实体对象中的方法 try { Method setLastUpdateStaff = aClazz.getDeclaredMethod("setLastUpdateStaff", StaffProfile.class); if (null != setLastUpdateStaff) setLastUpdateStaff.invoke(arg, loginStaff); } catch (NoSuchMethodException e) { log.error("repository 增强 save 方法: 类【" + arg.getClass() + "】没有 setLastUpdateStaff 方法"); } catch (IllegalArgumentException e) { log.error("repository 增强 save 方法: 类【" + arg.getClass() + "】使用 setLastUpdateStaff 方法时参数错误"); } catch (IllegalAccessException | InvocationTargetException e) { log.error("repository 增强 save 方法: 类【" + arg.getClass() + "】,使用 setLastUpdateStaff 方法错误"); } try { Method setLastUpdateDate = aClazz.getDeclaredMethod("setLastUpdateDate", Timestamp.class); if (null != setLastUpdateDate) setLastUpdateDate.invoke(arg, updateTime); } catch (NoSuchMethodException e) { log.error("repository 增强 save 方法: 类【" + arg.getClass() + "】没有 setLastUpdateDate 方法"); } catch (IllegalArgumentException e) { log.error("repository 增强 save 方法: 类【" + arg.getClass() + "】使用 setLastUpdateDate 方法时参数错误"); } catch (IllegalAccessException | InvocationTargetException e) { log.error("repository 增强 save 方法: 类【" + arg.getClass() + "】,使用 setLastUpdateDate 方法错误"); } try { Method getCreateStaff = aClazz.getDeclaredMethod("getCreateStaff"); Object createStaff; if (null != getCreateStaff) { createStaff = getCreateStaff.invoke(arg); if (null == createStaff) aClazz.getDeclaredMethod("setCreateStaff", StaffProfile.class).invoke(arg, loginStaff); } } catch (NoSuchMethodException e) { log.error("repository 增强 save 方法: 类【" + arg.getClass() + "】没有 getCreateStaff/setCreateStaff 方法"); } catch (IllegalArgumentException e) { log.error("repository 增强 save 方法: 类【" + arg.getClass() + "】使用 setCreateStaff 方法时参数错误"); } catch (IllegalAccessException | InvocationTargetException e) { log.error("repository 增强 save 方法: 类【" + arg.getClass() + "】,使用 getCreateStaff/setCreateStaff 方法错误"); } try { Method getCreateDate = aClazz.getDeclaredMethod("getCreateDate"); Object createDate; if (null != getCreateDate) { createDate = getCreateDate.invoke(arg); if (null == createDate) aClazz.getDeclaredMethod("setCreateDate", Timestamp.class).invoke(arg, updateTime); } } catch (NoSuchMethodException e) { log.error("repository 增强 save 方法: 类【" + arg.getClass() + "】没有 getCreateDate/setCreateDate 方法"); } catch (IllegalArgumentException e) { log.error("repository 增强 save 方法: 类【" + arg.getClass() + "】使用 setCreateDate 方法时参数错误"); } catch (IllegalAccessException | InvocationTargetException e) { log.error("repository 增强 save 方法: 类【" + arg.getClass() + "】,使用 getCreateDate/setCreateDate 方法错误"); } } } public void after(){ } }
三、弊端
首先是执行效率较原来低了一点点,
文章评论