SpringAOP/切面编程示例
原创:转载需注明原创地址 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这里用户自行编写, 不同的业务有不同的处理方式.