AspectJ AOP的使用@Before、@PointCut、@Around等

  • AOP概念
  • 使用AspectJ面向切面编程
  • 详细说明
    • @Aspect
    • @Pointcut、execution
    • 各种通知

最近在看一个项目中使用到AOP的功能,现在将自己过去所学的知识梳理一下。

AOP概念

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方
式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个
热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑
的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高
了开发的效率。
具体概念请看这篇文章:https://blog.csdn.net/q982151756/article/details/80513340

使用AspectJ面向切面编程

切面(Aspect) :通知(advice)和切入点(pointcut)共同组成了切面(aspect)。可以从注解方式来理解,代码如下。
@Aspect为类上面的注解——切面
@pointcut(…)——切入点。为此类内一个空方法上面的注解。可以把拦截的地址表达式表示为方法签名,利于使用起来方便。
@before、@after等——通知。为此类下面的方法上面的注解。
三者在一块组成一个切面。

package com.nowcoder.community.aspect;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;/*** @author cjy* @Package com.nowcoder.community.aspect* @date 2021/8/11 16:48*/
/*@Component
@Aspect*/
public class AlphaAspect {//定义一个切点,目标方法@Pointcut("execution(* com.nowcoder.community.service.*.*(..))")public void pointcut(){}//目标方法之前@Before("pointcut()")public void before(){System.out.println("before");}@After("pointcut()")public void after(){System.out.println("after");}//方法返回之后@AfterReturning("pointcut()")public void afterReturning(){System.out.println("afterReturning");}//再抛异常的时候植入代码@AfterThrowing("pointcut()")public void afterThrowing(){System.out.println("AfterThrowing");}//环绕,参数ProceedingJoinPoint连接点,植入的部位@Around("pointcut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable{System.out.println("around before");  //前Object obj = joinPoint.proceed();//调用目标组件的方法System.out.println("around after");  //后return obj;}
}

详细说明

@Aspect

首先,代码的类的最上面使用的是@Aspect注解,作用是把当前类标识为一个切面供容器读取,之后使用@Component将切面注入IOC容器。

@Pointcut、execution

进入类中,是使用@Pointcut(“execution(* com.nowcoder.community.service..(…))”)这样的一个注解修饰一个pointcut()方法。这样是为了指定切入点和一个point方法签名。execution中可以匹配如下内容:

修饰符匹配(modifier-pattern?)
返回值匹配(ret-type-pattern)可以为表示任何返回值,全路径的类名等
类路径匹配(declaring-type-pattern?)
方法名匹配(name-pattern)可以指定方法名 或者 代表所有, set 代表以set开头的所有方法
参数匹配((param-pattern))可以指定具体的参数类型,多个参数间用“,”隔开,各个参数也可以用“
”来表示匹配任意类型的参数,如(String)表示匹配一个String参数的方法;(*,String) 表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型;可以用(…)表示零个或多个任意参数
异常类型匹配(throws-pattern?)
例如:

1)execution(* *(..))
//表示匹配所有方法
2)execution(public * com. savage.service.UserService.*(..))
//表示匹配com.savage.server.UserService中所有的公有方法
3)execution(* com.savage.server..*.*(..))
//表示匹配com.savage.server包及其子包下的所有方法

然后要使用所定义的Pointcut时,可以指定Pointcut签名。例如:

@Before("pointCut")

这种使用方式等同于以下方式,直接定义execution表达式使用:

@Before("execution(* com.savage.aop.MessageSender.*(..))")

Pointcut定义时,还可以使用&&、||、! 这三个运算,例如:

@Pointcut("execution(* com.savage.aop.MessageSender.*(..))")
private void logSender(){}@Pointcut("execution(* com.savage.aop.MessageReceiver.*(..))")
private void logReceiver(){}@Pointcut("logSender() || logReceiver()")
private void logMessage(){}

笔者更推荐这一种,将一些公用的Pointcut放到一个类中,以供整个应用程序使用。类似于常量存储,便于修改和扩展。

package com.savage.aop;import org.aspectj.lang.annotation.*;public class Pointcuts {@Pointcut("execution(* *Message(..))")
public void logMessage(){}@Pointcut("execution(* *Attachment(..))")
public void logAttachment(){}@Pointcut("execution(* *Service.*(..))")
public void auth(){}
}

使用如下:

@Aspect
public class LogBeforeAdvice {@Before("com.sagage.aop.Pointcuts.logMessage()")public void before(JoinPoint joinPoint) {System.out.println("Logging before " + joinPoint.getSignature().getName());}
}

各种通知

最后,就是整个aop的核心代码了,使用了@Before、@Around等注解修饰的方法。
@Before 前置通知(Before advice) :在某连接点(JoinPoint)——核心代码(类或者方法)之前执行的通知,但这个通知不能阻止连接点前的执行。
@After 后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
@AfterReturning 返回后通知(After return advice) :在某连接点正常完成后执行的通知,不包括抛出异常的情况。
@Around 环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。这时aop的最重要的,最常用的注解。用这个注解的方法入参传的是ProceedingJionPoint pjp,可以决定当前线程能否进入核心方法中——通过调用pjp.proceed();
@AfterThrowing 抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。

有如下的一个例子:某一个系统需要一个日志组件,用来记录用户在什么时间访问了哪个资源。正常情况下来讲,需要在每一个controller层接口部分返回一个用户操作的log。这样需要修改的代码很多,如果使用面向切面思想,如果直接在controller层方法后,或者service方法前指定一个切面,就可以对其进行扩展。代码如下:

