SpringAOP源码解读——第一节

本文介绍了Spring AOP的基础知识,包括AOP、AspectJ和Spring AOP的区别,重点讲解了Spring AOP的配置方法,如基于接口、XML配置和@AspectJ注解配置。文中详细阐述了配置过程,包括Pointcut、Advice、JoinPoint的使用,并举例展示了如何获取参数和返回值。
摘要由CSDN通过智能技术生成

1.AOP, AspectJ, Spring AOP的区别

1.1 AOP

  • AOP 要实现的是在我们原来写的代码的基础上,进行一定的包装,如在方法执行前、方法返回后、方法抛出异常后等地方进行一定的拦截处理或者叫增强处理。
  • AOP 的实现并不是因为 Java提供了什么神奇的钩子,可以把方法的几个生命周期告诉我们,而是我们要实现一个代理,实际运行的实例其实是生成的代理类的实例。

1.2 Spring AOP

  • 它基于动态代理来实现。默认地,如果使用接口的,用 JDK 提供的动态代理实现,如果没有接口,使用 CGLIB实现。大家一定要明白背后的意思,包括什么时候会不用 JDK 提供的动态代理,而用 CGLIB 实现。
  • Spring 3.2 以后,spring-core 直接就把 CGLIB 和 ASM的源码包括进来了,这也是为什么我们不需要显式引入这两个依赖。
  • Spring 的 IOC 容器和 AOP 都很重要,Spring AOP 需要依赖于 IOC 容器来管理。 如果你是 web
    开发者,有些时候,你可能需要的是一个 Filter 或一个 Interceptor,而不一定是 AOP。 Spring AOP 只能作用于Spring 容器中的 Bean,它是使用纯粹的 Java 代码实现的,只能作用于 bean 的方法。
  • Spring 提供了 AspectJ 的支持,后面我们会单独介绍怎么使用,一般来说我们用纯的 Spring AOP 就够了。
  • 很多人会对比 Spring AOP 和 AspectJ 的性能,Spring AOP是基于代理实现的,在容器启动的时候需要生成代理实例,在方法调用上也会增加栈的深度,使得 Spring AOP 的性能不如 AspectJ那么好。

1.3 AspectJ:

  • AspectJ 出身也是名门,来自于 Eclipse 基金会,link:https://www.eclipse.org/aspectj

属于静态织入,它是通过修改代码来实现的,它的织入时机可以是:

  • Compile-time weaving:编译期织入,如类 A 使用 AspectJ 添加了一个属性,类 B
    引用了它,这个场景就需要编译期的时候就进行织入,否则没法编译类 B。
  • Post-compile weaving:也就是已经生成了 .class 文件,或已经打成 jar
    包了,这种情况我们需要增强处理的话,就要用到编译后织入
  • Load-time weaving:指的是在加载类的时候进行织入,要实现这个时期的织入,有几种常见的方法。1、自定义类加载器来干这个,这个应该是最容易想到的办法,在被织入类加载到JVM 前去对它进行加载,这样就可以在加载的时候定义行为了。2、在 JVM 启动的时候指定 AspectJ 提供的
    agent:-javaagent:xxx/xxx/aspectjweaver.jar。
  • AspectJ 能干很多 Spring AOP 干不了的事情,它是 AOP 编程的完全解决方案。Spring AOP
    致力于解决的是企业级开发中最普遍的 AOP 需求(方法织入),而不是力求成为一个像 AspectJ 一样的 AOP 编程完全解决方案。
  • 因为 AspectJ 在实际代码运行前完成了织入,所以大家会说它生成的类是没有额外运行时开销的。

2.SpringAOP的配置方法

2.1 概念解释:

首先要说明的是,这里介绍的 Spring AOP 是纯的 Spring 代码,和 AspectJ 没什么关系,但是 Spring 延用了 AspectJ 中的概念,包括使用了 AspectJ 提供的 jar 包中的注解但是不依赖于其实现功能。
后面介绍的如 @Aspect、@Pointcut、@Before、@After 等注解都是来自于 AspectJ,但是功能的实现是纯 Spring AOP 自己实现的
下面我们来介绍 Spring AOP 的使用方法,先从最简单的配置方式开始说起,这样读者想看源码也会比较容易。
目前 Spring AOP 一共有三种配置方式,Spring 做到了很好地向下兼容,所以大家可以放心使用。

  • Spring 1.2 基于接口的配置:最早的 Spring AOP 是完全基于几个接口的。
  • Spring 2.0 schema-based 配置:Spring 2.0 以后使用 XML 的方式来配置,使用 命名空间
  • Spring 2.0 @AspectJ 配置:使用注解的方式来配置,这种方式感觉是最方便的,还有,这里虽然叫做
    @AspectJ,但是这个和 AspectJ 其实没啥关系。

2.2 基于接口的配置

1.定义一个接口和实现类:
在这里插入图片描述
2.接下来,我们定义两个 advice(通知),分别用于拦截方法执行前和方法返回后:
在这里插入图片描述
上面的两个 Advice 分别用于方法调用前输出参数和方法调用后输出结果。

3.现在可以开始配置了,我们配置一个名为 spring_1_2.xml 的文件:
在这里插入图片描述
4.接下来,我们跑起来看看:
在这里插入图片描述
查看输出结果:
准备执行方法: createUser, 参数列表:[Tom, Cruise, 55]
方法返回:User{firstName=‘Tom’, lastName=‘Cruise’, age=55, address=‘null’}
准备执行方法: queryUser, 参数列表:[]
方法返回:User{firstName=‘Tom’, lastName=‘Cruise’, age=55, address=‘null’}

缺点分析:
此中方法有个致命的问题,如果我们需要拦截 OrderService 中的方法,那么我们还需要定义一个 OrderService 的代理。如果还要拦截 PostService,得定义一个 PostService 的代理…
而且上面会对类的所有方法进行拦截,我们需要粒度小一点的,对其中的方法进行拦截:
在上面的配置中,配置拦截器的时候,interceptorNames 除了指定为 Advice,是还可以指定为 Interceptor 和 Advisor 的。
这里我们来理解 Advisor 的概念,它也比较简单,它内部需要指定一个 Advice,Advisor 决定该拦截哪些方法,拦截后需要完成的工作还是内部的 Advice 来做
它有好几个实现类,这里我们使用实现类 NameMatchMethodPointcutAdvisor 来演示,从名字上就可以看出来,它需要我们给它提供方法名字,这样符合该配置的方法才会做拦截。
在这里插入图片描述
我们可以看到,userServiceProxy 这个 bean 配置了一个 advisor,advisor 内部有一个 adviceadvisor 负责匹配方法,内部的 advice 负责实现方法包装
注意,这里的 mappedNames 配置是可以指定多个的,用逗号分隔,可以是不同类中的方法。相比直接指定 advice,advisor 实现了更细粒度的控制,因为在这里配置 advice 的话,所有方法都会被拦截。

上面我们对每一个bean都会生成一个代理,我们需要一个自动生成代理的类:
下面介绍 autoproxy 的解决方案。
autoproxy:从名字我们也可以看出来,它是实现自动代理,也就是说当 Spring 发现一个 bean 需要被切面织入的时候,Spring 会自动生成这个 bean 的一个代理来拦截方法的执行,确保定义的切面能被执行。
这里强调自动ÿ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值