原創:轉載需注明原創地址 https://www.cnblogs.com/fanerwei222/p/11833954.html
Spring AOP/切面編程實例和一些注意事項, 主要是利用注解來實現, 具體的理論這里不多說, 因為實踐出真知, 很多技術和方法按道理來說是應該先學習理論的, 但是過深的理論探究只會陷入學術陷阱里面, 有一些理論概念知識之后就可以進行一些實戰, 隨后在慢慢的理解實戰中使用的技術或者說一些注解的功能是什么樣的, 再次慢慢結合理論知識來加強鞏固自己的理解, 不然我上來直接給你說@Aspect是干嘛用的, @Pointcut是干嘛用的, AOP有幾個關鍵點, 效果也不大好, 這些只說一遍 , 然后看了大概知道有幾層東西之后就可以開始實戰了, 綜合實戰經驗來記住理論知識! 在我看來是一個技術人員最佳的學習途徑.
首先是注解類:
import java.lang.annotation.*; /** * TODO * 操作記錄注解 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface OperateRecord { /** * 所屬控制器名稱 * @return */ String controllerName() default "默認值"; /** * 操作類型(CRUD) * @return */ String operateType() default "默認值"; /** * 所屬模塊 * @return */ String module() default "默認值"; }
重頭戲是下面的注解處理類:
/** * TODO * 操作記錄處理切面類 */ @Aspect @Component public class OperateRecordAspect { @Resource private OperateRecordService recordService; /** * 客戶端ip地址 */ private String clientIp = ""; /** * 操作類型 */ private String operateType = ""; /** * 操作控制器 */ private String operateController = ""; /** * 所屬模塊名稱 */ private String module = ""; /** * 操作記錄切入點, 此處@annotation是注解類 */ @Pointcut("@annotation(com.xxx.OperateRecord)") public void logOperateRecordPointCut() { } /** * 操作記錄切入點的后置通知(@After的值就是上面的切入點) * @param joinPoint 操作記錄連接點 */ @After("logOperateRecordPointCut()") public void afterPointCut(JoinPoint joinPoint){ try { /** * 通過連接點來獲取方法信息, 然后獲取到注解信息 */ MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//joinPoint.getArgs();//獲取調用注解的那個方法的參數值, 例如:@注解名 public void hello(String id){} joinPoint.getArgs()可以獲取到id的值 Method method = signature.getMethod(); OperateRecord record = method.getAnnotation(OperateRecord.class); HttpServletRequest REQUEST = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest(); clientIp = IpUtils.getIp(REQUEST); operateType = record.operateType(); operateController = record.controllerName(); module = record.controllerName(); /** * 設置記錄實體類信息 */ OperateRecord recordEntity = new OperateRecord(); recordEntity.setId(UuidUtils.getUUID()); recordEntity.setClientIp(clientIp); recordEntity.setCreateTime(new Date()); recordEntity.setModule(module); recordEntity.setOperateController(operateController); recordEntity.setOperateType(operateType); recordService.addOperateRecord(recordEntity); } catch (Exception e) { //有異常不用處理, 直接忽略 System.out.println("此信息僅供提示, 不影響程序運行------操作記錄切面添加信息異常處理-------"); } } /** * 異常通知:目標方法發生異常的時候執行以下代碼 * value="execution(* com.xxxx.impl.*.*(..))" 匹配該包下的所有類的所有方法的執行作為切入點 * @param joinPoint * @param e */ @AfterThrowing(value="execution(* com.xxxx.impl.*.*(..))",throwing="e") public void afterThorwingMethod(JoinPoint joinPoint, NullPointerException e){ try { /** * 通過連接點來獲取方法信息, 然后獲取到注解信息 */ MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); OperateRecord annotation = method.getAnnotation(OperateRecord.class); } catch (Exception ex){ //有異常不用管 } } }
以上的實體類和service以及UuidUtils這里用戶自行編寫, 不同的業務有不同的處理方式.