package com.nowcoder.community.aspect;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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;/*** @author cjy* @Package com.nowcoder.community.aspect* @date 2021/8/11 17:00*/
@Component
@Aspect
public class ServiceLogAspect {//日志组件private static final Logger logger = LoggerFactory.getLogger(ServiceLogAspect.class);//指定切入点,类路径匹配,匹配所有com.nowcoder.community.service中所有的方法@Pointcut("execution(* com.nowcoder.community.service.*.*(..))")//point签名public void pointCut(){}//在方法执行前执行@Before("pointCut()")public void before(JoinPoint joinPoint) {//记录内容//用户【1,2,3(ip)】,在【时间】访问量【com....功能】的方法//转换为子类型ServletRequestAttributes attr = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();if (attr == null){logger.info("使用kafka消费");return;}HttpServletRequest request = attr.getRequest();String ip = request.getRemoteHost();String now = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());//类名和方法名获取String target = joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName();logger.info(String.format("用户[%s],在[%s]访问了[%s]",ip,now,target));}/** 也可以写为controller方法,使用@AfterReturning注解。当这个方法(连接点)正常返回后执行通知,异常的话不执行通知* 或者使用@Around环绕通知,自定义方法完成前后执行。而且还可以决定当前线程是否进入到核心方法中* 主要是ProceedingJoinPoint.proceed()方法可以真正的调用目标方法,必须有返回值返回* pjp.getArgs()可以获取参数,可以对参数进行校验* */
}

完成以后,在每个service方法旁边,都会有一个->m的标识,也就是切入点在此。

这样的切入点范围市比较广的,有时候只对其中的一些功能切入,我们可以配合自定义注解方式使用AOP编程。

AspectJ AOP的使用(@Before、@PointCut、@Around等)相关推荐

  1. Spring之—— AspectJ AOP 完整示例

    转载请注明出处:http://blog.csdn.net/l1028386804/article/details/49744721 这里我们用一个完整的例子演示spring aspectj aop的使 ...

  2. Spring AOP / AspectJ AOP 的区别?

    Spring AOP / AspectJ AOP 的区别? Spring AOP属于运行时增强,而AspectJ是编译时增强. Spring AOP基于代理(Proxying),而AspectJ基于字 ...

  3. Spring AOP中定义切点PointCut详解

    1.AOP是什么? 软件工程有一个基本原则叫做"关注点分离"(Concern Separation),通俗的理解就是不同的问题交给不同的部分去解决,每部分专注于解决自己的问题.这年 ...

  4. 使用注解作为AOP的切入点(@Pointcut)

    错误日志 在使用aop的注解切入时- 引入jar包 <dependency><groupId>org.springframework.boot</groupId>& ...

  5. AOP -- 注解 @Aspect 、@Pointcut

    目录 1.基本概念 1.1.切面类 @Aspect 1.2.切点 @Pointcut 1.3.Advice 1.4.JoinPoint 1.5.运算符用法 1.6.@annotation(annota ...

  6. b aspectJ AOP简单介绍(概念模型)

    文章目录 概述 动态切点模型 pointscuts advice 暴露pointcuts的context Inter-type declaratios aspects 参考资料 概述 下来会以这个方法 ...

  7. 第15章-Spring AOP切点表达式(Pointcut)详解

    文章目录 一.概述 二.切点表达式配置 1. 内置配置 2. 注解配置 3. 公共配置 二.切点表达式类型 **`execution`** **`within`** **`this`** **`tar ...

  8. Spring Aop源码学习--PointCut切入点

    PointCut切入点简单来说就是用来指明Advice(增强)所作用的地方(一般指方法),PointCut简单来说是一个基于表达式的拦截条件. PointCut接口及实现类: PointCut接口提供 ...

  9. Spring AOP and AspectJ AOP 有什么区别

    AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理.静态代理的代表为AspectJ:动态代理则以Spring AOP为代表. (1)AspectJ是静态代理的增强,所谓静态代理,就是 ...

最新文章

  1. 2018/5/1 ----1986年图灵奖PPT
  2. lora终端连接云服务器_腾讯云服务器上安装mysql,并用navicat连接
  3. python获取剪切板内容_如何从python中读取(windows)剪贴板中的文本?
  4. 基础【循环】-----(枚举器)------(转)
  5. 关于Trie的一些算法
  6. PHP开源的项目管理软件
  7. strspn和strcspn妙用
  8. faster rcnn源码阅读笔记2
  9. uniapp微信公众号h5微信授权登录
  10. win10用android手柄游戏手柄,win10系统使用游戏手柄的步骤
  11. 无线网络经常掉线?默认网关不可用?试试这个办法
  12. 数据统计并制作韦恩图
  13. 微信屏蔽网址的解决办法:366API轻松实现被微信屏蔽的网址在微信内正常访问
  14. 华科_图形学笔记_05_初探造型技术_02
  15. kafka-topics.sh工具:查看/删除/修改/创建主题
  16. 欧几里得 扩展欧几里得
  17. ava Springboot养老院信息管理系统源码
  18. 智能血压计方案/设计案列/APP/小程序
  19. Java与报表知识概括
  20. Mastercam 2017四轴五轴编程加工实例视频教程

热门文章

  1. Phab2 Pro体验 Tango技术简介
  2. 蓝图(blueprint)的理解和用法
  3. SDF 还能这样用?Cocos Creator 基于 SDF 实现多种 Shader 特效
  4. 实现自己的日志打印系统
  5. 计算机二级投影运算怎么看,二级计算机中交、并、除、自然连接、投影、选择和笛卡尔积是怎么计算的?...
  6. Metasploit(二)
  7. Error:Module “./antd/es/badge/style“ does not exist in container. while loading “./antd/es/badge/sty
  8. JWT(Golang)
  9. 中学数学教材教法试题
  10. CAD图纸可以转换成哪些格式呢?