📝个人主页:哈__
期待您的关注
目录
一、AOP简介
二、AOP个人浅谈
三、AOP中几个核心的方法注解
四、AOP中几个核心的属性
1.切入点(PointCut)
五、代码演示
1.SpringBoot引入依赖
2.定义一个AOP,也就是切面类
3.使用自定义注解进行增强
六、AOP实现的原理
一、AOP简介
AOP的全称是Aspect-Oriented Programming,即面向切面编程(也称面向方面编程)。它是面向对象编程(OOP)的一种补充,目前已成为一种比较成熟的编程方式。
在传统的业务处理代码中,通常都会进行事务处理、日志记录等操作。虽然使用OOP可以通过组合或者继承的方式来达到代码的重用,但如果要实现某个功能(如日志记录),同样的代码仍然会分散到各个方法中。这样,如果想要关闭某个功能,或者对其进行修改,就必须要修改所有的相关方法。这不但增加了开发人员的工作量,而且提高了代码的出错率。
为了解决这一问题,AOP思想随之产生。AOP采取横向抽取机制,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。这种采用横向抽取机制的方式,采用传统的OOP思想显然是无法办到的,因为OOP只能实现父子关系的纵向的重用。虽然AOP是一种新的编程思想,但却不是OOP的替代品,它只是OOP的延伸和补充。
可以看看类和切面的关系,图片来自黑马程序员。
行了,到了这一步了也不就在废话了,我在尽量不使用太多专业术语的情况下尽可能给大家讲明白AOP。
二、AOP个人浅谈
在我们传统的OOP(面向对象编程)时,在我们原有的方法上我们希望做一些修改,我们希望啊,在执行这个方法之前通知我们的老板,告诉他我已经开始执行任务啦,不要再催促我了。在方法执行结束后,我还要把执行结果告诉老板。那么你会怎么做,是如下边的代码一样吗?
这样子做的确没问题,但是你有没有想过,如果我们的老板比较认真,每一项任务都要向老板汇报,那么你这样写代码还方便吗?如果你只有几项任务的话还好说,就是累一些,但如果你有五十项,一百项呢?
这时AOP就凸显出它的优点了。如果看了简介不明白什么是AOP,那么现在来看看我的理解。
你有很多的任务,你无法把每一项任务都向老板汇报。这时有着这样的一个组织,这个组织可以帮你和老板进行沟通,如果你想对你任务进行这样的能力增强,你就要告诉这个组织,你需要他们的帮助。什么意思呢?我用一张图来解释。
你需要AOP给你提供的帮助,你就需要向AOP提供你要进行业务能力增强的方法的路径,AOP找到这个方法就会对方法进行增强,在你调用方法的时候就会进行增强。
这下你总能理解什么是AOP了吧。
三、AOP中几个核心的方法注解
下边的代码我只使用的Around,其他的注解大家可以看看其他文章,或者自己试一下。
四、AOP中几个核心的属性
1.切入点(PointCut)
切入点就是用来描述我们到底要对哪个方法进行增强的,我们需要提供一串切入点需要的表达式。
切入点表达式的规则如下。
execution(modifier? ret-type declaring-type?name-pattern(param-pattern) throws-pattern?)
modifier:匹配修饰符,public, private 等,省略时匹配任意修饰符ret-type:匹配返回类型,使用 * 匹配任意类型declaring-type:匹配目标类,省略时匹配任意类型 .. 匹配任意的包及其子包name-pattern:匹配方法名称,使用 * 表示通配符 * 表示所有的方法set* 匹配名称以 set 开头的方法param-pattern:匹配参数类型和数量 () 匹配没有参数的方法(..) 匹配有任意数量参数的方法(*) 匹配有一个任意类型参数的方法(*,int) 匹配有两个参数的方法,并且第一个为任意类型,第二个为 int 类型throws-pattern:匹配抛出异常类型,省略时匹配任意类型 下边的PointCut注解就传入了一个切入点表达式。
@Pointcut(value = "execution(* com.example.shardingsphere.controller.*.*(..))")
五、代码演示
1.SpringBoot引入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
2.定义一个AOP,也就是切面类
@Component@Aspectpublic class GlobalAspect { @Pointcut(value = "execution(* com.example.shardingsphere.controller.*.*(..))") public void pointCut(){} @Around(value = "pointCut()") public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { Object proceed = null; System.out.println("通知老板开始统计了"); proceed = proceedingJoinPoint.proceed(); System.out.println("告诉老板统计结果"); return proceed; }}
ProceedingJointPoint类还有许多的方法可以使用,比如获取原来方法的参数等功能。以下内容来自转载。
public interface JoinPoint { String toString(); //连接点所在位置的相关信息 String toShortString(); //连接点所在位置的简短相关信息 String toLongString(); //连接点所在位置的全部相关信息 Object getThis(); //返回AOP代理对象,也就是com.sun.proxy.$Proxy18 Object getTarget(); //返回目标对象,一般我们都需要它或者(也就是定义方法的接口或类,为什么会是接口呢? //这主要是在目标对象本身是动态代理的情况下,例如Mapper。所以返回的是定义方法的对象如 //aoptest.daoimpl.GoodDaoImpl或com.b.base.BaseMapper<T, E, PK>) Object[] getArgs(); //返回被通知方法参数列表 Signature getSignature(); //返回当前连接点签名。其getName()方法返回方法的FQN,如void aoptest.dao.GoodDao.delete() //或com.b.base.BaseMapper.insert(T)(需要注意的是,很多时候我们定义了子类继承父类的时候, //我们希望拿到基于子类的FQN,无法直接拿到,要依赖于 //AopUtils.getTargetClass(point.getTarget())获取原始代理对象,下面会详细讲解) SourceLocation getSourceLocation();//返回连接点方法所在类文件中的位置 String getKind(); //连接点类型 StaticPart getStaticPart(); //返回连接点静态部分 } ———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议, 原文链接:https://blog.csdn.net/feiying0canglang/article/details/120711774
同时在启动程序上加上注解。
@EnableAspectJAutoProxy
进行测试,我写了这样的一个方法。
@GetMapping("/test2") public String test(){ System.out.println("开始统计公司工资情况"); return "执行完毕"; }
结果如下图所示。
你能够看到,AOP已经成功的增强了我们原来的业务逻辑,这说明我们之后再也不用在我们的业务逻辑中进行这样的统计了,我们可以直接在切面类中进行功能的增强,并且切面类的代码可以复用,提高我们的开发效率。
3.使用自定义注解进行增强
每次想要增强一个方法我们就得写一个表达式,如果是有通配符的话还好说,但如果我们使用了通配符,那就说明可能对所有的方法进行增强,但有一些方法我不想进行增强,这可怎么办?没关系,我们可以使用自定义的注解来实现。
我们的表达式不在指向方法了,我们指向注解,哪个方法加了这个注解,哪个方法就需要增强。
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface MyAspect {}
修改表达式。也就是我们在哪里定义的这个注解。
@Pointcut(value = "@annotation(com.example.shardingsphere.aop.MyAspect))")
之后在我们的controller中的test方法上加上@MyAspect注解。进行测试。结果是一样的。
六、AOP实现的原理
这里就简单的说一下,AOP是通过Jdk动态代理或者Cglib动态代理实现的,我们调用我们需要增强的方法,实际上是调用了代理类的方法,由代理类真正的执行我们的业务逻辑。想了解jdk动态代理可以看看我的这篇博客【Java】jdk1.8 Java代理模式,Jdk动态代理讲解(非常详细,附带class文件)-CSDN博客