【Spring】Spring中AOP的简介和基本使用,SpringBoot使用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
@Aspect
public 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博客

版权声明:本文为博主作者:哈__原创文章,版权归属原作者,如果侵权,请联系我们删除!

原文链接:https://blog.csdn.net/qq_61024956/article/details/138333607

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
xiaoxingxing的头像xiaoxingxing管理团队
上一篇 2024年5月6日
下一篇 2024年5月6日

相关推荐